てくなべ (tekunabe)

ansible / network automation / 学習メモ

はじめて自社のアドベントカレンダーを企画したらアウトプッターが集まった話

はじめに

2018年、自社ではじめてアドベントカレンダーを企画し、枠をすべて埋めた形で無事に終了しました。

f:id:akira6592:20181225155831p:plain:w300
埋まった

qiita.com

この記事では、企画の経緯や感じたことなどをまとめたいと思います。

アドベントカレンダーは本来、クリスマスまでの期間に日数を数えるために使用されるカレンダーのことです。この習慣に乗っかるかたちで、記事を投稿しあうイベントで https://qiita.com/advent-calendarhttps://adventar.org/ などが有名です。

そろそろウチでも・・

弊社でもここ数年、ブログやイベント登壇などによって技術情報を社外にアウトプットする人たちが増えてきました。そのため「そろそろ、ウチでもアドベントカレンダーいけるんじゃないか?」と思って9月ごろに考えました。

全社員にお知らせ

社内数人に少し相談したところ好感触だったので、10月末に全社員にメールなどを通じて企画をお知らせしました。

伝えた内容は以下の通りです(概要)

  • どうやって参加するの?
    • Qiita アカウントでログインして https://qiita.com/advent-calendar/2018/ap-com の12月1日から25日までの 空いている日にちに登録
    • Organization に所属してなくても参加OK
    • この機会に Organization に所属した場合は連絡を
    • 記事自体は外部のブログでもOK
  • なぜ開催するの?
  • アウトプットするメリットは?
    • (予想以上の反響があったり疑問点が解消したりして、さらにアウトプットしたい、勉強したい、という気持ちになった新卒2年目の事例を紹介)
  • どんなネタにしたら良い?
    • プログラミングでもサーバーでもネットワークでもOK、あくまで技術中心
    • その他、相談ごとなどあったらお気軽に私まで

わりと順調に枠が埋まっていく

企画のお知らせの後、少しずつ枠が埋まっていきました。普段あまり接点がない人でも技術的な興味が似通っているという発見もありました。

投稿開始~終了

多くの人が、あらかじめ記事を書いて下書き、予約といった準備をしていたようで、12/01 の開始以降も順調に投稿されていきました。

途中、広報や上層部からも注目され、宣伝してもらったので社内認知度も上がったと思います。

しばらく空いたままの枠もありましたが、2枠目を登録する人によって助けられました。私自身でも2枠目3枠目を埋めることはできましたが、なるべく多くの人に参加してもらいたかったため自粛しました。

そして 12/25 に最後の投稿がされて、無事に全部埋まった形で終了しました。

記事一覧

以下の記事が投稿されました。

日付 タイトル
12/01 [Ansible] グループ変数を活用したネットワーク機器への Syslog サーバー追加
12/02 Ansibleを実際使ってみてハマったハマりポイント
12/03 VSCode内の統合ターミナルから、Docker内でアプリを実行するために使った力技
12/04 VBAでOutlookの仕様『宛先へ付与される「’」』を表示名ごと削除する
12/05 Drag & Drop API を使うときにやっておいたほうがいいこと
12/06 Terraformを使ってEKSを構築する
12/07 外部からVPC内に接続するまでの経路が途切れてしまったときの緊急対処法
12/08 Golangでインターフェースを使いコードを疎結合にする
12/09 React 16.6の新機能、React.lazyとReact.Suspense を使った非同期処理
12/10 React v16.x ロードマップをかいつまんでみた
12/11 ネットワークエンジニアがMacで業務するために必要なツールたちまとめ
12/12 Outlook VBAで定型項目の通知メールを自動転記する
12/13 VagrantにてOpenstack&TungstenFabricを一発構築してみた(作業:1分未満、待ち:数十分)
12/14 Ansible_そういえば、よく使ったねモジュールランキング2018
12/15 Zabbix4.0のインポートファイルで設定出来ない項目を一括変更する方法
12/16 Cloud AutoML VisionによるCiscoルータの分類 ~画像データ水増し効果の推定~
12/17 VagrantによるVXLAN設定環境一発構築
12/18 WordPress環境を作る Kubernetes編
12/19 Kerasの学習済みモデルを使ってサクッとWebアプリ作成
12/20 Rancher を使ってCloudProviderを使ってみた(on AWS)
12/21 EC2インスタンスの状態変化をLambda(boto3)とSNSで自動通知する
12/22 PackerのAnsibleProvisionerでインベントリ毎のgroup_varsを使い分ける
12/23 Kubernetesで監視を行う際の注意点
12/24 ST2をslackでコントロールする
12/25 [StackStorm] mysql Pack 使ってみた

終わってみて

アウトプットする人たちを引き出して可視化できた

今回のアドベントカレンダーという、アウトプットする場を用意することで、アウトプットする人たちを引き出せました。年内までの社内の技術研修のアウトプット先としてもちょうどよかったようです。

眺めるみると、この人は乗っかってくれるだろう、という人もいれば、意外な人もいて興味深かったです。「あの人 Qiita やってたんだ!」のような。いちエンジニア社員の呼びかけで、集まってもらって嬉しかったです。

[Ansible] 公式 lint ツール、ansible-lint 4.0.0 リリース。新しいドキュメントサイトやデフォルトルール追加など

■ はじめに

Ansible Playbook の 書式をチェックする lint ツール ansilbe-lint のバージョン 4.0.0 が 2018/12/18 にリリースされました。

  • 以下 changelog から引用
    • New documentation site docs.ansible.com/ansible-lint
    • Additional default rules for ansible-lint, listed in docsite default rules
    • Fixed running with role path containing single or multiple dirs #390
    • Fixed double sudo rule output #393
    • Severity property added to rules to be used by Galaxy #379
    • Packaging: consistency and automation #389
    • Updated rule TrailingWhitespaceRule.py to remove carriage return char #323
    • Allow snake_case module names for rules #82
    • Suggest tempfile module instead of mktemp command #422
    • Update tox to run with only supported ansible versions #406
    • GitHub repository edits: move to ansible org, add CODE_OF_CONDUCT, add ROADMAP, label edits

