うさラボ

お勉強と備忘録

ネットワークリソースモジュールで遊んでみる

ネットワークリソースモジュールを有効活用したい

ansible v2.9で追加されたネットワークリソースモジュールですが、いままでろくに使ったことがありませんでした。 少し時間ができたので、いろいろと試してみました。

ネットワークリソースモジュールとは

さまざまなネットワークデバイスの管理方法を簡素化および標準化

しているらしい
特徴としては下記のstateがあります、それぞれの説明は割愛させていただきます。

  1. merged
  2. replaced
  3. overridden
  4. deleted
  5. gathered
  6. rendered
  7. parsed

詳しいことは公式ドキュメントにお任せ docs.ansible.com

個人的にパッと見た時に特徴的だったのはreplacedでした。 今までのios_configでは設定の置き換えができなかった思いますので「これは、始まったか」と心の中でつぶやきました(嘘)

どう使うか

個人的にNW機器の構成管理をする際にPlaybook(もしくは変数ファイル)をあるべき状態に定義すればよい状態を目指しています ネットワークリソースモジュールを使って状態を目指します。

そもそもあるべき状態を定義すればよいってどんな状態なの?

今回はIOSのStaticRouteのAnsibleで設定していきます。

あるべき状態、つまり設定値は変数ファイル(static_route.yml)として host_vars配下に配置してあります

 -- inventory
    |-- group_vars
    |   `-- ios.yml
    |-- host_vars
    |   `-- ios01
    |       `-- static_route.yml
    `-- ios1.ini

中身は以下にようになっています(インデントが若干おかしいのはいったん見逃してください)。

static_route:
-   address_families:
    -   afi: ipv4
        routes:
        -   dest: 0.0.0.0/0
            next_hops:
            -   forward_router_address: 10.10.20.254
                interface: GigabitEthernet1
    -   afi: ipv4
        routes:
        -   dest: 10.17.253.101/32
            next_hops:
            -   forward_router_address: 192.168.253.45
    -   afi: ipv4
        routes:
        -   dest: 8.8.8.8/32
            next_hops:
            -   forward_router_address: 10.10.20.254

この変数ファイルに定義してあるroute=機器に設定されているrouteとしたいわけです。 追加削除もこの変数ファイルをいじるだけでOKにし、Config投入時は差分の箇所のみ変更をかけてもらいたい。 冪等性も担保したい、もし手動で設定してしまってもなんとかしたい。

さっそく考えてみる

今回はCiscoDevNetで常時開放しているIOSXEを利用します。

すでにStaticRouteが何本も入っている状態です。

まず変数ファイルを用意する必要があるんですが、手で書き起こすのはさすがにやりたくない。。

そこでネットワークリソースモジュールの出番です。

gatheredを使う

gatheredはfactsに似ています、機器の設定を取得し決まった形に変換してくれます。

こんなPlaybookを作成し実行してみました。

---
- hosts: ios01
  gather_facts: False

  tasks:
    - name: gathered
      cisco.ios.ios_static_routes:
        state: gathered
      register: gather_result

    - name: Write the Static Route configuration to a file
      copy:
        content: "{{ {'static_route': gather_result['gathered'] } | to_nice_yaml }}"
        dest: "{{ inventory_dir }}/host_vars/{{ inventory_hostname }}/static_route.yml"
      delegate_to: localhost

staticrouteの設定を取得し、parseし格納されます。 f:id:usage_automate:20210331194030p:plain

これで、実機から設定を変数ファイルに書き起こすことができました。(上に張っていたstatic_route.ymlです) (nice_to_yamlだと-のあとに余計にスペースはいったりちょっと変なんですよねぇ)

変数ファイルに追加や削除してみる

さて、先ほど出力したファイルをいじってみましょう。

設定追加

static_route.ymlに8.8.8.9/32のルートを追加してみます。 8.8.8.8/8を参考にコピペで作ります。

static_route:
-   address_families:
    -   afi: ipv4
        routes:
        -   dest: 0.0.0.0/0
            next_hops:
            -   forward_router_address: 10.10.20.254
                interface: GigabitEthernet1
    -   afi: ipv4
        routes:
        -   dest: 10.17.253.101/32
            next_hops:
            -   forward_router_address: 192.168.253.45
    -   afi: ipv4
        routes:
        -   dest: 8.8.8.8/32
            next_hops:
            -   forward_router_address: 10.10.20.254
    -   afi: ipv4
        routes:
        -   dest: 8.8.8.9/32
            next_hops:
            -   forward_router_address: 10.10.20.254

