はじめに
先日、セイコーソリューションズ株式会社が提供するコンソールサーバー「SmartCS」で、Ansibleの他社ベンダー用モジュールが実行可能になったとのニュースリリースがありました。
コンソールサーバーSmartCSがITインフラの運用自動化対応を強化
これにより、例えばCisco IOS機器の初期設定作業を、ios_config
やios_command
を使ってできるようになると思います。
ただ、注意が必要なのは、機器故障等で前回取得したConfigファイルを使って初期設定を行う場合、冒頭にはじかれるコマンドがあることです。Ansibleでは以下3つのコマンドをデフォルトで無視し、設定対象から除外しているようです。
GitHub - ansible/lib/ansible/module_utils/network/common/config.py
機種や設定によっては、これ以外にもはじかれるコマンドがあります。そのため、お試しでios_config
モジュールにignore_commands
オプションを追加し、指定した文字列を含むコマンドを、設定対象外にできるようにしてみました。
既存コードの変更
ローカル環境の以下ファイルを2箇所変更しています。
GitHub - ansible/lib/ansible/modules/network/ios/ios_config.py
- 冒頭のargument_specにignore_commandsを定義
- コメント「[新規追加] ignore unnecessary commands」で、無視するコマンド(ignore_commands)が設定コマンド(commands)の中に含まれる場合、リストから除外
def main():
""" main entry point for module execution
"""
# ~ 省略 ~
argument_spec = dict(
# ~ 省略 ~
ignore_commands=dict(type='list'), # [新規追加]
)
# ~ 省略 ~
if any((module.params['lines'], module.params['src'])):
match = module.params['match']
replace = module.params['replace']
path = module.params['parents']
candidate = get_candidate_config(module)
running = get_running_config(module, contents, flags=flags)
try:
response = connection.get_diff(candidate=candidate, running=running, diff_match=match, diff_ignore_lines=diff_ignore_lines, path=path,
diff_replace=replace)
except ConnectionError as exc:
module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
config_diff = response['config_diff']
banner_diff = response['banner_diff']
if config_diff or banner_diff:
commands = config_diff.split('\n')
if module.params['before']:
commands[:0] = module.params['before']
if module.params['after']:
commands.extend(module.params['after'])
# [新規追加] ignore unnecessary commands -START-
if module.params["ignore_commands"]:
import re
ignore_commands = module.params["ignore_commands"]
commands_tmp = []
for cmd in commands:
for ignore in ignore_commands:
if re.search(ignore, cmd):
break
else:
commands_tmp.append(cmd)
commands = commands_tmp
# -END-
result['commands'] = commands
result['updates'] = commands
result['banners'] = banner_diff
# send the configuration commands to the device and merge
# them with the current running config
if not module.check_mode:
if commands:
edit_config_or_macro(connection, commands)
if banner_diff:
connection.edit_banner(candidate=json.dumps(banner_diff), multiline_delimiter=module.params['multiline_delimiter'])
result['changed'] = True
設定Configファイル
簡単のため、Config一式でなく、冒頭のコマンドとACL設定のみ投入します。
冒頭の3行はデフォルトで無視されるコマンドです。続く2行を設定対象から除外し、最後にACL2行を追加してみます。
Using 845634 out of 33645387 bytes
Building configuration...
Current configuration : 1047 bytes
Load for five secs: 1%/0%; one minute: 0%; five minutes: 0%
Time source is NTP, 10:45:34.567 JST Sat Jan 19 2019
ip access-list extended test
permit ip host 192.168.1.1 host 10.1.1.1
permit ip host 192.168.1.2 host 10.1.1.2
Playbook
1つ目のタスクで、ios_config
のsrc
オプションで上記のConfigファイルを指定し、続くignore_commands
オプションで「Load for five secs:」もしくは「Time source is NTP,」を除外対象にしています。
2つめと3つ目のタスクで、目的のACLが問題なく投入されたかを確認します。
---
- hosts: cisco
gather_facts: no
connection: network_cli
tasks:
- name: change configuration from config file
ios_config:
src: test3_config.txt
ignore_commands:
- "Load for five secs:"
- "Time source is NTP,"
save_when: modified
- name: run show command
ios_command:
commands: show running-config | section ip access-list extended test
register: result
- name: display ACLs
debug:
msg: "{{ result.stdout_lines[0] }}"
実行結果①(ignore_commandsオプション無しの場合)
想定通り、コマンド「Load for five secs:~」ではじかれFailとなっています。
$ ansible-playbook -i inventory playbook1_config.yml
PLAY [cisco] ******************************************************************************************************************************************************************************************************
TASK [change configuration from config file] **********************************************************************************************************************************************************************
An exception occurred during task execution. To see the full traceback, use -vvv. The error was: test3(config)#
fatal: [test3]: ( ~省略~ ) line 186, in __rpc__\nansible.module_utils.connection.ConnectionError: Load for five secs: 1%/0%; one minute: 0%; five minutes: 0%\r\nLoad for five secs: 1%/0%; one minute: 0%; five minutes: 0%\r\n ^\r\n% Invalid input detected at '^' marker.\r\n\r\ntest3(config)#\n", "module_stdout": "", "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error", "rc": 1}
PLAY RECAP ********************************************************************************************************************************************************************************************************
test3 : ok=0 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
実行結果②(ignore_commandsオプション有りの場合)
問題なくACLが設定されました!
$ ansible-playbook -i inventory playbook1_config.yml
PLAY [cisco] ******************************************************************************************************************************************************************************************************
TASK [change configuration from config file] **********************************************************************************************************************************************************************
changed: [test3]
TASK [run show command] *******************************************************************************************************************************************************************************************
ok: [test3]
TASK [display ACLs] ***********************************************************************************************************************************************************************************************
ok: [test3] => {
"msg": [
"ip access-list extended test",
" permit ip host 192.168.1.1 host 10.1.1.1",
" permit ip host 192.168.1.2 host 10.1.1.2"
]
}
PLAY RECAP ********************************************************************************************************************************************************************************************************
test3 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
最後に
設定前にConfigファイルを編集すればいいじゃん!と思った方、その通りです。でも、何でも自動化してみたいお年頃なので、お許しください