インストールやアップグレードは、今までと同じく「pip install ansible-lint」、「pip install --upgrade ansible-lint」でできます。

この記事では、個人的にきになった、新しいドキュメントサイトと、追加されたデフォルトルールについてまとめます。


■ 新しいドキュメントは doc.ansible.com 配下に

https://docs.ansible.com/ansible-lint/ が新しいドキュメントのサイトです。

f:id:akira6592:20181224125025p:plain

ansible-lint はいままで、willthames/ansible-lint というリポジトリで開発されていましたが、2018年10月に ansilbe 配下の ansilbe/ansible-lint に移動しました。これでドキュメントもコードも ansible 配下ということになりました。

なお、現在では ansible 本体のドキュメント上では、anislbe-lint は

the official, highly configurable best-practices linter for Ansible playbooks, by Ansible.

と記載されています。


■ デフォルトルールの追加

ansible-lint 4.0.0 で 14 個のデフォフォルトルールが追加されました

ここでは、今回追加されたデフォルトルールの中で、気になったルールをいくつか確認してみます。

Deprecated module は使わないこと

Ansible では、将来利用不可になるなどの利用で、利用が推奨されていないモジュールがあります。ドキュメント上では、Deprecated module と表現されます。このルールでは、Deprecated module を使用を禁止します。

{{ var_name }} の変数名の前後にはスペースを入れること

  • [E206] Variables should have spaces before and after: {{ var_name }}

Plaubok 内では、変数名を {{ }} で囲いますが、その際、変数名の前にスペースを入れる、というルールです。たまに、スペースがない記載を見かけます。

ロール内の copy や template の src には ../templates を指定しないこと

  • [E404] Doesn’t need a relative path in role

(Playbookではなく)ロール内で使用する、copy や template モジュールの src オプションで、../templates を含む相対パスを使用しない、というルールです。 もともとロールの仕組みとして、明示的な指定をしなくてもロールから見て ../templates/ 配下のファイルを参照する仕様なので、書き方を統一させるいみでのルール追加なのだと思います。

なお、コードを見る限りcopytemplates モジュールの他に、win_copywin_templates モジュールも、このルールの対象のようです。

リテラルと True/False を比較しないこと

  • [E601] Don’t compare to literal True/False

when: var == True ではなく、when: var で、

when: var == Flase ではなく、when: not var で、

というルールです。

空文字を比較しないこと

  • [E602] Don’t compare to empty string

when: var != "" ではなく、when: var で、

when: var == "" でなく、when: not var で、

というルールです。

補足

もちろん、今まで通りデフォルトルールを除外したり(コンフィグファイル内の skip_list )、逆に新しいルールを追加することもできます。

まとめ

これまで、複数の書き方が許容されていたものなどに対して、新たなルールが設けられました。 公式の linter である ansible-lint のデフォルトルールが追加されていくことで、一つの書き方に緩やかに収束していくのだと思います。

[Ansible] ios_config モジュールの backup オプションによるバックアップで意図しないバックアップファイルが削除されるバグについて (Ansible 2.7.5 現在)

■ はじめに

Ansible には Cisco IOS ネットワーク機器に設定変更コマンドを実行する ios_config モジュールがあります。 ios_config モジュールには、backup という、設定変更前のコンフィグを事前に Ansible 側に保存するオプションがあります。 デフォルトは no のため、バックアップは保存しません。backup: yes と指定するとバックアップが有効になります。

この backup オプションによるバックアップには、ターゲットホスト名が類似(例: ios01ios01a)した複数のホストを対象にすると、バックアップファイルが他ホストによって上書きされてしまう、というバグがあります。(Ansible 2.7.5 現在)

現在 devel ブランチで開発中の Ansible 2.8 では修正されています。

この記事では、本バグについての発生条件、再現性の確認、修正後の動作確認についてご紹介します。

(2019/02/08 追記) Ansible 2.7 は 2.7.7 で本バグが修正されたようです。

Change backup file globbing for network _config modules so backing up one host's config will not delete the backed up config of any host whose hostname is a subset of the first host's hostname (e.g., switch1 and switch11)

ansible/CHANGELOG-v2.7.rst at stable-2.7 · ansible/ansible · GitHub


■ 原因

バックアップする直前に、過去のバックアップファイルを削除します。 削除対象のファイル名を決める際、ホスト名の 前方一致 でマッチさせているため、意図しないホストのバックアップファイルまで消してしまいます。

そのため、例えば ios01aios01 の 2ホスト対してバックアップを行う場合、ios01aios01 の順にのタスクが実行されると、以下のようになってしまいます。

  • ios01a のタスク
    • ios01a の前方一致でマッチしたファイルを削除(特に問題なし)
    • ios01a のバックアップファイルを保存する
  • ios01 のタスク
    • ios01 の前方一致でマッチしたファイルを削除(先程保存したios01a のバックアプファイルが削除されてしまう)
    • ios01 のバックアップファイルを保存する


■ 再現の確認(Ansible 2.7.5)

バグが発生することを確認してみます。

インベントリファイル (inventory.ini)

先程例に示した、2ホストを定義して、グループ ios でまとめます。

[ios]
ios01 ansible_host=ios-xe-mgmt.cisco.com 
ios01a ansible_host=ios-xe-mgmt.cisco.com

変数ファイル (gorup_vars/ios.yml)

グループ ios が利用する変数を定義します。特に今回のバグに関係するものはありません。

ansible_network_os: ios
ansible_user: user
ansible_password: pass9999
ansible_connection: network_cli

playbook (backup_test.yml)

グループ ios を対象にして ios_config モジュールの backup オプションによる、バックアップのみ行う Playbook にします。

- hosts: ios
  gather_facts: no

  tasks:
    - name: backup test
      ios_config:
        backup: yes

