シナプス技術者ブログ

シナプスの技術者公式ブログ。インターネットで、鹿児島の毎日を笑顔にします。

Ansibleでネットワーク機器の設定を取得する

シナプスの技術部ネットワーク課の末吉です。

業務の中でネットワーク機器の設定を独自スクリプトで取得して保存しているのですが、Ansibleでも同様のことができる様でしたので、Cisco/Juniper/YAMAHAの設定をAnsibleで取得してみました。

Ansibleとは

レッドハットが開発するオープンソースの構成管理ツールである。サーバを立ち上げる際、あらかじめ用意した設定ファイルに従って、ソフトウェアのインストールや設定を自動的に実行する事が出来る

引用: Ansible (ソフトウェア) - Wikipedia

早速試してみます。

検証環境

  • サーバ

    • RockyLinux8.7
      • Python3.9
        • paramiko 2.12.0
      • Ansible-core 2.13.3
        • ansible.netcommon 4.1
        • cisco.ios 3.3.0
        • junipernetworks.junos 3.1.0
        • yamaha_network.rtx 1.0.1
  • ネットワーク機器
    各機器にはsshで接続するため、ssh接続できることが前提となります。各機器は以下の設定とします。

機器 ログインユーザーID/PW 管理者PW IPアドレス
Cisco Catalyst2960G login / loginpassword adminpassword 192.168.1.1
Juniper MX204 login / loginpassword ログインユーザーで実施するため無し 192.168.1.2
YAMAHA RTX830 login / loginpassword adminpassword 192.168.1.3

Ansibleセットアップ

AnsibleはEPELリポジトリよりインストールします。

# dnf install epel-release

Python3.9をインストールします。

# dnf install python3.9

Ansibleをインストールします。

# dnf install ansible

Pythonでssh接続に利用するparamikoをインストールします。

# pip3.9 install paramiko

AnsibleでYAMAHA機器に接続するモジュールをインストールします。

# ansible-galaxy collection install yamaha_network.rtx

ssh接続が初めての場合に接続できないため、/etc/ansible/ansible.cfg に以下を追記します。

[defaults]
host_key_checking = False

Ansibleのバージョン確認

インストールしたパッケージとバージョンを確認します。

# rpm -q ansible ansible-core
ansible-6.3.0-1.el8.noarch
ansible-core-2.13.3-1.el8.x86_64

# ansible --version
ansible [core 2.13.3]
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3.9/site-packages/ansible
  ansible collection location = /root/.ansible/collections:/usr/share/ansible/collections
  executable location = /usr/bin/ansible
  python version = 3.9.13 (main, Nov 16 2022, 15:31:39) [GCC 8.5.0 20210514 (Red Hat 8.5.0-15)]
  jinja version = 3.1.2
  libyaml = True

Ansible モジュールバージョン確認

今回利用するモジュールのバージョンを確認します。

# ansible-galaxy collection list

# /root/.ansible/collections/ansible_collections
Collection         Version
------------------ -------
ansible.netcommon  4.1.0
ansible.utils      2.8.0
yamaha_network.rtx 1.0.1


# /usr/lib/python3.9/site-packages/ansible_collections
Collection                    Version
----------------------------- -------
<〜省略〜>
cisco.aci                     2.2.0
cisco.asa                     3.1.0
cisco.dnac                    6.5.3
cisco.intersight              1.0.19
cisco.ios                     3.3.0
cisco.iosxr                   3.3.0
cisco.ise                     2.5.0
cisco.meraki                  2.10.1
cisco.mso                     2.0.0
cisco.nso                     1.0.3
cisco.nxos                    3.1.0
cisco.ucs                     1.8.0
<〜省略〜>
junipernetworks.junos         3.1.0

Ansibleの構成

  • Ansibleは、2つのファイル群にて構成されています。
種類 ファイル内容
インベントリファイル 対象機器を記載するファイル。記述形式としてINI形式、YAML形式がある。今回はYAML形式で記述
Playbookファイル どの様な実行をするのかを記載するファイル。記述形式はYAML形式

各機器の設定を取得

各機器の設定を取得するために作成したインベントリファイルとplaybookファイルは以下のとおりです。

種類 用途 ファイル名
インベントリファイル Cisco用 /etc/ansible/ios_hosts.yml
インベントリファイル Juniper用 /etc/ansible/junos_hosts.yml
インベントリファイル YAMAHA用 /etc/ansible/rtx_hosts.yml
Playbookファイル Cisco用 /etc/ansible/ios_get-config.yml
Playbookファイル Juniper用 /etc/ansible/junos_get-config.yml
Playbookファイル YAMAHA用 /etc/ansible/rtx_get-config.yml

