LoginSignup
3
4

More than 3 years have passed since last update.

Ansibleのネットワークモジュールに「設定したくないコマンド」を指定するオプションを追加してみた

Last updated at Posted at 2019-11-01

はじめに

先日、セイコーソリューションズ株式会社が提供するコンソールサーバー「SmartCS」で、Ansibleの他社ベンダー用モジュールが実行可能になったとのニュースリリースがありました。
コンソールサーバーSmartCSがITインフラの運用自動化対応を強化

これにより、例えばCisco IOS機器の初期設定作業を、ios_configios_commandを使ってできるようになると思います。
ただ、注意が必要なのは、機器故障等で前回取得したConfigファイルを使って初期設定を行う場合、冒頭にはじかれるコマンドがあることです。Ansibleでは以下3つのコマンドをデフォルトで無視し、設定対象から除外しているようです。
GitHub - ansible/lib/ansible/module_utils/network/common/config.py
無題1101_1.png

機種や設定によっては、これ以外にもはじかれるコマンドがあります。そのため、お試しでios_configモジュールにignore_commandsオプションを追加し、指定した文字列を含むコマンドを、設定対象外にできるようにしてみました。

既存コードの変更

ローカル環境の以下ファイルを2箇所変更しています。
GitHub - ansible/lib/ansible/modules/network/ios/ios_config.py

  1. 冒頭のargument_specにignore_commandsを定義
  2. コメント「[新規追加] ignore unnecessary commands」で、無視するコマンド(ignore_commands)が設定コマンド(commands)の中に含まれる場合、リストから除外
ios_config.py抜粋
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行を追加してみます。

test3_config.txt
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_configsrcオプションで上記のConfigファイルを指定し、続くignore_commandsオプションで「Load for five secs:」もしくは「Time source is NTP,」を除外対象にしています。
2つめと3つ目のタスクで、目的のACLが問題なく投入されたかを確認します。

playbook1_config.yml
---

- 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が設定されました!:relaxed:

$ 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ファイルを編集すればいいじゃん!と思った方、その通りです。でも、何でも自動化してみたいお年頃なので、お許しください:relaxed:

3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4