実行結果

ここでは分かりやすいように、ホストごとに ansible-playbook コマンドを分けて実行します。

1つめのホスト(ios01a)

まずは、ios01a に対して実行します。

$ ansible --version
ansible 2.7.5
(...略...)

$ ansible-playbook -i inventory.ini backup_test.yml -l ios01a

PLAY [ios] *************************************************************************

TASK [backup test] *****************************************************************
ok: [ios01a]

PLAY RECAP *************************************************************************
ios01a                     : ok=1    changed=0    unreachable=0    failed=0

バックアップファイルは backup ディレクトリの中に保存される(なければ作成される)ので、backup ディレクトリ内を確認します。

$ tree backup
└── ios01a_config.2018-12-22@10:37:25

正常に、ios01a のバックアップファイルが保存されました。

2つめのホスト (ios01)

続いて、ios01 に対して実行します。

$ ansible-playbook -i inventory.ini backup_test.yml -l ios01

PLAY [ios] *************************************************************************

TASK [backup test] *****************************************************************
ok: [ios01]

PLAY RECAP *************************************************************************
ios01                      : ok=1    changed=0    unreachable=0    failed=0

先ほどと同じく、backup ディレクトリを確認します。

$ tree backup
backup
└── ios01_config.2018-12-22@10:38:26

このように、1つめのホスト ios01a のバックアップファイルが消えてしまいios01 のバックアップファイルのみになってしまいました。バグが再現しました。

本来であれば以下のように、 ios01ios01a の 2ホスト分のバックアップアップファイルがあるべきところです。

$tree backup
backup
├── ios01_config.2018-12-22@10:38:26 
└── ios01a_config.2018-12-22@10:37:25   # このファイルが消えてしまった


■ 開発中の Ansible 2.8 での修正確認

本バグの修正コードは、devel ブランチ(開発中のAnsible 2.8)にマージされています。修正されていることを確認するために、実際に試してみます。

先程用意したインベントリファイルや Playbook など一式はそのまま利用します。backup ディレクトリは一旦削除しておきます。

1つめのホスト(ios01a)

まずは、ios01a に対して実行します。

$ ansible --version
ansible 2.8.0.dev0
(...略...)
$  ansible-playbook -i inventory.ini backup_test.yml -l ios01a

PLAY [ios] *************************************************************************

TASK [backup test] *****************************************************************
ok: [ios01a]

PLAY RECAP *************************************************************************
ios01a        : ok=1    changed=0    unreachable=0    failed=0    skipped=0

backup ディレクトリを確認します。

$ tree backup
backup
└── ios01a_config.2018-12-22@10:51:28

正常に ios01a のバックアップファイルが保存されました。ここまでは、Ansible 2.7.5 で試したときと同じです。

2つめのホスト(ios01)

続いて、ios01 に対して実行します。

$  ansible-playbook -i inventory.ini backup_test.yml -l ios01

PLAY [ios] *************************************************************************

TASK [backup test] *****************************************************************
ok: [ios01]

PLAY RECAP *************************************************************************
ios01         : ok=1    changed=0    unreachable=0    failed=0    skipped=0

backup ディレクトリを確認します。

$tree backup
backup
├── ios01_config.2018-12-22@10:52:35
└── ios01a_config.2018-12-22@10:51:28

今回(開発中の Ansible 2.8)は、無事に 2つのホスト分のバックアップファイルがある状態になりました。


IOS 以外のモジュールにも同様のバグ

修正のPRを確認すると分かりやすいのですが、他のプラットフォームのモジュールにも同じような、ホスト名の前方一致で削除対象のファイル名を決めている箇所があったようです。

junos_config モジュールの backup オプションだけ試したのですが、やはり Ansible 2.7.5 で同じバグが再現でき、開発中の Ansible 2.8 で修正されていることを確認しました。


■ まとめ

Ansible 2.7.5 現在、cisco_ios モジュールの backup オプションのコンフィグファイルのバックアップの処理で、ターゲットホスト名が類似していると、意図せずファイルが削除される場合があることを確認できました。 このバグは Ansible 2.8 で修正される予定です。また、Ansible 2.7 系のブランチにもバックポートされそう(2018/12/22現在)なので、Ansible 2.7.6 で修正されるかもしれません。

参考

対応 issue

github.com

対応 PR

devel ブランチ

github.com

stable-2.7 ブランチ

github.com

[Ansible] ios_config モジュールの src で指定するファイルの内容には正しいインデントが必要


これは Ansible Blogger 2018 (sponsored by Red Hat) Advent Calendar 2018 の22日目の記事です。

■ はじめに

Ansible には、 Cisco IOS ネットワーク機器に対して設定変更コマンドを実行できる ios_config モジュールがあります。

ios_config モジュールには、Playbook 内に実行したいコマンドを直接指定する lines オプションのほかに、src オプションがあります。 src には、別ファイルにコマンドを書いて(以下、コマンドファイル)、そのファイル名を指定します。 コマンドファイルはただコマンドを列挙するだけでなく、階層を考慮して適切にインデントする必要があります。

f:id:akira6592:20181222130211p:plain
正しいインデントが必要

この記事では、どのようにインデントすればよいのか、なぜインデントが必要なのか、についてご説明します。


■ まとめ

少し長くなるので、はじめにまとめます。

  • 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 TESTip 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 モジュールは、コマンド実行前に、そのコマンドがネットワーク機器側に設定済みかどうか確認し、設定済みであれば実行しない、という仕組みです。設定済みかどうか確認する際に、コンフィグの階層まで含めて比較、確認します。

f:id:akira6592:20181217133821p:plain
階層を解釈して比較し差分を生成

階層まで含めて正しく比較するために、コマンドファイルのインデントが利用されます。

具体的な例で見ていきましょう。

インデントがないとコンフィグ階層が解釈されない

インデントがないと、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 コマンドが利用できないためです。

