Ansibleのnapalm-ansibleモジュールでCisco IOSの設定変更をしてみた

# はじめに
Ansibleのサードパーティー製モジュール群napalm-ansibleの内、設定変更系のモジュールnapalm_install_configの動作確認を行った時のメモです。

# napalm-ansibleとは
NAPALM (ナパーム、Network Automation and Programmability Abstraction Layer with Multivendor support) は、ネットワーク機器の設定変更・ステータス情報取得などを自動化してくれるPythonライブラリです。

以下のマルチベンダの機器に対応しています。

 - Arista EOS
 - Cisco IOS
 - Cisco IOS-XR
 - Cisco NX-OS
 - Juniper JunOS
 
Ansible上で使えるモジュールとして提供されているのがnapalm-ansibleで、執筆時点では以下が提供されています。

| モジュール                    |                                  概要 |
|:-----------------------------|:--------------------------------------|
| napalm_get_facts             |インベントリ、設定、ステータス情報を取得 |
| napalm_install_config        |設定変更を行う |
| napalm_validate              |各種ステータスの妥当性をチェックする |
| napalm_parse_yang            |ファイルや実機からConfig/Stateをパースし、YANGに対応した辞書形式で出力 |
| napalm_diff_yang             |2つのYANGオブジェクトを比較 |
| napalm_translate_yang        | YANGオブジェクトを従来のConfigに変換 |
| napalm_ping                  | Pingを実行 |

# セットアップ
手順は、てくなべ (tekunabe)さんのブログを参考にさせて頂きました。
[Ansible の napalm-ansible モジュール群でCisco IOS 機器の様々な情報を取得する](https://tekunabe.hatenablog.jp/entry/2017/05/27/napalm-ansible_fatcs)

###  準備したもの

| ハード/ソフト            |バージョン        |用途                   |
|:---------------------|:-------------------|:----------------------|
| CentOS | 7.5.1804 |Ansible/NAPALMをインストールする機器。|
| Ansible |2.7.0 ||
| NAPALM |2.3.3 ||
| napalm-ansible |0.10.0 | |
| Cisco CSR1000V |15.2(2)E6 |Ansibleで管理する機器。ホスト名はcsr1。 |

### ネットワーク機器側の設定
Configファイルの転送はSCPを使うため、SCPサーバの有効化が必要です。

` csr1(config)#ip scp server enable `


# Ansible実行

例として、napalm_install_configモジュールで、インタフェースのIPアドレス設定、開放を行ってみました。

### 現状Config

```text:csr1_show_run_int_gi2
interface GigabitEthernet2
 no ip address
 shutdown
 negotiation auto
```

### 設定Config

```text:csr1_setup.txt
interface GigabitEthernet2
 ip address 10.10.10.10 255.255.255.0
 no shutdown
```

### Inventoryファイル
csr1のログイン情報を記載。

```text:inventory
[cisco]
192.168.1.100

[cisco:vars]
hostname= "{{ inventory_hostname }}"
ansible_username=csr1
ansible_password=cisco
enable_secret=csr1
```

### Playbook

内容としては、指定ディレクトリ上の設定Configをネットワーク機器へSCP転送し、設定を上書き保存後、差分を示すdiffファイルを生成するというものです。

```yaml:playbook5.yml
---

- hosts: cisco
  gather_facts: no
  connection: local

  tasks:
    - name: Install Config
      napalm_install_config:
        provider: "{{ cli }}"
        config_file: '/home/<ユーザ名>/ansible/csr1_setup.txt'
        commit_changes: True
        replace_config: False
        get_diffs: True
        diff_file: '/home/<ユーザ名>/ansible/diff'

  vars:
    cli:
      hostname: "{{ inventory_hostname }}"
      username: "{{ ansible_username }}"
      password: "{{ ansible_password }}"
      dev_os: "ios"
      #ユーザーの権限レベルが0の場合、以下コマンドでenableパスワードを指定
      optional_args: {'secret': 'csr1'}
```

### 実行結果

```text:
[<ユーザ名>@localhost library]$ ansible-playbook -i inventory playbook5.yml

PLAY [cisco] ******************************************************************************

TASK [Install Config] *********************************************************************
changed: [192.168.1.100]

PLAY RECAP ********************************************************************************
192.168.1.100              : ok=1    changed=1    unreachable=0    failed=0   
```

### 設定後のConfig
想定通り設定反映されていることが確認できました。

```text:csr1_show_run_int_gi2
interface GigabitEthernet2
 ip address 10.10.10.10 255.255.255.0
 negotiation auto
```

### 生成されたdiffファイル

```text:
+interface GigabitEthernet2
+ ip address 10.10.10.10 255.255.255.0
- no shutdown
```

### ネットワーク機器側で生成されたファイル
Bootflash内に、設定Configとロールバック用ファイルが格納されていました。

```text:
csr1#dir
Directory of bootflash:/
---<snip>---
  14  -rw-              135   Nov 7 2018 23:56:37 +09:00  merge_config.txt 
  20  -rw-            29652   Nov 8 2018 00:05:07 +09:00  rollback_config.txt
```

# 番外編：間違ったConfigを投入した場合の動作

### 設定Config
先ほどとは別のIPアドレスを設定してみます。追加でdescriptionの設定も行いますが、スペルが誤っています。

```text:csr1_setup2.txt
interface GigabitEthernet2
 ip address 10.10.10.20 255.255.255.0
 deescription Test
```
### 実行結果
ログを見ると、Configのマージに失敗し、ロールバックを試みていることが分かります。

```text:
[<ユーザ名>@localhost library]$ ansible-playbook -i inventory playbook5.yml

PLAY [cisco] ******************************************************************************

TASK [Install Config] *********************************************************************
fatal: [192.168.1.100]: FAILED! => {"changed": false, "msg": "cannot install config: 
Configuration merge failed; automatic rollback attempted:\n deescription Test\n   
^\n% Invalid input detected at '^' marker.\n\n141 bytes copied in 0.075 secs (1880 bytes/sec)"}
 [WARNING]: Could not create retry file '/home/<ユーザ名>/ansible/napalm-
ansible/napalm_ansible/modules/playbook5.retry'.         
[Errno 13] Permission denied:
u'/home/<ユーザ名>/ansible/napalm-ansible/napalm_ansible/modules/playbook5.retry'


PLAY RECAP ********************************************************************************
192.168.1.100              : ok=0    changed=0    unreachable=0    failed=1   
```

### 設定後のConfig
IPアドレス設定も含めて全てロールバックされていました。

```text:
interface GigabitEthernet2
 ip address 10.10.10.10 255.255.255.0
 negotiation auto
```

# Ansible純正モジュールとの比較
ios_configモジュールと比較すると、SCPサーバを有効化しないといけない点や、ファイルがネットワーク機器内に残る点が正直微妙だと感じました。
Ansible2.7ではマルチベンダ対応の設定変更モジュールcli_configもリリースされましたし、個人的には使うことはないかなと。。
ただ、今回試したモジュール以外で使えそうなものがあるかもしれないので、良さそうなものがあればまたご紹介したいと思います。