異なるネットワーク機種でansibleを利用する

# 目的
Cisco, Aruba, HPE Comwareなど異なる機種の管理をansibleで行う。
機種により実行するコマンドが異なるために、ネットワーク機器にSSHでログインしてコマンドを入力する場合は機種とコマンドの文法を意識する必要がある。ansibleを利用して機種を意識しなくて設定を行えるようにする。
ServiceNowのchangeが承認されたら実行するようにすることでServiceNowでネットワーク機器の管理及び設定することが可能になる。

# 本記事の内容
本記事は異なる機種にログインしてバージョン情報を取得するansible playbookを作成する。

# 前提
* スイッチで実行する基本的なコマンド
* ansible及びansible-playbookの基本的に知識
* ansible環境。本記事の例ではansible-vaultを利用しています
* 機器名をDNSに登録（任意）されていない場合はIPアドレスを利用する

# ディレクトリ構成
<pre>
~/ansible # ansible playbook用ディレクトリ
  |- network　# ネットワーク機器用ディレクトリ
       |- show_version.yml # "show version"用のplaybook
       |- roles # ansible roles
            |- show_version # "show version"用roleディレクトリ
                 |- tasks # "show version"用実行ansibleコマンド用ディレクトリ
                     |- main.yml　# "show version"コマンド用のansible-playbook用roleスクリプト
                     |- cisco.ios.ios.yml # cisco用スクリプト
                     |- aruba.yml # aruba用スクリプト
                     |- comware.yml # HPE Comware用スクリプト
                 |- vars # "show version"用roleの変数
                     |- main.yml # 変数定義ファイル
~/scripts # bash用スクリプトディレクトリ
  |- network # ネットワーク機器用スクリプトディレクトリ
        |- show_version.sh # "show version"用のbashスクリプト
/etc/ansible # ansible設定ファイルディレクトリ
  |- hosts # ansible用インベントリファイル
  |- group_vars 
       |- all
            |- vault.yml # ansible-vaultの暗号化ユーザ名／パスワードファイル
</pre>

# 使い方
ansible-playbookを直接実行することも可能ですが、ansibleにそんなに詳しくない人でも利用できるようにbashスクリプトを作成しました。文法は次の通りです。
<pre>./show_version.sh -h
Usage: show_version.sh [-n ホスト名] [-h ヘルプ]
</pre>

<pre>./show_version.sh -ncisco-switch-01
</pre>

# hostsファイル
/etc/ansibleディレクトリに次のようなhostsファイルを作成します。"aruba_user", "aruba_password"等はansible-vaultファイルvault.ymlに定義したユーザ名／パスワードです。ServiceNowから動的に機器情報を取得することも可能。
<pre>
[aruba]
aruba-switch-01 ansible_host=192.168.0.1
aruba-switch-02 ansible_host=192.168.0.2

[aruba:vars]
ansible_user =     "{{ aruba_user }}"
ansible_password = "{{ aruba_password }}"
ansible_network_os = aruba
ansible_connection = network_cli

[cisco]
cisco-switch-01 ansible_host=192.168.0.10
cisco-switch-02 ansible_host=192.168.0.11

[cisco:vars]
ansible_user =     "{{ cisco_user }}"
ansible_password = "{{ cisco_password }}"
ansible_become_password = "{{ cisco_become_password }}"
ansible_network_os = cisco.ios.ios
ansible_connection = network_cli

[comware]
comware-switch-01 ansible_host=192.168.0.20
comware-switch-02 ansible_host=192.168.0.21

[comware:vars]
ansible_user =     "{{ comware_user }}"
ansible_password = "{{ comware_password }}"
ansible_network_os = comware
ansible_connection = local

[network:children] # すべてのネットワーク機器
aruba
cisco
comware
</pre>

# playbookファイルshow_version.yml
<pre>---
- name: get network device version info
  hosts: "{{ host | default('network') }}" # 引数が指定されていない場合は"network"（すべての機器）の情報を取得する
  gather_facts: no

  roles:
     - show_version # role"show_version"を実行する
</pre>

# roles/show_version/tasks/main.yml
hostsファイルのvarsで定義されたansible_network_osの値により実行するymlファイルを選択する
<pre>---
- name: execute show version (aruba)
  block:
    - include_tasks: "{{ ansible_network_os }}.yml" # 機種に対応してymlファイルを読込み、実行する
  when:
      - ansible_network_os is defined # 変数ansible_network_osが定義されている場合のみ実行する
</pre>

# roles/show_version/tasks/cisco.ios.ios.yml
Ciscoのplaybookファイル。
<pre>- name: execute command (cisco)
  no_log: true
  ios_command:
    commands:
      - terminal length 0
      - show version
  register: result

- name: debug cisco
  debug:
    msg: "{{ result.stdout_lines[1] }}"
  when:
    - result.stdout_lines[1] is defined
</pre>

# roles/show_version/tasks/aruba.yml
Aruba用のplaybookファイル。
<pre>- name: execute command (aruba)
  no_log: true
  aruba_command:
    commands:
      - no page
      - show version
  register: result

- name: aruba debug
  debug:
    msg: "{{ result.stdout_lines }}"
  when:
    - result.stdout_lines is defined
</pre>

# roles/show_version/tasks/aruba.yml
HPE Comwareのplaybookファイル。HPE Comwareと接続する場合はhpe-cw7-ansible-mainを利用します。
https://github.com/HPENetworking/hpe-cw7-ansible
<pre>- name: execute command (comware)
  no_log: true
  comware_command:
    command:
      - screen-length disable
      - show version
    type: display
    username: "{{ username }}"
    password: "{{ password }}"
    hostname: "{{ inventory_hostname }}"
  register: result

- name: debug comware
  debug:
    msg: "{{ result.response | replace('\\r', '') }}"
  when:
    - result.response is defined
</pre>

# roles/show_version/vars/main.yml
<pre>
username: "{{ ansible_user }}"
password: "{{ ansible_password }}"
</pre>

# ~/scripts/network/show_version.sh
<pre>#!/bin/bash

HOST=""

usage() {
  echo "Usage: show_version.sh [-n ホスト名] [-h ヘルプ]" 1>&2
}

exit_abnormal() {
  usage
  exit 1
}

call_ansible_script() {
  cd ~/ansible/network/
  if [ -z "$HOST"  ]; then
    ansible-playbook show_version.yml --ask-vault-pass
  else
    ansible-playbook show_version.yml --ask-vault-pass -e "host=$HOST"
  fi
}

while getopts ":n:h" OPT; do
  case $OPT in
  n) HOST=${OPTARG}
    call_ansible_script
    exit 0
    ;;
  h) usage
    exit 0
    ;;
  :) echo "-$OPTARGはホスト名が必須です"
    exit_abnormal;;
  esac
done
echo "execute ansible host:$HOST"
call_ansible_script
exit 0
</pre>

# あとがき
本記事はスイッチから基本情報を取得する例を取り上げましたが、実際の運用ではtemplateを利用して一括で異なる機種の設定なども行えます。

以上