f:id:akira6592:20181217120626p:plain
インデントがない場合すべてグローバルレベルで比較

  • 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 TESTip address 172.16.0.1 255.255.255.0 コマンドが、interface GigabitEthernet3 配下である、という階層に解釈されます。そのため、interface GigabitEthernet3 は、親階層のコマンドとして必ず実行されます。

そして、差分コンフィグ生成の際、ネットワーク機器側の interface GigabitEthernet3description TESTip address 172.16.0.1 255.255.255.0 コマンドがないため、(コンフィグ階層を保ったまま)実行する必要があると判断されます。

その結果、以下の 3行がすべて実行されます。

interface GigabitEthernet3
 description TEST
 ip address 172.16.0.1 255.255.255.0

f:id:akira6592:20181217120807p:plain
インデントがあると階層を解釈して比較

  • コマンド実行イメージ(正常)
csr1000v(config)#interface GigabitEthernet3
csr1000v(config-if)#description TEST
csr1000v(config-if)#ip address 172.16.0.1 255.255.255.0

なお、これらの動作は、src の代わりに linesparents で以下のように指定した場合と同じです。このタスクでは親階層を示すコマンドである inteface GigabitEthernet3lines ではなく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 で表示される形式と同じ
  • インデントがない場合、すべてグローバルコンフィギュレーションモードで実行しようとしてしまう
  • インデントがある場合、コンフィグの階層を解釈したうえで正しく実行する

[Bolt] エージェントレスなインフラ自動化ツール「Puppet Bolt」かんたんチュートリアル

■ はじめに

Puppet Bolt はエージェントレスなインフラ自動化ツール

Ansible や Chef などとよく比較される Puppet という構成管理ツールがあります。 Puppet といえばエージェント型のイメージがありますが、2018年10月にエージェントレス型の別ツール「Puppet Bolt(以下、Bolt)1.0」がリリースされました。

puppet.com

thinkit.co.jp

Bolt は、サーバーに対してパッケージのインストールやサービスの起動などの設定作業を自動化できます。エージェントレスという点では、Ansible に近いかも知れません。なお、ネットワーク機器に対応しているかどうかは調査できていません。

インストールは Linux にも Windows にもでき、管理対象としても Linux(SSH接続) にも Windows(WinRM接続) に対応していうようです。

この記事では、私が試したインストール方法や簡単な使い方や、補足情報をチュートリアルとしてご紹介します。

