これは Ansible Blogger 2018 (sponsored by Red Hat) Advent Calendar 2018 の22日目の記事です。
■ はじめに
Ansible には、 Cisco IOS ネットワーク機器に対して設定変更コマンドを実行できる ios_config モジュールがあります。
ios_config
モジュールには、Playbook 内に実行したいコマンドを直接指定する lines
オプションのほかに、src
オプションがあります。 src
には、別ファイルにコマンドを書いて(以下、コマンドファイル)、そのファイル名を指定します。
コマンドファイルはただコマンドを列挙するだけでなく、階層を考慮して適切にインデントする必要があります。
この記事では、どのようにインデントすればよいのか、なぜインデントが必要なのか、についてご説明します。
■ まとめ
少し長くなるので、はじめにまとめます。
ios_config
モジュールのsrc
で指定するコマンドファイルは階層を示すためにインデントが必要- インデントの形式はネットワーク機器側の
show run
で表示される形式と同じ - インデントがない場合、すべてグローバルコンフィギュレーションモードで実行しようとしてしまう
- インデントがある場合、コンフィグの階層を解釈したうえで正しく実行する
■ そもそも src
オプションとは
はじめにでもご紹介した通り、コマンドファイルを指定するオプションです。
- Playbook
- hosts: iosprg gather_facts: no tasks: - name: config test ios_config: src: config.txt # ファイル名を指定
- config.txt
interface GigabitEthernet3 description TEST ip address 172.16.0.1 255.255.255.0
今回は、このコマンドファイルのインデントが重要というお話です。
■ どのようにインデントすればよいのか
以下の点だけおさえておけば大丈夫です。
ネットワーク機器側の show running-config で表示される形式と同じインデントをする
例えば、具体的には以下のような形式です。見慣れていると形式かと思います。
- インデントあり
interface GigabitEthernet3 description TEST ip address 172.16.0.1 255.255.255.0
コンフィグの階層をインデントで表したような形式です。
interface GigabitEthernet3
が、グローバルコンフィギュレーションモードで実行したいコマンドです。
スペースによってインデントされている description TEST
と ip address 172.16.0.1 255.255.255.0
が、インターフェースコンフィギュレーションモードで実行したいコマンドです。
■ だめな書き方
一方、コンフィグの階層を作らずにインデントなしで以下のように書いてしまうと、Playbook 実行時にエラーが起こるなどの不都合が起きてしまいます。
- インデントなし
interface GigabitEthernet3 description TEST ip address 172.16.0.1 255.255.255.0
手作業でターミナルへコピペする分には、上記のようにインデントなしでも問題ありません。 すべてのコマンドを実行し、1行ごとにネットワーク機器側が必要に応じてモードを切り替えるためです。 (もちろん手作業の場合でも、見さすさの観点でインデントを入れるケースもよくあると思います。)
しかし、Ansible の ios_config
モジュールの src
で指定するコマンドファイルにおいては、コマンドの階層を考慮して適切にインデントする必要があります。
その理由についてご説明します。
■ インデントが必要な理由
ios_config
モジュールは、コマンド実行前に、そのコマンドがネットワーク機器側に設定済みかどうか確認し、設定済みであれば実行しない、という仕組みです。設定済みかどうか確認する際に、コンフィグの階層まで含めて比較、確認します。
階層まで含めて正しく比較するために、コマンドファイルのインデントが利用されます。
具体的な例で見ていきましょう。
インデントがないとコンフィグ階層が解釈されない
インデントがないと、ios_config
モジュールはすべてグローバルコンフィグレーションモードで実行しようとします。その際、ネットワーク機器側のグローバルコンフィギュレーションレベルで設定済みかどうかを確認します。そして、設定済みのコンフィグはスキップされ実行しません。
例えば、もし
interface GigabitEthernet3 no ip address
という状態のネットワーク機器に対して、
interface GigabitEthernet3 description TEST ip address 172.16.0.1 255.255.255.0
というインデントがないコマンドファイルを src
に指定して実行すると、 interface GigabitEthernet3
がスキップされて実行されません。
続いて、グローバルコンフィギュレーションモードのまま description TEST
を実行しようとしてエラーになります。グローバルコンフィギュレーションモードでは desctiption
コマンドが利用できないためです。
ansible-paybook
コマンド実行時エラー抜粋
"module_stderr": "Traceback (...略...)ansible.module_utils.connection.ConnectionError: description TEST\r\n ^\r\n% Invalid input detected at '^' marker.\r\n\r\ncsr1000v(config)#\n",
- ログを元にしたコマンド実行の再現イメージ(エラー)
csr1000v(config)#description TEST ^ % Invalid input detected at '^' marker. ncsr1000v(config)#
なお、これらの動作は、src
の代わりに lines
で以下のように指定した場合と同じです。このタスクでは親階層を示すコマンドである inteface GigabitEthernet3
含めてすべて lines
オプションに指定しているため、正しく動作しません。
- name: config test ios_config: lines: - inteface GigabitEthernet3 # 正しくは parents オプションに指定すべき - description TEST - ip address 172.16.0.1 255.255.255.0
インデントがあるとコンフィグ階層が正しく解釈される
インデントがあれば、ios_config
モジュールはコンフィグの階層を解釈します。解釈したうえで、ネットワーク機器側で設定済みかどうかを確認します。
例えば、もし
interface GigabitEthernet3 no ip address
という状態のネットワーク機器(先ほどと同じ)に対して、
interface GigabitEthernet3 description TEST ip address 172.16.0.1 255.255.255.0
というインデントがあるコマンドファイルを src
に指定して実行すると、description TEST
と ip address 172.16.0.1 255.255.255.0
コマンドが、interface GigabitEthernet3
配下である、という階層に解釈されます。そのため、interface GigabitEthernet3
は、親階層のコマンドとして必ず実行されます。
そして、差分コンフィグ生成の際、ネットワーク機器側の interface GigabitEthernet3
に description TEST
と ip address 172.16.0.1 255.255.255.0
コマンドがないため、(コンフィグ階層を保ったまま)実行する必要があると判断されます。
その結果、以下の 3行がすべて実行されます。
interface GigabitEthernet3 description TEST ip address 172.16.0.1 255.255.255.0
- コマンド実行イメージ(正常)
csr1000v(config)#interface GigabitEthernet3 csr1000v(config-if)#description TEST csr1000v(config-if)#ip address 172.16.0.1 255.255.255.0
なお、これらの動作は、src
の代わりに lines
、parents
で以下のように指定した場合と同じです。このタスクでは親階層を示すコマンドである inteface GigabitEthernet3
が lines
ではなくparents
に指定しているため、正しく動作します。
- name: config test ios_config: parents: - inteface GigabitEthernet3 # 正しい指定 lines: - description TEST - ip address 172.16.0.1 255.255.255.0
■ まとめ(再掲)
ios_config
モジュールのsrc
で指定するコマンドファイルは階層を示すためにインデントが必要- インデントの形式はネットワーク機器側の
show run
で表示される形式と同じ - インデントがない場合、すべてグローバルコンフィギュレーションモードで実行しようとしてしまう
- インデントがある場合、コンフィグの階層を解釈したうえで正しく実行する