てくなべ (tekunabe)

ansible / network automation / 学習メモ

[Ansible] -i オプションでディレクトリを指定すると複数のインベントリファイルをマージできる

■ はじめに

Ansible の管理対象ホストを定義するインベントリは、ansible-playbook コマンドの -i オプションで指定します。スタティックなインベントリでも、ダイナミックインベントリでも同じです。

  • コマンド例
$ ansible-playbook -i inventory site.yml

この -i オプションでは、ファイルの指定だけでなく、ディレクトリも指定できます。ディレクトリを指定した場合は、そのディレクトリ配下の複数のインベントリファイルをマージして扱うことができます。

この記事では、簡単な例で試してご説明します。

  • 動作確認環境: Ansible 2.7.5


■ おためし

準備

inventories ディレクトリのインベントリファイルは以下のとおりです。

inventories/
|-- hosts1
`-- hosts2

それぞれのインベントリファイルの中身は以下のとおりです。

  • hosts1
[vsrx]
vsrx1 ansible_host=172.16.0.1

[vsrx:vars]
ansible_network_os=junos
ansible_connection=netconf
  • hosts2
[vsrx]
vsrx2 ansible_host=172.16.0.2

上記の 2ファイルをマージするとどの様になるかご想像つきましたでしょうか。

実行

それでは -iディレクトリを指定して、インベントリファイルがマージでできているかを確認します。

ansible-inventory コマンド編

インベントリの情報を確認するための ansible-inventory コマンドを利用して確認します。

まず --graph オプションで、グループの所属状態を確認します。

$ ansible-inventory -i inventories --graph
@all:
  |--@ungrouped:
  |--@vsrx:
  |  |--vsrx1
  |  |--vsrx2

上記の通り、host1host2 に分かれて定義されていた vsrx グループがマージされ、vsx1vsrx2 の 2ホストが所属する状態になりました。

次に --list オプションででインベントリ情報のリストを表示してみます。

$ ansible-inventory -i inventories --list
{
    "_meta": {
        "hostvars": {
            "vsrx1": {
                "ansible_connection": "netconf", 
                "ansible_host": "172.16.0.1", 
                "ansible_network_os": "junos"
            }, 
            "vsrx2": {
                "ansible_connection": "netconf", 
                "ansible_host": "172.16.0.2", 
                "ansible_network_os": "junos"
            }
        }
    }, 
    "all": {
        "children": [
            "ungrouped", 
            "vsrx"
        ]
    }, 
    "ungrouped": {}, 
    "vsrx": {
        "hosts": [
            "vsrx1", 
            "vsrx2"
        ]
    }
}

上記の通り、vsrx グループがマージさました。 また、host1 にのみ定義していた vsrx グループに対する変数 ansible_connection などもうまくマージされた後に適用されています。

ansible-playbook コマンド編

今度は、簡単な playbook を実行して試します。

  • playbook (test.yml)
- hosts: all
  gather_facts: no

  tasks:
    - name: inventory merge test
      debug:
        msg: "I am {{ inventory_hostname }}"                                   

対象は all にしていますので、vsrx1vsrx2 が対象になるはずです。

(認証情報を定義した変数ファイルは省略)

  • playbook 実行
$ ansible-playbook -i inventories test.yml

PLAY [all] *******************************************************************

TASK [inventory merge test] **************************************************
ok: [vsrx1] => {
    "msg": "I am vsrx1"
}
ok: [vsrx2] => {
    "msg": "I am vsrx2"
}

PLAY RECAP *******************************************************************
vsrx1                      : ok=1    changed=0    unreachable=0    failed=0   
vsrx2                      : ok=1    changed=0    unreachable=0    failed=0  

無事にvsrx1vsrx2 が対象になっていることを確認できました。

補足

■ まとめ

ansible-playbook コマンドなどの -i オプションに、ファイルではなく、ディレクトリを指定するとマージして扱えることを確認できました。

このような指定が必要になるケースは多くはないかもしれませんが、何かのときに思い出していただければ幸いです。

フィードバックがないというフィードバック

フィードバックがほしい

ブログや登壇などのアウトプットをする理由のひとつが、フィードバックが得られることです。

  • わかりやすかった
  • 自分も始めてめてみようと思った
  • 内容が薄い
  • もっと別のことを聞きたかった

こられはすべてフィードバックですので、次のアウトプットにつなげるための参考にさせてもらっています。いつもありがとうございます。

フィードバックがない?

上記で挙げたようなフィードバックがないことももちろんあります。この状態は、何も得るものがなかったということなのでしょうか。

私は、フィードバックがないこと自身が暗黙のフィードバックだと考えています。

直敵的なフィードバック(感想など)が得られなかった原因は、例えば以下のようなものだと思います。

  • フィードバックを得る仕組みを用意していなかった
  • フィードバックを掴みにいく行動をしていなかった
  • 良くも悪くもなかった
  • 何も残らない内容だった
  • ターゲットに届いていなかった

などなど。ふりかえる材料には十分なりえます。

ですので、直接的なフィードバックがないこと自身は、私はアウトプットしない理由にはしていません。そもそも自分向けメモのような、フィードバックを想定していない場合もあります。

Ansible Night in Nagoya 2019.02 に参加と登壇してきました

■ はじめに

【祝】初名古屋開催!

2019/02/15 に名古屋で「Ansible Night in Nagoya 2019.02」が開催されました。

Ansible ユーザー会によるこのイベントは、これまで東京、大阪福岡で開催されてきましたが、今回ははじめての名古屋開催となりました。

ansible-users.connpass.com


■ 会場

Misoca さんのセミナールーム

f:id:akira6592:20190217120917p:plain:w400
会場入り口
f:id:akira6592:20190217120949p:plain:w400
準備中

このようなイベントが開催できるのは、開場提供をしてくださる方々のおかげです。ありがとうございます。 今回は、クラウド見積・納品・請求書サービスを提供する株式会社 Misoca さんのセミナールームを提供していただきました。オフィスへの行き方を説明するページがとてもていねいに書かれているのが、方向音痴な私にとっては助かりました。

ライブビューイングも

東京のレッドハットさんのオフィスでは、ライブビューイングも設定されていました。


■ 各発表

● Ansibleではじめるサーバー・ネットワークの自動化

私の発表分です。

www.slideshare.net

内容は基本的なものに

初の名古屋開催の最初の発表ということで、Ansible とはなにかからはじめる内容にしました。

「8a1」APC勉強会や、ssmjp 2018/10で発表させてただいた内容をベースにして、少し最新情報(Ansible 2.8)の加えました。

その場で Playbook を書いてみる

f:id:akira6592:20190217120406j:plain:w400
デモでPlaybook実行中「ちょっと時間がかかってるようですね・・」

途中「apache httpd をインストールして、index.html をデプロイして、httpd サービスを起動する」という処理の Playbook をゼロから書いて実行するデモを行いました。

yum モジュールのところで、少し時間がかかって、ヒヤヒヤしました。途中で、準備していたデモ動画に切り替えて説明を進めました。そうこうしているうちに、裏では Playbook の処理が終わっていたようで、最後の少し余った時間で、動作確認をすることができました。

  • 実際に書いた Playbook (web.yml)
- hosts: web
  become: yes

  tasks:
    - yum:
        name: httpd
        state: latest
    
    - template:
        src: index.html.j2
        dest: /var/www/html/index.html

    - service:
        name: httpd
        state: started
  
  vars:
    v_name: Nagoya

(時間短縮のため、タスクに name をつけていません・・)

  • 準備していたインベントリファイル (inventory.ini)
[web]
172.16.0.10

[web:vars]
ansible_user=vagrant
  • 準備していたコンテンツファイル(index.html.j2)
<html>
<head>
  <title>Test Page</title>
</head>
<body style="background-color:#339cff">
<h1 style="color:#ffffff">Hello, {{ v_name }}!</h1>
</body>
</html>
  • デモで実行したコマンド
$ ansible-playbook -i inventory.ini web.yml

slack で頂いたご質問

Ansible ユーザー会の slack である ansiblejp (参加リンク http://bit.ly/slack-ansiblejp )で、発表中に以下のご質問をいただきました。

ansibleを書くにあたって便利なエディタとかツールってありますか?

最後の時間で口頭でご紹介しましたが。Visual Studio Code に Ansible という拡張があります。デモ環境もこちらを使っていました。

● Ansible AWXを導入してみた

アビームシステムズ株式会社 後藤卓さん・DaichiYamaguchiさん

www.slideshare.net

  • 作ったものは、AWX、Jenkins、GitLab、Redmineなどで、AWS上のサーバ構築自動化システム。
  • いままでは、紙による構築申請だったところを、redmine に置き換えた。
  • Ansible 単品ではなくAWX を採用した理由は GUIWindows Server を扱う人が多かったため CLI より GUI
  • AWX のいいところは、ジョブテンプレート、実行ログの管理。決め手はロールベースのアクセス制御
  • プロキシに引っかかる場合は突破するための対応が必要
  • 運用で苦労しそうなことは、Playbook 自体の管理やメンテナンスのCI、コンテナが死んだ時の対応をどうするか(オートヒーリングか)

● ネットワークエンジニアがAnsibleと出会った話

株式会社リクルートテクノロジーズ 遠藤惇平さん

speakerdeck.com

  • Ansible でネットワーク機器の自動化も行けそうと思て上司に相談したら通った
  • 自動化対象の作業は自動化難易度の低さを優先、成功体験を積むため
  • Ansibleで、ios/ nxos / panos / junos / bigip のパスワード変更作業の検証が成功

● Ansibleと変更管理とシステム運用と

藤原尚由さん

  • Playbook のメンテナンスは辛い
  • 人の入れ替わりや時間の経過で、なんの処理だかかわからなくなってしまう
  • Playbookの変更理由をgitなりsubversionなりに残しておこう。

● 名古屋コミュニティ盛り上げていきましょう!

DaichiYamaguchiさん

www.slideshare.net

  • 名古屋は人口に対して勉強会の回数が少ない
  • コミュニティ参加すると、最新技術動向を知れる、人脈を築ける
  • 登壇、運営、手伝い、参加、飲み会などでコミュニティに関わってみましょう


■ togetter まとめ

togetter.com


■ Ansible 飯(懇親会)

会場近くの、ぴち天というお店で懇親会を行いました。地元の方に、三河尾張の関係やコミュニティのお話などを楽しく伺いました。


■ 感想など

いろいろな方のお話を聞けて楽しかったです。他の方の諸資料は、アップされ次第リンクを貼らせていだたきます。また、ブログましたなどと声をかけていただけることがあって嬉しかったです。インターネットってすごいですね。

名古屋でもコミュニティが盛り上がるとよいですね。ありがとうございました!

[Ansible] INI形式の変数定義では yes や true は 文字列、True は boolean

■ はじめに

いままで INI 形式のインベントリファイル内での変数は ansible_host くらいしか定義してなかったので気が付かったのですが、boolean の値を定義する場合は YAML とは異なる事情があるようです。

ansibleで変数に入れたyes/noの扱いに苦しんだ - Qiita

自分なりにしらべたことや、試したことをまとめます。

ポイントは、 INI 形式では boolean 値になりそうな値の中では、大文字から始まる True / False が boolean になる点です。

INI 形式では True / False のみが boolean

以下の回答によると、大文字から始まる TrueFalse のみを boolean として扱って、それ以外は文字列扱いになるようです。

How Exactly Does Ansible Parse Boolean Variables? - Stack Overflow

また、以下の公式サイトのページによると、INI 形式で定義した変数は pythonast.literal_eval で処理されるようです。 ini – Uses an Ansible INI file as inventory source. — Ansible Documentation


■ おためし

以下の Playbook で動作を確認します。環境は Ansible 2.7.5 です。

- hosts: localhost
  connection: local
  gather_facts: no

  tasks:
    - name: print value
      debug:
        msg: "{{ test_bool }}"

    - name: print type
      debug:
        msg: "{{ test_bool | type_debug }}"

type_debug フィルターで、Python としての型を確認できます。

INI 形式のインベントリファイルの場合

yes は文字列

インベントリファイル (INI)

localhost test_bool=yes

実行結果

文字列になりました。"yes" のようにダブルコーテーションがついています。

TASK [print value] *************************************************************
ok: [localhost] => {
    "msg": "yes"
}

TASK [print type] **************************************************************
ok: [localhost] => {
    "msg": "unicode"
}

true も文字列

インベントリファイル (INI)

localhost test_bool=true

実行結果

文字列になりました。

TASK [print value] *************************************************************
ok: [localhost] => {
    "msg": "true"
}

TASK [print type] **************************************************************
ok: [localhost] => {
    "msg": "unicode"
}

TRUE は文字列

インベントリファイル (INI)

localhost test_bool=TRUE

実行結果

文字列になりました。

TASK [print value] *************************************************************
ok: [localhost] => {
    "msg": "TRUE"
}

TASK [print type] **************************************************************
ok: [localhost] => {
    "msg": "unicode"
}

True は boolean

インベントリファイル (INI)

localhost test_bool=True

実行結果

booleanになりました。

TASK [print value] *************************************************************
ok: [localhost] => {
    "msg": true
}

TASK [print type] **************************************************************
ok: [localhost] => {
    "msg": "bool"
}

以降、比較のために YAML 形式でも試します。

YAML 形式のインベントリファイルの場合

yes は boolean

イベントリファイル (YAML)

all:
  hosts:
    localhost:
      test_bool: yes

実行結果

INI 形式のインベトリファイルで test_bool=yes と指定したときとは異なり、boolean になりました。

TASK [print value] *************************************************************
ok: [localhost] => {
    "msg": true
}

TASK [print type] **************************************************************
ok: [localhost] => {
    "msg": "bool"
}

vars で定義した場合

yes は boolean

イベントリファイル (INI)

ここでは変数は定義しません。

localhost

./host_vars/localhost.yml

ここに変数定義します。

test_bool: yes
実行結果
TASK [print value] *************************************************************
ok: [localhost] => {
    "msg": true
}

TASK [print type] **************************************************************
ok: [localhost] => {
    "msg": "bool"
}


■ まとめ

INI 形式と YAML 形式で boolean として扱う値の違いについて確認しました。

YAML 形式については、公式ドキュメントの YAML Syntax に記載されている通りyes / no / True / False などでも boolean になります。

一方、INI 形式については、boolean になりそうな値の中では、大文字から始まる True / False が boolean になります。

公式ドキュメントの Working with Inventory には、以下の注意書きがありました。

Values passed in the INI format using the key=value syntax are not interpreted as Python literal structure (strings, numbers, tuples, lists, dicts, booleans, None), but as a string. For example var=FALSE would create a string equal to ‘FALSE’. Do not rely on types set during definition, always make sure you specify type with a filter when needed when consuming the variable.

以下に結果をまとめます。

フォーマット 定義 結果 備考
INI test_bool=yes 文字列
INI test_bool=no 文字列
INI test_bool=true 文字列
INI test_bool=false 文字列
INI test_bool=TRUE 文字列
INI test_bool=FALSE 文字列
INI test_bool=True boolean
INI test_bool=False boolean
YAML test_bool: yes boolean YAML Syntax 通り
YAML test_bool: no boolean YAML Syntax 通り
YAML test_bool: true boolean YAML Syntax 通り
YAML test_bool: false boolean YAML Syntax 通り
YAML test_bool: True boolean YAML Syntax 通り
YAML test_bool: False boolean YAML Syntax 通り
YAML test_bool: yes boolean YAML Syntax 通り

[Ansible] デフォルトから変更されている設定項目を確認する方法(ansible-config dump --only-changed)

はじめに

Ansible 2.4 以上には ansible-config という、設定項目を表示するコマンドがあります。

ansible-config dump --only-changed のように、dumpサブコマンドと --only-changed オプションを付けて実行すると、デフォルトから変更されている設定項目のみを表示できます。

Ansible では、[ansible.cfg] ファイルや環境変数など、複数の場所で設定変更ができるため、どこでどのような設定変更をしているか分かりにくくなることがあります。このような場合に ansible-config dump --only-changed が便利です。

実行例をご紹介します。(動作確認環境: Ansible 2.7.7)


事前確認

$ pwd
/home/vagrant
$ echo $ANSIBLE_PERSISTENT_CONNECT_TIMEOUT
45
$ cat ./ansible.cfg
[defaults]
retry_files_enabled = False
host_key_checking = False

ansible-config dump --only-changed 実行結果

f:id:akira6592:20190208170445p:plain

このように、どこのファイル、変数でどのように変更されているかが表示されます。


--only-changed なしの場合はすべて表示

--only-changed オプションなしで、単に ansible-config dump だけでコマンドを実行すると、すべての設定項目が表示されます。 ドキュメントに頼らず「デフォルト値はどうなっているだっけ?」と調べるときに便利です。デフォルトのままの設定項目は緑色、変更箇所は黄色で表示されます。

f:id:akira6592:20190208170725p:plain


参考

ネットワーク設定自動化に利用するインプット形式の分類(範囲、処理形式、表現形式別)

はじめに

ネットワーク機器の設定変更を自動化するあたって考慮するポイントの1つは、設定情報のインプットをどのような形式にするかです。

f:id:akira6592:20190208142707p:plain:w400
設定情報のインプット形式は?

たとえば、機器が解釈できるコマンドを直接インプットする方法もあれば、パラメータシートのように人にも解釈しやすいものをインプットしてコマンドを生成する方法もあります。また、宣言的にインプットする方法もあれば、手続き的にインプットする方法もあります。 この記事では、設定情報のインプットを「範囲」「処理形式」「表現形式」の3つの観点で分類して、それぞれの特徴をまとめます。

なお、ネットワーク機器に CLI でコマンドを投入していく形式を想定しています。




■ 分類方法(3つの観点:範囲/処理形式/表現形式)

設定情報のイインプット形式を3つの観点で分類します。それぞれの観点について説明します。


・範囲(全体/部分)

どの範囲の設定内容か、という観点です。

全体

f:id:akira6592:20190208134122p:plain
全体的

ネットワーク機器の設定全体を指定する形式です。 Cisco IOS のコンフィグであれば、show run で表示されるコンフィグの形式を指します。

version 16.8
service timestamps debug datetime msec
service timestamps log datetime msec
platform qfp utilization monitor load 80
no platform punt-keepalive disable-kernel-core
platform console virtual
!
hostname csr1000v

(...略...)


wsma agent exec
!
wsma agent config
!
wsma agent filesys
!
wsma agent notify
!
!
end

部分的

f:id:akira6592:20190208134147p:plain
部分的

部分的に設定を指定する形式です。

ntp server 10.0.0.1
ntp server 10.0.0.2


・処理式形(宣言的/手続き的)

どのように設定内容を処理させるか、という観点です。

宣言的

f:id:akira6592:20190208134231p:plain
宣言的

「こういう設定状態であってほしい」と宣言型で指定して処理する形式です。指定する側にとっては、今の状態がどうなっているかはあまり意識しません。

たとえば、参照先 NTP サーバーの設定が、10.0.0.110.0.0.210.0.0.3、の3つがある状態から、

- ntp_servers:
    - 10.0.0.1
    - 10.0.0.2

ntp server 10.0.0.1
ntp server 10.0.0.2

のような指定をすると、10.0.0.110.0.0.2、の2つになることを期待します。既存の設定にあった 10.0.0.3 が消えることがポイントです。

手続き的

f:id:akira6592:20190208134244p:plain
手続き的

このコマンドを実行(手続き)してほしい、という指定する形式です。 ネットワーク機器が解釈できるコマンドそのもので、手作業でコピペする時と同じイメージです。 手続きそのものですので、指定する側にとっては、今の状態がどうなっているかを強く意識する必要があります。

たとえば、参照先 NTP サーバーの設定が、10.0.0.110.0.0.210.0.0.3、の3つがある状態から、

ntp server 10.0.0.1
ntp server 10.0.0.2

のような指定をすると、10.0.0.110.0.0.210.0.0.3、の3つのままなることを期待します。no ntp server 10.0.0.3 を指定していないため、10.0.0.3 が残ったままになることがポイントです。

また、依存関係のある設定を正しい順序で追加したり、設定を削除する場合の no コマンドをあらかじめ準備する必要があります。 これら準備は、人が考えたり、パターン化したうで自動で生成する仕組みを作りこみます。


・表現式形(パラメーター/コンフィグ)

どのように設定内容を表現するか、という観点です。

パラメーター

f:id:akira6592:20190208135308p:plain
パラメーター

YAML や JASON、Excel などで設定をパラメーターとして表現する形式です。これらのパラメーターは、コンフィグに変換してからネットワーク機器に投入します。 たとえば、YAML でパラメーターを表現すると以下のようになります。

- ntp_servers:
    - 10.0.0.1
    - 10.0.0.2

コンフィグ

f:id:akira6592:20190208135323p:plain
コンフィグ

ネットワーク機器が解釈できるコンフィグそのものによって、設定を表現する形式です。

ntp server 10.0.0.1
ntp server 10.0.0.2




■ 各パターンの特徴

前述した 3つの観点で分類して、本記事での名称を以下に示します。

No 範囲 処理形式 表現形式 名称 イメージ
1 全体 宣言 パラメーター 全体宣言的パラメーター 機器単位のパラメーターシート
2 全体 宣言 コンフィグ 全体宣言的コンフィグ 想定事後コンフィグ
- 全体 手続き パラメーター 全体手続き的パラメーター なし
- 全体 手続き コンフィグ 全体宣言的コンフィグ なし
3 部分 宣言 パラメーター 部分宣言的パラメーター 作業依頼単位のパラメーター
- 部分 宣言 コンフィグ 部分宣言的コンフィグ なし
- 部分 手続き パラメーター 部分手続き的パラメーター なし
4 部分 手続き コンフィグ 部分手続き的コンフィグ 作業用投入コンフィグ

現時点で具体的なイメージが湧いたものに番号を付けました。

1~4 のインプット形式について、ぞれぞれ以下の点について説明します。

  • インプット前に必要な準備(もちろんこれ自体もサブシステムしても可)
  • 自動化システム内で処理すること
  • コンフィグが正しく入ったか確認する方法
    • ここでは状態(show ip route 結果など)ではなく、コンフィグそのものの確認
    • この確認が必要かどうかはここでは取り上げません


・[1] 全体宣言的パラメーター

f:id:akira6592:20190208134816p:plain
全体宣言的パラメーター

機器全体の設定を定義した、パラメーターシートのようなイメージです。

  • YAMLで指定する例
system:
    hostname: rt101
    ntp_servers:
        - 10.0.0.1
        - 10.0.0.2
interfaces:
    - name: GigabitEthernet0/0/1
      description: to rt102
      ipv4_address: 10.0.101.254/24
    - name: GigabitEthernet0/0/2
      description: to rt202
      ipv4_address: 10.0.102.254/24
# (...略...)

インプット前に必要な準備

  • 機器の全設定に対応する、統一されたフォーマットのパラメーター
  • YAMLJSON のようなテキストベースのフォーマットで、マシンリーダブルなものが望ましい

自動化システム内で処理すること

  • パラメーターから投入コマンドの生成
  • no コマンドや、設定間の依存性に要注意
  • 生成したコンフィグを投入

コンフィグが正しく入ったか確認する方法

  • インプットから生成したコンフィグと事後のコンフィグが一致していること


・[2] 全体宣言的コンフィグ

f:id:akira6592:20190208134855p:plain
全体宣言的コンフィグ

「全体としてこのコンフィグの状態にしてほしい」と指定します。git でコンフィグ全体を管理していて「こうなってほしい」というコンフィグに変更してコミットするのもこのパターンです。

version 16.8
service timestamps debug datetime msec
service timestamps log datetime msec
platform qfp utilization monitor load 80
no platform punt-keepalive disable-kernel-core
platform console virtual
!
hostname csr1000v

(...略...)

ntp server 10.0.0.1
ntp server 10.0.0.2

(...略...)

wsma agent exec
!
wsma agent config
!
wsma agent filesys
!
wsma agent notify
!
!
end

インプット前に必要な準備

  • ゴールとなる、あるべき姿のコンフィグ

自動化システム内で処理すること

  • 現在のコンフィグと、指定した全体的宣言コンフィグの差分を生成
    • または、コンフィグをアトミックに切り替えられる機器であれば不要
  • no コマンドや、設定間の依存性に要注意
  • 生成したコンフィグを投入
    • コンフィグをアトミックに切り替えられる機器であれば、切り替え

コンフィグが正しく入ったか確認する方法

  • インプットのコンフィグと事後のコンフィグが一致していること


・[3] 部分宣言的パラメーター

f:id:akira6592:20190208140626p:plain
部分宣言的パラメーター

部分的な設定を「こうあってほしい」という表現でパラメータで表現するパターンです。機器全体の現状の設定を知らず、各部署から設定変更依頼がパラメーターでくる場合もこのパターンです。

  • yaml で指定する例
- ntp_servers:
    - 10.0.0.1
    - 10.0.0.2

インプット前に必要な準備

  • 統一されたフォーマットの設定パラメーター

自動化システム内で処理すること

  • パラメーターから投入コマンドの生成
  • no コマンドや、設定間の依存性に要注意

コンフィグが正しく入ったか確認する方法

  • インプットから生成したコンフィグが処理され、追加、変更、削除後に宣言した通りの設定になること
  • 例(追加)
    • 事前設定状態: A, B
    • 宣言パラメーター: A, B, C
    • 処理: 投入コマンドとして差分「C」を生成して投入
    • 事後設定状態: A, B, C
    • 確認:
      • 宣言パラメーター「A, B, C」と事後設定状態「A, B, C」が一致すること
      • 差分「C」が事後設定状態「A, B, C」に含まれること


・[4] 部分手続き的コンフィグ

f:id:akira6592:20190208135137p:plain
部分手続き的コンフィグ

手順化した作業用投入コンフィグのイメージです。手作業するときに、コピペ用に準備するようなものと同じようなものです。

ntp server 10.0.0.1
ntp server 10.0.0.2

インプット前に必要な準備

  • 設定、削除、依存性に考慮して手順化したコンフィグを生成

自動化システム内で処理すること

  • 生成したコンフィグを投入

コンフィグが正しく入ったか確認する方法

  • 事前状態に手続きコンフィグをマージ(追加、変更、削除)した結果と、事後設定状態が同じこと
    • マージのロジックはプログラム側で独自実装する必要がある
  • 例(追加)
    • 事前設定状態: A, B
    • 手続きコンフィグ: C
    • 処理: 手続きコンフィグ通り「C」を投入
    • 事後設定状態: A, B, C
    • 確認:
      • 事前設定状態「A, B」と手続きコンフィグ「C」をマージした結果と、事後設定状態「A, B, C」が同じであること
      • 手続きコンフィグ「C」が事後設定状態「A, B, C」に含まれること




■ まとめ

ネットワーク設定自動化に必要な設定情報のインプットをどのような形式を、範囲、処理形式、表現形式によって分類しました。

f:id:akira6592:20190208140803p:plain
4つのインプット形式

それぞれ、あらかじめ準備することが異なりますので、どのような形式のインプットかを意識して設計すると良いと思います。

ネットワーク自動化しにくい機器(TELNET/WebUI/踏み台の向こう)

はじめに

netmikoNAPALMAnsible のように、既存のネットワークを自動化できるOSSが増えてきました。 それでもやはり、自動化しやすい機器としにくい機器があるなと考えています。

この記事では機器使用面、環境面含めてそれぞれれまとめます。 (当たり前と思われるかもしれませんが、改めて。)


TELNET のみ対応の機器

「はじめに」でご紹介したような OSS は、基本的に SSH 接続が前提です。NETCONF や HTTP API に対応しているものもあります。

TeraTerm マクロの延長で考えると、接続方法(TELNET/SSH)は特に関係ないのではと思われるかもしれません。TeraTerm マクロの場合は、接続処理を TeraTerm 本体が担っていています。 一方で、上記のような OSSTeraTerm とは別の仕組みを利用しており、接続方法はその仕様に依存します。 Python では Paramiko という Python で書かれた SSH 実装を利用している OSS が多いです。

一応、netmiko で telnet ができたり、Ansible に telnet モジュールがあったりはします。

Ansible の場合

Ansible で Cisco IOS の機器に対して、show version を実行する場合に、telnetSSH でどのように Playbook の書き方が異なるか見てみます。

telnet (telnet モジュール)

telnet するには telnet モジュールを利用します。 (公式ドキュメントから引用)

- name: run show commands
  telnet:
    user: cisco
    password: cisco
    login_prompt: "Username: "
    prompts:
      - "[>|#]"
    command:
      - terminal length 0
      - show version

SSH (ios_command モジュール)

SSHCisco IOS も show コマンドを実行するには ios_command モジュールを利用します。 (公式ドキュメントから引用)

- name: run show version on remote devices
  ios_command:                   # 注釈)認証情報は別途定義したものを利用(標準機能)
      commands: show version

違いは?

ご覧いただいたように、ios_command モジュールのほうがシンプルに書けます。telnet モジュールの各オプションで指定しているような、

  • ログインする際のプロンプトはどのような文字列か
  • CLI の プロンプトはどのような文字があり得るか
  • ページャを無効にするための terminal length 0

といった定義は、ios_command モジュール内にあらかじめ組み込まれています。そのため、Playbook はシンプルに書けます。

また、各種OSSSSH や、NETCONF、WEB API 対応が中心であるため、もし telnet 接続機能にバグがあって、issue やプルリクエストを出しても、低い優先度で扱われてしまう可能性もあります。

TELNET が自動化しにくい理由まとめ

  • 各種OSSSSH や、NETCONF、WEB API 対応が中心
  • telnet できる機能があったとしても、おまけ的

もちろんセキュリティの観点もあります。

[2019/07/28 追記] twitterでこんな意見もいただきました


■ Web UI のみ対応の機器

Web UI は人が直接操作するのに適している UI であり、自動化(機械的に処理)するには向いていません。 selenium で自動化しようとしても、ちょっとした画面の変更で動かなくなったりする可能性があります。 本来作りこみたい処理に比べて、画面遷移処理などのオーバーヘッドが高くなりがちです。


■ 踏み台の向こう側の機器

手作業に踏み台サーバーにログインして、そこからさらに対象のネットワーク機器にログインする運用もあると思います。 自動化するときも踏み台を経由しなければいけない場合は、一工夫必要になります。環境によっては難しいケースもあるかもしれません。 また、複雑な環境によりトラブルシューティングもしにくくなってしまう可能性があります。

自動化のしやすさの面では直接接続できる環境のほうが良いと思います。構成次第ではAnsibleをインストールしたサーバー自体を踏み台と見なせるケースもありそうです。


さいごに

今回は大枠での私見をまとめました。 抜けてる観点などありましたら @akira6592 へご連絡いただけると幸いです。 SSH ができても show コマンド結果が json などのマリンリーダブルな形式で出力できない、など細かいところではまだあると思います。