主な内容

  • インストール
  • 単純なリモートコマンドの実行(bolt command run
  • スクリプトを指定して実行する(bolt script run
  • 「タスク」を指定して実行する(bolt task run
  • 「プラン」を指定して実行する(bolt plan run

環境

  • Bolt 1.6.0
  • Bolt インストール先: CentOS 7.5.1804
  • 管理対象: CentOS 7.5.1804


■ 用語の整理

チュートリアルに入る前に、今後出てくる用語の整理です。 少し無理やりなところもありますが、Bolt の用語と Ansible の用語を対応させてみました。

Bolt Ansibe 説明
inventory invnetory 接続先のホスト情報を記載するもの
command ansible コマンドで shellcommand モジュールを利用する アドホックなコマンド実行
task module 特定の機能を持つもの
plan Playbook 一連処理、定義を記述したもの




■ インストール

各種パッケージマネージャーを利用してインストールします。

RHEL の場合

RHEL 6

sudo rpm -Uvh https://yum.puppet.com/puppet6/puppet6-release-el-6.noarch.rpm
sudo yum install puppet-bolt

RHEL 7

今回はこちらの方法を利用しました。

sudo rpm -Uvh https://yum.puppet.com/puppet6/puppet6-release-el-7.noarch.rpm
sudo yum install puppet-bolt

詳細は「Install Bolt on RHEL or SLES」を参照してください。

Windows の場合

Bolt は Windows にも対応していて、MSI や Chocolatey でインストールできます。 詳細は「install Bolt on Windows」を参照してください。

その他

その他、macOS や他の方法のインストールは「Installing Bolt」を参照してください。

他のプラットフォーム向けのインストール手順は以下のページに記載されています。 https://puppet.com/docs/bolt/1.x/bolt_installing.html

インストールできたことを確認するため、バージョンを表示してみます。

$ bolt --version
1.6.0

今回は 1.6.0 というバージョンがインストールされました。

bolt help を実行すると、ヘルプが表示されます。

$ bolt help
Usage: bolt <subcommand> <action> [options]

Available subcommands:
  bolt command run <command>       Run a command remotely
  bolt file upload <src> <dest>    Upload a local file
  bolt script run <script>         Upload a local script and run it remotely
  bolt task show                   Show list of available tasks
  bolt task show <task>            Show documentation for task
  bolt task run <task> [params]    Run a Puppet task
  bolt plan show                   Show list of available plans
  bolt plan show <plan>            Show details for plan
  bolt plan run <plan> [params]    Run a Puppet task plan
  bolt apply <manifest>            Apply Puppet manifest code
  bolt puppetfile install          Install modules from a Puppetfile into a Boltdir

Run `bolt <subcommand> --help` to view specific examples.

where [options] are:
    -n, --nodes NODES                Identifies the nodes to target.
                                     Enter a comma-separated list of node URIs or group names.
                                     Or read a node list from an input file '@<file>' or stdin '-'.
                                     Example: --nodes localhost,node_group,ssh://nix.com:23,winrm://windows.puppet.com
                                     URI format is [protocol://]host[:port]
                                     SSH is the default protocol; may be ssh, winrm, pcp, local, docker, remote
                                     For Windows nodes, specify the winrm:// protocol if it has not be configured
                                     For SSH, port defaults to `22`
                                     For WinRM, port defaults to `5985` or `5986` based on the --[no-]ssl setting
    -q, --query QUERY                Query PuppetDB to determine the targets
        --noop                       Execute a task that supports it in noop mode
        --description DESCRIPTION    Description to use for the job
        --params PARAMETERS          Parameters to a task or plan as json, a json file '@<file>', or on stdin '-'
Authentication:
    -u, --user USER                  User to authenticate as
    -p, --password [PASSWORD]        Password to authenticate with. Omit the value to prompt for the password.
        --private-key KEY            Private ssh key to authenticate with
        --[no-]host-key-check        Check host keys with SSH
        --[no-]ssl                   Use SSL with WinRM
        --[no-]ssl-verify            Verify remote host SSL certificate with WinRM
Escalation:
        --run-as USER                User to run as using privilege escalation
        --sudo-password [PASSWORD]   Password for privilege escalation. Omit the value to prompt for the password.
Run context:
    -c, --concurrency CONCURRENCY    Maximum number of simultaneous connections (default: 100)
        --compile-concurrency CONCURRENCY
                                     Maximum number of simultaneous manifest block compiles (default: number of cores)
        --modulepath MODULES         List of directories containing modules, separated by ':'
        --boltdir FILEPATH           Specify what Boltdir to load config from (default: autodiscovered from current working dir)
        --configfile FILEPATH        Specify where to load config from (default: ~/.puppetlabs/bolt/bolt.yaml)
        --inventoryfile FILEPATH     Specify where to load inventory from (default: ~/.puppetlabs/bolt/inventory.yaml)
Transports:
        --transport TRANSPORT        Specify a default transport: ssh, winrm, pcp, local, docker, remote
        --connect-timeout TIMEOUT    Connection timeout (defaults vary)
        --[no-]tty                   Request a pseudo TTY on nodes that support it
        --tmpdir DIR                 The directory to upload and execute temporary files on the target
Display:
        --format FORMAT              Output format to use: human or json
        --[no-]color                 Whether to show output in color
    -h, --help                       Display help
        --verbose                    Display verbose logging
        --debug                      Display debug logging
        --trace                      Display error stack traces
        --version                    Display the version




■ 単純なリモートコマンドの実行(bolt command run

リモートホストに対して、一度きりの単純なコマンドを実行してみましょう。ここでは hostname を実行します。

  • 実行コマンド
bolt command run "hostname" -n 172.16.0.10 -u vagrant --no-host-key-check -p

各オプションの意味は以下の通りです。

オプション 説明 今回の指定値
command run リモート実行するコマンドを指定するサブコマンド hostname
-n (--nodes) リモートホスト 172.16.0.10
-u (--user) リモートユーザー名 vagrant
--no-host-key-check SSHホストキーのチェックを無効
-p (--password) リモートユーザーパスワード (指定なし、プロンプトで入力)
  • 実行結果
$ bolt command run "hostname" -n 172.16.0.10 -u vagrant --no-host-key-check -p
Please enter your password: (パスワードを入力)
Started on 172.16.0.10...
Finished on 172.16.0.10:
  STDOUT:
    testsv    ← リモートホストで hostname コマンドを実行した結果
Successful on 1 node: 172.16.0.10
Ran on 1 node in 0.67 seconds

補足

リモートホストを指定する -n(--nodes) とトランスポート

-n 172.16.0.10,172.16.0.11 のようにカンマ区切りにすると複数を対象にできます。また、インベントリファイルによって、ホスト情報や接続方式を管理することもできるようです。 もしWindows を対象に WinRM で接続する場合は 、以下のよ

  • -n winrm://winsv01 のようにスキームでトランスポートオプションを指定する
  • -n winsv01 --transport winrm のように、 --tranport オプションで指定する

-n オプションの詳細はこちら

トランスポートは以下の4つから選択できます。 - ssh (デフォルト) - winrm - local - docker

その他のオプション

上記で利用したオプションの他にも、秘密鍵の指定(--private-key)や、権限昇格の指定(--run-as)などのオプションもあります。 デバッグ表示する --debug も便利です。 すべてのオプションについては bolt help コマンド結果のヘルプを参照してください。

対応する公式ドキュメント


スクリプトを指定して実行する(bolt script run

Bolt は、先程のように短いコマンドの実行だけでなく、予め用意したスクリプトを指定してリモート上で実行することもできます。 ここでは、myscript.sh という簡単なシェルスクリプトを用意して、bolt 経由でリモート上で実行します。

#!/bin/bash
echo "Hello, Bolt! on (`hostname`)"
  • 実行コマンド
bolt script run myscript.sh -n 172.16.0.10 -u vagrant --no-host-key-check -p
  • オプション説明
オプション 説明 今回の指定値
script run リモート実行するスクリプトを指定するサブコマンド myscript.sh

※その他は bolt command run 実行時と同じ

  • 実行結果
$ bolt script run myscript.sh -n 172.16.0.10 -u vagrant --no-host-key-check -p
Please enter your password: (パスワードを入力)
Started on 172.16.0.10...
Finished on 172.16.0.10:
  STDOUT:
    Hello, Bolt! (on testsv)  ← リモートホストで myscript.sh を実行した結果
Successful on 1 node: 172.16.0.10
Ran on 1 node in 0.68 seconds

今回は、シェルスクリプトを指定しましたが、 Python や、PowerShell(リモートが Windows の場合)でもよいようです。

補足

対応する公式ドキュメント




■ 「タスク」を指定して実行する(bolt task run

今度はタスクの実行です。タスクとは特定の機能をも持つ機能単位で、モジュール名::タスク名 のように指定します。タスク名を省略して モジュール名 のように指定した場合は、 init という名前のタスクが呼ばれます。 さらに、実行するタスクにが利用するオプションと値を必要に応じて指定します。 例えば、service::linux name="postfix" action="stop" のようなかたちです。

(どのようなモジュール、タスクがあるのかは調べきれておりません・・。独自追加もできるようです。)

タスク実行その1: サービスの制御

ここでは、リモートホストhttpd サービスを停止するタスクを実行します。

  • 実行コマンド
bolt task run service::linux name="postfix" action="stop" -n 172.16.0.10 -u vagrant --no-host-key-check -p --run-as root
  • オプション説明
オプション 説明 今回の指定値
task run タスクを指定するサブコマンド service::linux
name タスク service::linux で利用するサービス名 posffix
action タスク service::linux で利用するアクション名 stop
--run-as su 先ユーザー root

※その他は bolt command run 実行時と同じ

  • 実行結果
$ bolt task run service::linux name="postfix" action="stop" -n 172.16.0.10 -u vagrant --no-host-key-check -p --run-as root
Please enter your password: (パスワードを入力)
Started on 172.16.0.10...
Finished on 172.16.0.10:
  {
    "status": "postfix stop"
  }
Successful on 1 node: 172.16.0.10
Ran on 1 node in 1.51 seconds

タスク実行その2: パッケージのインストール

今度は、linux にパッケージをインストールしてみます。利用するタスクは package::linux です。

$ bolt task run package::linux action=install name=wget -n 172.16.0.10 -u vagrant --no-host-key-check -p --run-as root
  • オプション説明 | オプション | 説明 | 今回の指定値 | |---|---|--| | task run | タスクを指定するサブコマンド| package::linux | | name | タスク package::linux で利用するサービス名 | install | | action | タスク package::linux で利用するアクション名 | wget |
$ bolt task run package::linux action=install name=wget -n 172.16.0.10 -u vagrant --no-host-key-check -p --run-as root
Please enter your password:
Started on 172.16.0.10...
Finished on 172.16.0.10:
  {
    "status": "wget install"
  }
Successful on 1 node: 172.16.0.10
Ran on 1 node in 1.97 seconds

補足

モジュールやタスクのオプションなどの情報

タスクの一覧は bolt task show コマンド で確認できます。

  • タスク一覧の表示
$ bolt task show
facts                              Gather system facts
facts::bash                        Gather system facts using bash
facts::powershell                  Gather system facts using powershell
facts::ruby                        Gather system facts using ruby and facter
package                            Manage and inspect the state of packages
package::linux                     Manage the state of packages (without a puppet agent)
package::windows                   Manage the state of packages (without a puppet agent)
puppet_agent::install              Install the Puppet agent package
puppet_agent::install_powershell
puppet_agent::install_shell
puppet_agent::version              Get the version of the Puppet agent package installed. Returns nothing if nonepresent.
puppet_agent::version_powershell
puppet_agent::version_shell
puppet_conf                        Inspect puppet agent configuration settings
reboot                             Reboots a machine
reboot::last_boot_time             Gets the last boot time of a Linux or Windows system
service                            Manage and inspect the state of services
service::linux                     Manage the state of services (without a puppet agent)
service::windows                   Manage the state of Windows services (without a puppet agent)

Use `bolt task show <task-name>` to view details and parameters for a specific task.

各モジュール、タスクの情報は bolt task show モジュール名::タスク名 コマンド で確認できます。

  • service の情報
$ bolt task show service

service - Manage and inspect the state of services

USAGE:
bolt task run --nodes <node-name> service action=<value> name=<value> provider=<value>

PARAMETERS:
- action: Enum[start, stop, restart, enable, disable, status]
    The operation (start, stop, restart, enable, disable, status) to perform on the service
- name: String[1]
    The name of the service to operate on.
- provider: Optional[String[1]]
    The provider to use to manage or inspect the service, defaults to the system service manager

MODULE:
built-in module
  • service::linux の情報
$ bolt task show service::linux

service::linux - Manage the state of services (without a puppet agent)

USAGE:
bolt task run --nodes <node-name> service::linux action=<value> name=<value>

PARAMETERS:
- action: Enum[start, stop, restart]
    The operation (start, stop) to perform on the service
- name: String[1]
    The name of the service to operate on.

MODULE:
built-in module

対応する公式ドキュメント




■ 「プラン」を指定して実行する(bolt plan run

最後に、プランの実行を試します。プランとは、コマンドやタスクなどを組み合わせて一連の処理にまとめたようなものです。

ここでは、以下の3つの処理のプランを作成して、実行します。

  • httpd のインストール
  • httpd の起動
  • index.html のコピー

プランの作成

まず、myweb モジュールのプランを配置するためのディレクトリを作成します。

mkdir -p modules/myweb/plans/

続いてプランのファイル(.pp)を作成します。ここでは myweb モジュールの deploy という名前のプランを作成するため、ファイル名を modules/myweb/plans/deploy.pp とします。

plan myweb::deploy (TargetSpec $nodes) {
  run_task(
    "package::linux",
    $nodes,
    name => "httpd",
    action => "install"
  )

  run_task(
    "service::linux",
    $nodes,
    name => "httpd",
    action => "start"
  )

  upload_file(
    "/vagrant/bolt/index.html",
    "/var/www/html/index.html",
    $nodes
  )
}

bolt plan show でプランの定義を確認できます

$ bolt plan show --modulepath ./modules/
aggregate::count
aggregate::nodes
canary
facts
facts::info
myweb::deploy    ← 作成したプラン
puppetdb_fact
reboot

Use `bolt plan show <plan-name>` to view details and parameters for a specific plan.

プランの処理内容

run_task で、package::linux を指定して、httpd をインストールします。続いて、service::linux で http サービスを起動します。 最後にupload_fileでコンテンツファイルをコピーします。

なお、upload_file で指定するパス "/vagrant/bolt/index.html" は、最初、bolt コマンド実行時からの相対パスで指定しましたが、見つからなかったため絶対パスにしました。

index.html の作成

コンテンツとなる簡単な HTML ファイル(index.html)を作成します。

<html>
<body>
<h1> Hello, Bolt!</h1>
</body>
<html>

実行

  • 実行コマンド
bolt plan run test::command nodes=172.16.0.10 --no-host-key-check -u vagrant -p --run-as root  --modulepath ./modules/
  • オプション説明
オプション 説明 今回の指定値
plan run タスクを指定するサブコマンド test::command
nodes プラン test::command で利用するパラメータ(リモートホスト 172.16.0.10
--modulepath モジュールのパス ./modules/
  • 実行結果
$ bolt plan run myweb::deploy nodes=172.16.0.10 --no-host-key-check -u vagrant -p --run-as root  --modulepath ./modules/
Please enter your password: (パスワードを入力)
Starting: plan myweb::deploy
Starting: task package::linux on 172.16.0.10
Finished: task package::linux with 0 failures in 3.99 sec
Starting: task service::linux on 172.16.0.10
Finished: task service::linux with 0 failures in 1.3 sec
Starting: file upload from /vagrant/bolt/index.html to /var/www/html/index.html on 172.16.0.10
Finished: file upload from /vagrant/bolt/index.html to /var/www/html/index.html with 0 failures in 0.93 sec
Finished: plan myweb::deploy in 6.27 sec
Plan completed successfully with no result

f:id:akira6592:20181220115117p:plain
コンテンツ表示確認(URLは環境都合上のもの)

無事に httpd がインストール、起動し、用意したコンテンツが表示されました。

補足

対応する公式ドキュメント




■ まとめ

エージェントレスなインフラ自動化ツール「Puppet Bolt」で、簡単なコマンド実行や、いくつかの処理をまとめたプランの実行を試してみました。 プランの作成に少々戸惑いましたが、コードで柔軟な処理がかけるかも知れません。 実行コマンドも、今回は長めになってしまいましたが、何かしらの定義ファイルを用意しておけば、もっと短くできそうです。

参考

サイト

[nornir] 指定できるプラットフォーム名(ios / junos / eos / vyos など)

■ はじめに

Python 製自動化フレームワークライブラリ nornir は、ネットワーク機器への接続に、 NAPALMnetmiko をデフォルトで利用できます。

接続の際のコネクションパラメーターとして、どのプラットフォームに接続するかを示す platform ( nornir 1.x 系では nornir_nos) 変数を指定します。

たとえば、Juniper Junos をまとめるグループを定義する groups.yaml の場合、以下のような指定になります。

junos: 
  username: root
  password: hogehoge9999
  platform: junos         # プラットフォーム名

このプラットフォーム名の指定は、ネットワーク機器への接続部分に

に依存します。

この記事では、それぞれの場合でどのようなラットフォーム名を利用できるか紹介します。

なお、nornir についての基本情報は以下の記事をご参照ください。 tekunabe.hatenablog.jp


■ NAPALM を利用する場合

NAPALM ドキュメントのGeneral support matrixDriver Name に記載があるもです。

NAPALM 2.3.3 現在は以下の通りです。

  • eos
  • junos
  • iosxr
  • nxos
  • nxos_ssh
  • ios


■ netmiko 利用する場合

netmiko/ssh_dispatcher.pyCLASS_MAPPER で定義されるものです。

netmiko 2.3.0 現在は以下の通りです。( 末尾に _ssh を付けた形も可)

  • a10
  • accedian
  • alcatel_aos
  • alcatel_sros
  • apresia_aeos
  • arista_eos
  • aruba_os
  • avaya_ers
  • avaya_vsp
  • brocade_fastiron
  • brocade_netiron
  • brocade_nos
  • brocade_vdx
  • brocade_vyos
  • calix_b6
  • checkpoint_gaia
  • ciena_saos
  • cisco_asa
  • cisco_ios
  • cisco_nxos
  • cisco_s300
  • cisco_tp
  • cisco_wlc
  • cisco_xe
  • cisco_xr
  • coriant
  • dell_dnos9
  • dell_force10
  • dell_isilon
  • dell_os10
  • dell_os6
  • dell_os9
  • dell_powerconnect
  • eltex
  • enterasys
  • extreme
  • extreme_ers
  • extreme_exos
  • extreme_netiron
  • extreme_nos
  • extreme_slx
  • extreme_vdx
  • extreme_vsp
  • extreme_wing
  • f5_linux
  • f5_ltm
  • f5_tmsh
  • fortinet
  • generic_termserver
  • hp_comware
  • hp_procurve
  • huawei
  • huawei_vrpv8
  • ipinfusion_ocnos
  • juniper
  • juniper_junos
  • linux
  • mellanox
  • mrv_optiswitch
  • netapp_cdot
  • netscaler
  • ovs_linux
  • paloalto_panos
  • pluribus
  • quanta_mesh
  • rad_etx
  • ruckus_fastiron
  • ubiquiti_edge
  • ubiquiti_edgeswitch
  • vyatta_vyos
  • vyos

プラットフォーム名の変換

なお、私が試した限り netmiko にないプラットフォーム名 ios でも netmiko を利用できました。(本来は cisco_ios

plugins/connections/netmiko.py にある以下の変換表によって変換されて利用できたようです。

napalm_to_netmiko_map = {
    "ios": "cisco_ios",
    "nxos": "cisco_nxos",
    "eos": "arista_eos",
    "junos": "juniper_junos",
    "iosxr": "cisco_xr",
}

[Ansible] AWX から Cisco IOS と Juniper Junos を操作する

■ はじめに

Ansible には GUI 付きの Ansible Tower という製品があります。そのアップストリーム版 OSS にあたるものとして AWX があります。

f:id:akira6592:20181218002414p:plain
AWXのダッシュボード画面

この記事では、AWX から IOS と Junos の機器に対して簡単な操作(show versionの実行と表示)を試したときの手順をまとめます。

ポイントは以下のとおりです。

  • コネクションプラグインとして local ではなく、IOS には network_cli を、Junos には netconf を利用
  • Credential Type として、Network ではなく、Machine を利用

以前は、local とコネクションプラグインと、Network Credential という、ネットワーク機器固有方法でした。最近のバージョンで、サーバーと同じように Credential Tpye に Machine が利用できるようになりました。詳細は「RED HAT ANSIBLE NETWORK AUTOMATION のアップデート情報(翻訳)」の「ネットワーク機器のための認証情報の管理」をご参照ください。

先日の Ansibleもくもく会 2018.12 ネットワーク編 (Ansible Tower 3.3.x を利用)で、Network Credential と network_cliコネクションプラグイン という組み合わせで Playbook がうまく動かなかったので、正しいと思う組み合わせで試してみたくなり、やってみました。

  • 環境
    • AWX 2.1.2
    • Ansible 2.7.4
    • ブラウザ言語設定: Chrome 英語
    • Centos 7.5


■ インストール

Software Design 2018年12月号 の Ansible 特集にあった AWX の章を参考にしました。

誌面では、執筆時の最新版 2.0.1 のインストールになっていますが、発売後筆者から

というコメントがありました。

もうちょっといけるかな、という気持ちで今回は 2.1.2 をインストールしました。


■ 準備

各種設定をしていきます。

Organizations

項目
NAME test_org

Projects

項目
NAME network_project
ORGANIZATION test_org
SCM TYPE Git
SCM URL https://github.com/akira6592/tower-samples.git

(上記リポジトリは作業用に作成したため、変更、削除する可能性があります)

Inventories

DTAILS

項目
NAME network_inventory
Organization test_org

GROUPS

ios

項目
NAME ios
VARIABLES (下記)
  • VARIABLES
---
ansible_network_os: ios
ansible_connection: network_cli     # ポイント

junos

項目
NAME junos
VARIABLES (下記)
  • VARIABLES
---
ansible_network_os: junos
ansible_connection: netconf     # ポイント

HOSTS

ios1

項目
NAME ios1
VARIABLES (下記)
GROUPS ios
  • VARIABLES
---
ansible_host: 172.16.0.2

vsrx1

項目
NAME vsrx1
VARIABLES (下記)
GROUPS junos
  • VARIABLES
---
ansible_host: 172.16.0.1

Credentials

ios_credential

項目
NAME ios_credential
ORGANIZATION test_org
CREDENTIOAL TYPE Machine ポイント
USERNAME iosuser
PASSWORD iospass9999

ユーザーに特権がなく、かつ特権が必要な操作を実行したい場合は、PRIVILEGE ESCALATION METHODenable を、PRIVILEGE ESCALATION PASSWORD に 機器側にenable secret で指定した特権パスワードを指定すればよさそうです。 それぞれ、変数の指定でいうと、ansible_become_method: enable と、ansible_become_pass: hogehoge のことでしょう。

junoos_credential

項目
NAME ios_credential
ORGANIZATION test_org
CREDENTIOAL TYPE Machine ポイント
USERNAME junos_user
PASSWORD junospass9999

TEMPLATES

ios_show_version

項目
NAME ios_show_version
INVENTORY network_inventory
PROJECT network_project
PLAYBOOK ios_command_test.yml(内容は下記)
CREDENTIAL ios_credential
  • ios_command_test.yml
- hosts: ios
  gather_facts: no

  tasks:
    - name: show command test
      ios_command:
        commands:
          - show version
      register: result

    - name: debug output
      debug:
        msg: "{{ result.stdout_lines[0] }}"

Credential で指定したユーザーに特権がなく、かつ特権が必要なコマンド(show running-configなど)を実行する場合は、Enable Privilege Escalation にチェックを入れるとできそうです。変数の指定でいうと ansible_become: yes のことでしょう。

junos_show_version

項目
NAME junos_show_version
INVENTORY network_inventory
PROJECT network_project
PLAYBOOK junos_command_test.yml (内容は下記)
CREDENTIAL junos_credential
  • junos_command_test.yml
- hosts: junos
  gather_facts: no

  tasks:
    - name: show command test
      junos_command:
        commands:
          - show version
      register: result

    - name: debug output
      debug:
        msg: "{{ result.stdout_lines[0] }}"


■ 実行

IOS の show version

ジョブテンプレートを実行します。

f:id:akira6592:20181217221358p:plain
実行

f:id:akira6592:20181217221424p:plain
実行結果画面

  • ログ詳細
SSH password: 
PLAY [ios] *********************************************************************
TASK [show command test] *******************************************************
ok: [ios1]
TASK [debug output] ************************************************************
ok: [ios1] => {
    "msg": [
        "Cisco IOS XE Software, Version 16.08.01", 
        "Cisco IOS Software [Fuji], Virtual XE Software (X86_64_LINUX_IOSD-UNIVERSALK9-M), Version 16.8.1, RELEASE SOFTWARE (fc3)", 
        "Technical Support: http://www.cisco.com/techsupport", 
        "Copyright (c) 1986-2018 by Cisco Systems, Inc.", 
        "Compiled Tue 27-Mar-18 13:32 by mcpre", 
        "", 
        "", 
        "Cisco IOS-XE software, Copyright (c) 2005-2018 by cisco Systems, Inc.", 
        "All rights reserved.  Certain components of Cisco IOS-XE software are", 
        "licensed under the GNU General Public License (\"GPL\") Version 2.0.  The", 
        "software code licensed under GPL Version 2.0 is free software that comes", 
        "with ABSOLUTELY NO WARRANTY.  You can redistribute and/or modify such", 
        "GPL code …
PLAY RECAP *********************************************************************
ios1                       : ok=2    changed=0    unreachable=0    failed=0  

Junos の show version

ジョブテンプレートを実行します。

f:id:akira6592:20181217221451p:plain
実行

f:id:akira6592:20181217221512p:plain
実行結果画面

  • ログ詳細
SSH password: 
PLAY [junos] *******************************************************************
TASK [show command test] *******************************************************
ok: [vsrx1]
TASK [debug output] ************************************************************
ok: [vsrx1] => {
    "msg": [
        "Hostname: vsrx1", 
        "Model: firefly-perimeter", 
        "JUNOS Software Release [12.1X47-D15.4]"
    ]
}
PLAY RECAP *********************************************************************
vsrx1                      : ok=2    changed=0    unreachable=0    failed=0   


■ まとめ

AWX で Cisco IOS と Juniper Junos の show version コマンドを実行し、画面に表示するところまでを確認できました。