完成したので、設定だ!!

と、そのまえに

想定通りか確認してみる

投入するルートが想定通りか、どんなconfigを投入するのか?どんな結果になるのか?を確認したくなったので先に確認しましょう。

確認用のPlaybookを作成しました。 こちらはgatheredとrenderedの合わせ技になります。

renderedは設定時のconfigを出力してくれるstateになり、実機にログインしないでも利用可能です(Localで使える)

gatheredで取得した設定からrenderedした結果とstatic_route.ymlからrenderedした結果をdiffしてみます

diffにはfact_diffを利用しました。

---
- hosts: ios01
  gather_facts: False

  tasks:
    - name: gathered
      cisco.ios.ios_static_routes:
        state: gathered
      register: gather_result

    - name: current config rendered
      cisco.ios.ios_static_routes:
        config: "{{ gather_result['gathered']  }}"
        state: rendered
      register: current_config

    - name: asumed config rendered 
      cisco.ios.ios_static_routes:
        config: "{{ static_route }}"
        state: rendered
      register: assumed_config

    - name: fact_diff
      ansible.utils.fact_diff:
        before: "{{ current_config.rendered }}"
        after: "{{ assumed_config.rendered }}"

実行してみましょう

f:id:usage_automate:20210331195037p:plain

追加予定routeのip route 8.8.8.9 255.255.255.255 10.10.20.254が+で見えました。 これは見やすい(よね?)

今度こそ実行

それでは設定変更を実施しましょう

用意したPlaybookがこちら

---
- hosts: ios01
  gather_facts: False

  tasks:
    - name: replaced
      cisco.ios.ios_static_routes:
        config: "{{ static_route }}"
        state: replaced

ポイントはstate: replacedですね

さて実行、どーーーーん! f:id:usage_automate:20210331195918p:plain

設定後の確認をしてみる

設定後の確認をしましょう、今回はconfigが想定通り設定されたか?の観点に絞って確認をします。

こちらは先ほど作成したPlaybookを再度実施することで簡単にできます。 f:id:usage_automate:20210331200049p:plain

変更なし=gatheredで取得した設定からrenderedした結果とstatic_route.ymlからrenderedした結果に差分なし

ということで想定通りに設定ができました。Ansible最高

おまけで削除

さて、DevnetのIOSXEにゴミをいれてしまったので最後は削除といきましょう。

まずは変数ファイルからいらないrouteを削除します

static_route:
-   address_families:
    -   afi: ipv4
        routes:
        -   dest: 0.0.0.0/0
            next_hops:
            -   forward_router_address: 10.10.20.254
                interface: GigabitEthernet1
    -   afi: ipv4
        routes:
        -   dest: 10.17.253.101/32
            next_hops:
            -   forward_router_address: 192.168.253.45

8.8.8.8/32と8.8.8.9/32のルートですね、こいつは私が足したので削除します。

追加時と同じように設定前の確認をします。

f:id:usage_automate:20210331200526p:plain

削除対象は赤色で出てきます(わかりやすい!)

ではreplaceを実行 f:id:usage_automate:20210331200802p:plain

え?なんでOK?

replacedの動きがよくわからない。。

overriddenが適切なのかも、、(自分の検証機じゃないのでoverriddenはスキップさせてください(´;ω;`))

ソースコードを読む気になれずでここでタイムアップ

まとめ

実際に動かすことが重要だと再認識しました。。。。

最後の削除で想定通り動かず不完全燃焼ですが、ネットワークリソースモジュールについて少し理解が深まってよかったです。

gatheredやrenderedなどの機能も便利に使えそうで妄想が膨らみますね。 今回想定と違ったoverridden/replaceの動きについてはリトライして勉強しようと思います。 (そもそもreplaceって文字だけでこんな挙動かなって勝手に想定していました、よくないですね)

変数ファイルをいじくるだけで設定を変更できるならGitとの相性もよりよくなるかも?とか、CIで投入予定のconfigまで出しておいて承認待ちで止めとくとかすればみんなの恐怖減るかな?とかいろいろと考えたら楽しくなりました。