AnsibleのJunosモジュールの接続実装について確認してみたメモ

AnsibleのJunosモジュールの接続実装方法について興味があったので簡単に確認したメモです。

# 1. Junosモジュールの接続方式

Ansible2.5からは以下の接続方式が推奨されるようになりました。

* network_cli(ssh)
* netconf(xml over ssh)

[http://docs.ansible.com/ansible/latest/network/user_guide/platform_junos.html](http://docs.ansible.com/ansible/latest/network/user_guide/platform_junos.html)

AnsibleのJunosモジュールではどう言う風に上記方式の接続実装がされているか確認してみました。

# 2. 実装の確認

## 2-1. コネクション処理

以下が、コネクション時の実装部分です。
`get_connection` を実行すると `cliconf(network_cli)` の場合は [Connection](https://github.com/ansible/ansible/blob/devel/lib/ansible/module_utils/connection.py) クラスが返され `netconf` の場合は [NetconfConnection](https://github.com/ansible/ansible/blob/devel/lib/ansible/module_utils/network/common/netconf.py) クラスが返されます。

```python:ansible/module_utils/network/junos/junos.py
(snip)
def get_connection(module):
    if hasattr(module, '_junos_connection'):
        return module._junos_connection

    capabilities = get_capabilities(module)
    network_api = capabilities.get('network_api')
    if network_api == 'cliconf':
        module._junos_connection = Connection(module._socket_path)
    elif network_api == 'netconf':
        module._junos_connection = NetconfConnection(module._socket_path)
    else:
        module.fail_json(msg='Invalid connection type %s' % network_api)

    return module._junos_connection


def get_capabilities(module):
    if hasattr(module, '_junos_capabilities'):
        return module._junos_capabilities

    capabilities = Connection(module._socket_path).get_capabilities()
    module._junos_capabilities = json.loads(capabilities)
    return module._junos_capabilities
(snip)
```

[https://github.com/ansible/ansible/blob/57f6abdb8460f8501eb9668004f4d7722bda5570/lib/ansible/module_utils/network/junos/junos.py#L69](https://github.com/ansible/ansible/blob/57f6abdb8460f8501eb9668004f4d7722bda5570/lib/ansible/module_utils/network/junos/junos.py#L69)

## 2-2. 実行可能メソッドについて

### 2-2-1. cliconf時のメソッド

cliconfの時に実行できるメソッド一覧です。

```bash
[root@localhost dev]# grep 'def ' ansible-devel/lib/ansible/plugins/cliconf/junos.py | sed -e "s/^ *def //g" -e "s/:$//g"
get_text(self, ele, tag)
get_device_info(self)
get_config(self, source='running', format='text')
edit_config(self, command)
get(self, command, prompt=None, answer=None, sendonly=False)
commit(self, *args, **kwargs)
discard_changes(self)
get_capabilities(self)
compare_configuration(self, rollback_id=None)
```

### 2-2-2. netconf時のメソッド

```bash
[root@localhost dev]# grep 'def' ansible-devel/lib/ansible/plugins/netconf/junos.py | sed -e "s/.*def //g" -e "s/^ *(by .*//g" | sed -e "/^ *$/d" -e "s/:$//g"
get_text(self, ele, tag)
get_device_info(self)
execute_rpc(self, name)
load_configuration(self, *args, **kwargs)
get_capabilities(self)
guess_network_os(obj)
get_configuration(self, *args, **kwargs)
compare_configuration(self, *args, **kwargs)
halt(self)
reboot(self)
halt(self)
get(self, *args, **kwargs)
get_config(self, *args, **kwargs)
edit_config(self, *args, **kwargs)
commit(self, *args, **kwargs)
validate(self, *args, **kwargs)
discard_changes(self, *args, **kwargs)
```

# 3. 動作確認

簡単なJunosのAnsibleモジュールを作ってみたいと思います。
作るモジュールはコマンドを実行して結果を取得するものを作ってみます。

## 3-1. モジュール

`show version` を実行するだけのモジュールです。

```python:test_junos_module.py
#!/usr/bin/python
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.junos.junos import junos_argument_spec, get_connection

argument_spec = junos_argument_spec

module = AnsibleModule(argument_spec=argument_spec,
                       supports_check_mode=True)

conn = get_connection(module)

result = dict(changed=False)
result['cmd'] = conn.get(command="show version")
module.exit_json(**result)
```

getメソッドは `network_cli` `netconf` の両方でサポートされています。

## 3-2. Playbook

```yaml:main.yml
---
- name: Junos Connect TEST
  hosts: junos
  gather_facts: no
  tasks:
    - test_junos_module:
      register: r

    - debug: var=r
```

## 3-3. Inventory

ここでは `network_cli` を使ってみます。

```yaml:inventory
[junos]
192.168.0.60

[junos:vars]
ansible_connection=network_cli
ansible_network_os=junos
ansible_user=root
ansible_ssh_pass=secret
```

## 3-4. 実行

```bash
[root@localhost dev]# ls
inventory  main.yml  test_junos_module.py
[root@localhost dev]# ansible-playbook main.yml -i inventory --module-path .

PLAY [Junos Connect TEST] ******************************************************************************************************************************************************

TASK [test_junos_module] *******************************************************************************************************************************************************
ok: [192.168.0.60]

TASK [debug] *******************************************************************************************************************************************************************
ok: [192.168.0.60] => {
    "r": {
        "changed": false,
        "cmd": "Model: vsrx\nJunos: 15.1X49-D130.6\nJUNOS Software Release [15.1X49-D130.6]",
        "failed": false
    }
}

PLAY RECAP *********************************************************************************************************************************************************************
192.168.0.60               : ok=2    changed=0    unreachable=0    failed=0
```

このように接続して処理をすることができます。

# 4. 最後に

今回は接続についての実装イメージが分かったので、後は `lxml` や `ncclient` の知識を身につければ自作のJunos(他ネットワーク関連含む)モジュールが作れそうです :-)