Asibleでパスワード等の機密情報を扱う場合は、漏洩などの事故防止のために、インベントリファイルに平文でパスワードを記載せず、Ansible Vault などを利用するのが一般的かと思いますが、今回は検証の為インベントリファイルに平文のまま記載します。

Cisco用ファイル

  • /etc/ansible/ios_hosts.yml
---
ios:
  hosts:
    CiscoL2SW:
      ansible_host: 192.168.1.1
  vars:
    ansible_connection: network_cli
    ansible_network_os: cisco.ios.ios
    ansible_user: login
    ansible_password: loginpassword
    ansible_become: True
    ansible_become_method: ansible.netcommon.enable
    ansible_become_password: adminpassword
  • /etc/ansible/ios_get-config.yml
---
- name: ios get config
  hosts: ios
  gather_facts: no

  vars:
    show_commands:
      - show run

  tasks:
    # showコマンド実行
    - name: exec show commands
      cisco.ios.ios_command:
        commands: "{{ show_commands }}"
      register: res_show_commands

    # showコマンド結果を表示
    - name: debug show commands
      ansible.builtin.debug:
        msg: "{{ res_show_commands.stdout_lines[ansible_loop.index0] }}"
      loop: "{{ show_commands }}"
      loop_control:
        extended: true

Juniper用

  • /etc/ansible/junos_hosts.yml
---
junos:
   hosts:
     JuniperRouter:
        ansible_host: 192.168.1.2
   vars:
     ansible_connection: network_cli
     ansible_network_os: junipernetworks.junos.junos
     ansible_user: login
     ansible_ssh_pass: loginpassword
  • /etc/ansible/junos_get-config.yml
---
- name: Junos get config
  hosts: junos
  gather_facts: no

  vars:
    show_commands:
    - show configuration

  tasks:
    # showコマンドを実行
    - name: get show configuration
      junos_command:
        commands: "{{ show_commands }}"
      register: reg_show_commands

    # showコマンド結果を表示
    - name: show configration
      ansible.builtin.debug:
        msg: "{{ reg_show_commands.stdout_lines[ansible_loop.index0] }}"
      loop: "{{ show_commands }}"
      loop_control:
        extended: true

YAMAHA用

  • /etc/ansible/rtx_hosts.yml
---
rtx:
  hosts:
    rtx830:
      ansible_host: 192.168.1.3
  vars:
    ansible_connection: network_cli
    ansible_network_os: yamaha_network.rtx.rtx
    ansible_user: login
    ansible_ssh_pass: loginpassword
    ansible_become: true
    ansible_become_password: adminpassword
  • /etc/ansible/rtx_get-config.yml
---
- name: rtx get config
  hosts: rtx

  tasks:
    # showコマンドを実行
    - name: get configuration
      yamaha_network.rtx.rtx_command:
        commands:
        - show config
      register: result

    # showコマンドの結果を表示
    - name: show config 
      debug:
        msg: "{{ result.stdout_lines[0] }}"

実行

  • 実行コマンド
ansible-playbook -i [インベントリーファイル] [playbookファイル]
  • 今回の実行コマンド
ios
ansible-playbook -i /etc/ansible/ios_hosts.yml /etc/ansible/ios_get-config.yml

junos
ansible-playbook -i /etc/ansible/junos_hosts.yml /etc/ansible/junos_get-config.yml

rtx
ansible-playbook -i /etc/ansible/rtx_hosts.yml /etc/ansible/rtx_get-config.yml
  • Ciscoスイッチを設定を取った際の実行例
# ansible-playbook -i /etc/ansible/ios_hosts.yml /etc/ansible/ios_get-config.yml

PLAY [ios get config] ************************************************************************************************

TASK [exec show commands] ********************************************************************************************
[WARNING]: ansible-pylibssh not installed, falling back to paramiko
ok: [CiscoL2SW]

TASK [debug show commands] *******************************************************************************************
ok: [CiscoL2SW] => (item=show run) => {
    "msg": [
        "Load for five secs: 21%/0%; one minute: 7%; five minutes: 6%",
        "Time source is NTP, 22:12:03.652 JST Sat Jan 28 2023",
        "",
        "Building configuration...",
        "",
        "Current configuration : 4975 bytes",
        "!",
<~省略~>
        "end"
    ]
}

PLAY RECAP ***********************************************************************************************************
CiscoL2SW                  : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

設定が取得できました。YAMAHAの場合以下の警告が出るようでしたが、設定の取得は問題ありませんでした。

# ansible-playbook -i /etc/ansible/rtx_hosts.yml /etc/ansible/rtx_get-config.yml
[WARNING]: Collection yamaha_network.rtx does not support Ansible version 2.13.3

各機器の設定を取得し保存する

各機器の設定内容を取得できたので取得した設定をファイルに保存するようにするplaybookを作成します。インベントリファイルは同じものを利用します。

種類 用途 ファイル名
Playbookファイル Cisco用 /etc/ansible/ios_save-config.yml
Playbookファイル Juniper用 /etc/ansible/junos_save-config.yml
Playbookファイル YAMAHA用 /etc/ansible/rtx_save-config.yml

Cisco用

  • /etc/ansible/ios_save-config.yml
---
- name: ios config save
  hosts: ios
  gather_facts: no

  vars:
    show_commands:
      - show run

  tasks:
    # ログ保存用ディレクトリ作成
    - name: create directory
      ansible.builtin.file:
        path: "/etc/ansible/config/ios/{{ inventory_hostname }}"
        state: directory
      register: logdir

    # showコマンド実行
    - name: exec show commands
      cisco.ios.ios_command:
        commands: "{{ show_commands }}"
      register: res_show_commands

    # showコマンド結果ファイル保存
    - name: save to file
      ansible.builtin.copy:
        content: "{{ res_show_commands.stdout[ansible_loop.index0] }}"
        dest: "{{ logdir.path }}/{{ inventory_hostname }}.config"
      loop: "{{ show_commands }}"
      loop_control:
        extended: true

Juniper用

  • /etc/ansible/junos_save-config.yml
---
- name: Junos config save
  hosts: junos
  gather_facts: no

  vars:
    show_commands:
      - show configuration | display set

  tasks:
    # ログ保存用ディレクトリ作成
    - name: create directory
      ansible.builtin.file:
        path: "/etc/ansible/config/junos/{{ inventory_hostname }}"
        state: directory
      register: logdir

    - name: Get show configuration
      junos_command:
        commands: "{{ show_commands }}"
      register: reg_show_configuration

    # showコマンド結果ファイル保存
    - name: save to file
      ansible.builtin.copy:
        content: "{{ reg_show_configuration.stdout[ansible_loop.index0] }}"
        dest: "{{ logdir.path }}/{{ inventory_hostname }}.config"
      loop: "{{ show_commands }}"
      loop_control:
        extended: true

YAMAHA用

  • /etc/ansible/rtx_save-config.yml
---
- name: rtx config save
  hosts: rtx

  vars:
    show_commands:
    - show config

  tasks:
    # ログ保存用ディレクトリ作成
    - name: create directory
      ansible.builtin.file:
        path: "/etc/ansible/config/rtx/{{ inventory_hostname }}"
        state: directory
      register: logdir

    - name: get configuration
      yamaha_network.rtx.rtx_command:
        commands:  "{{ show_commands }}"
      register: reg_show_configuration

    # showコマンド結果ファイル保存
    - name: save to file
      ansible.builtin.copy:
        content: "{{ reg_show_configuration.stdout[ansible_loop.index0] }}"
        dest: "{{ logdir.path }}/{{ inventory_hostname }}.config"
      loop: "{{ show_commands }}"
      loop_control:
        extended: true

実行

  • 実行コマンド
ansible-playbook -i [インベントリーファイル] [playbookファイル]
  • 今回の実行コマンド
ios
ansible-playbook -i /etc/ansible/ios_hosts.yml /etc/ansible/ios_save-config.yml

junos
ansible-playbook -i /etc/ansible/junos_hosts.yml /etc/ansible/junos_save-config.yml

rtx
ansible-playbook -i /etc/ansible/rtx_hosts.yml /etc/ansible/rtx_save-config.yml
  • Ciscoスイッチを設定を取った際の実行例
PLAY [ios config save] **************************************************************************************************************************************

TASK [create directory] *************************************************************************************************************************************
[WARNING]: ansible-pylibssh not installed, falling back to paramiko
changed: [CiscoL2SW]

TASK [exec show commands] ***********************************************************************************************************************************
ok: [CiscoL2SW]

TASK [save to file] *****************************************************************************************************************************************
changed: [CiscoL2SW] => (item=show run)

PLAY RECAP **************************************************************************************************************************************************
CiscoL2SW                  : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
  • ファイルを確認
# cat /etc/ansible/config/ios/CiscoL2SW/CiscoL2SW.config
Load for five secs: 27%/0%; one minute: 8%; five minutes: 6%
Time source is NTP, 22:14:57.800 JST Sat Jan 28 2023

Building configuration...

Current configuration : 4975 bytes
<~省略~>
end

設定をファイルに保存する事が出来ている事を確認できました。

まとめ

  • Ansibleで各機器の設定を取得する方法を確認することが出来た。
  • Ansibleを使う上でYAMLの書き方を学ぶことが出来た。
  • Ansibleは冪等性が保たれるため、各機器への設定追加に関しても学習していきたい。

参考