てくなべ (tekunabe)

ansible / network / automation

[Ansible] ロール呼び出しに指定したタグはロールの各タスクに継承される

問題

突然ですが、問題です。

以下のようにタグのついた Playbook、role があるとします。

  • tag_playbook.yml
- hosts: localhost
  gather_facts: no

  roles:
    - role: testrole
      tags:
        - tag_parent
  • roles/testrole/tasks/main.yml
- name: task1
  debug:
    msg: "task1"
  tags:
    - tag_parent
    - tag_child1

- name: task2
  debug:
    msg: "task2"
  tags:
    - tag_child2

ansible-plabook コマンドで-t tag_parent を指定して Playbook を実行した場合

$ ansible-playbook -i localhost, tag_playbook.yml  -t tag_parent

どのタスクが実行されるでしょうか。

答えはこちら


























答え

答えは、task1task2 です。(本記事のタイトル通りの挙動です)

  • 実行ログ
$ ansible-playbook -i localhost, tag_playbook.yml  -t tag_parent

PLAY [localhost] ************************************************************************

TASK [testrole : task1] *****************************************************************
ok: [localhost] => {
    "msg": "task1"
}

TASK [testrole : task2] *****************************************************************
ok: [localhost] => {
    "msg": "task2"
}

PLAY RECAP ******************************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   


解説

tag_playbook.yml では、role を呼び出す指定に、タグ tag_parent を付けています。この場合、呼ばれたロールの 各タスク にもタグ tag_parent が付きます。継承されるようなイメージです。

そのため、呼ばれた role の タスク task2 自身には、タグ tag_parent は付いていなくても実行される結果となります。

https://docs.ansible.com/ansible/latest/user_guide/playbooks_tags.html#tag-inheritance

Adding tags: to a play, or to statically imported tasks and roles, adds those tags to all of the contained tasks. This is referred to as tag inheritance.

タスクへのタグの付き方は、ansible-playbook コマンドの --list-tasks オプションを利用することで確認できます。

$ ansible-playbook -i localhost, tag_playbook.yml --list-tasks

playbook: tag_playbook.yml

  play #1 (localhost): localhost        TAGS: []
    tasks:
      testrole : task1  TAGS: [tag_child1, tag_parent]
      testrole : task2  TAGS: [tag_child2, tag_parent]

上記結果により、role 呼び出し側のタグ tag_parent が継承されて task2 にもつくことが確認できます。

なお、task1 のみの実行を意図して、ansible-playbook コマンドに -t tag_parent を指定するのであれば、ロール呼び出し側 では tag_parent を指定しないのが正しいです。


まとめ

タグの挙動はうっかり忘れがちなものもあると思いますので、ために公式ドキュメントを見返すのが良さそうです。

docs.ansible.com

※role や import* ではなく、include* のよう動的読み込みの場合は継承されないようです。

Tag inheritance is not applicable to dynamic inclusions such as include_role and include_tasks.

Cumulus Linux の仮想アプライアンス「Cumulus VX」を Vagrant で構築する

■ はじめに

つい最近、ホワイトボックススイッチ向けのネットワークOSであるCumulus Linux に、仮想アプライアンスCumulus VX」があることを知りました。

この記事では、Vagrant と Virtual Box を利用し、4 台の Cumulus VX を構築、接続、設定して、疎通確認するまでの手順をまとめます。


■ 想定構成

ネットワーク構成

以下のような 4 台(Cumulus VX 3.7.10)の構成を構築します。

f:id:akira6592:20191117192624p:plain
Cumulus VX 4台構成

なお、図には示していませんが、各スイッチは管理用ポートとして eth0 を持ち、eth0 からホストOSを経由してインターネット側にも抜けられます。

※もし最小構成(1台のみ、かつ管理ポートのみ)でよければ、今回紹介する手順よりも簡単な、以下の手順で構築できます。

# 最小構成の場合の手順
vagrant init CumulusCommunity/cumulus-vx   # Vagrantfile の作成
vagrant up    # 起動
vagrant ssh   # ログイン

ホストOS 環境


■ Vagrantfile の作成と起動

仮想マシンを定義する Vagrantfile を作成し、それを元にして起動します。

Vagrantfile の作成

まず、 Vagrantfile を作成します。

  • ポイント
    • 各スイッチのポート swp1swp2 を作成し、provision を利用して IP アドレスを設定するようにしています。
    • forwarded_port は、他の環境と重複しないようにします。
    • 最小メモリ要件は、こちらのページによると 512MB とのことなので、 512 MBにしています。
Vagrant.configure(2) do |config|

  config.vbguest.auto_update = false

  config.vm.provider "virtualbox" do |vb|
    vb.memory = 512
  end

  # spine1
  config.vm.define "spine1" do |device|
    device.vm.box = "CumulusCommunity/cumulus-vx"
    device.vm.hostname = "spine1" 
    device.vm.network "private_network", virtualbox__intnet: "nw101", auto_config: false
    device.vm.network "private_network", virtualbox__intnet: "nw102", auto_config: false

    device.vm.network "forwarded_port", id: "ssh", guest: 22, host: 2211

    device.vm.provision :shell, inline: <<-SHELL
      sudo net add interface swp1 ip address 10.0.101.1/30
      sudo net add interface swp2 ip address 10.0.102.1/30
      sudo net commit
    SHELL
  end
  
  # spine2
  config.vm.define "spine2" do |device|
    device.vm.box = "CumulusCommunity/cumulus-vx"
    device.vm.hostname = "spine2" 
    device.vm.network "private_network", virtualbox__intnet: "nw201", auto_config: false
    device.vm.network "private_network", virtualbox__intnet: "nw202", auto_config: false
    
    device.vm.network "forwarded_port", id: "ssh", guest: 22, host: 2212
    
    device.vm.provision :shell, inline: <<-SHELL
      sudo net add interface swp1 ip address 10.0.201.1/30
      sudo net add interface swp2 ip address 10.0.202.1/30
      sudo net commit
    SHELL
  end

  # leaf1
  config.vm.define "leaf1" do |device|
    device.vm.box = "CumulusCommunity/cumulus-vx"
    device.vm.hostname = "leaf1" 
    device.vm.network "private_network", virtualbox__intnet: "nw101", auto_config: false
    device.vm.network "private_network", virtualbox__intnet: "nw201", auto_config: false

    device.vm.network "forwarded_port", id: "ssh", guest: 22, host: 2221

    device.vm.provision :shell, inline: <<-SHELL
      sudo net add interface swp1 ip address 10.0.101.2/30
      sudo net add interface swp2 ip address 10.0.201.2/30
      sudo net commit
    SHELL
  end

  # leaf2
  config.vm.define "leaf2" do |device|
    device.vm.box = "CumulusCommunity/cumulus-vx"
    device.vm.hostname = "leaf2" 
    device.vm.network "private_network", virtualbox__intnet: "nw102", auto_config: false
    device.vm.network "private_network", virtualbox__intnet: "nw202", auto_config: false
    device.vm.network "forwarded_port", id: "ssh", guest: 22, host: 2222

    device.vm.provision :shell, inline: <<-SHELL
      sudo net add interface swp1 ip address 10.0.102.2/30
      sudo net add interface swp2 ip address 10.0.202.2/30
      sudo net commit
    SHELL
  end

end

vagrant up で起動

先ほど作成した Vagrantfile があるでディレクトリで vagrant up コマンドを実行し、仮想マシンを起動します。初回は、イメージのダウンロードから始まるため、相応の時間がかかります。

$ vagrant up
Bringing machine 'spine1' up with 'virtualbox' provider...
Bringing machine 'spine2' up with 'virtualbox' provider...
Bringing machine 'leaf1' up with 'virtualbox' provider...
Bringing machine 'leaf2' up with 'virtualbox' provider...
==> spine1: Box 'CumulusCommunity/cumulus-vx' could not be found. Attempting to find and install...
    spine1: Box Provider: virtualbox
    spine1: Box Version: >= 0
==> spine1: Loading metadata for box 'CumulusCommunity/cumulus-vx'
    spine1: URL: https://vagrantcloud.com/CumulusCommunity/cumulus-vx
==> spine1: Adding box 'CumulusCommunity/cumulus-vx' (v3.7.10) for provider: virtualbox
    spine1: Downloading: https://vagrantcloud.com/CumulusCommunity/boxes/cumulus-vx/versions/3.7.10/providers/virtualbox.box

...(略)...

    leaf2: User  Timestamp                   Command
    leaf2: ----  --------------------------  -----------------------------------------------
    leaf2: root  2019-11-17 09:21:38.336778  net add interface swp1 ip address 10.0.201.2/30
    leaf2: root  2019-11-17 09:21:38.372146  net add interface swp2 ip address 10.0.202.2/30
$

正常に起動ができたことを vagrant status コマンドで確認します。

$ vagrant status
Current machine states:

spine1                    running (virtualbox)
spine2                    running (virtualbox)
leaf1                     running (virtualbox)
leaf2                     running (virtualbox)

すべてが running であれば正常に起動していることを示しています。


■ ログインと状態・疎通確認

ログイン

ログインには大きく分けて 2の方法があります。

方法1: vagrant ssh コマンドによるログイン

1つ目は、 vagrant ssh 対象マシン名 コマンドによるログインです。vagrant で構築した環境ならではの方法です。ユーザーや下記の情報は .vagrant ディレクトリ配下の情報を自動で利用するため、特に指定は不要です。

例えば、leaf1 にログインする場合は、Vagrantfile があるでディレクトリで以下のコマンドを実行します。

$ vagrant ssh leaf1

Welcome to Cumulus VX (TM)

Cumulus VX (TM) is a community supported virtual appliance designed for
experiencing, testing and prototyping Cumulus Networks' latest technology.
For any questions or technical support, visit our community site at:
http://community.cumulusnetworks.com

The registered trademark Linux (R) is used pursuant to a sublicense from LMI,
the exclusive licensee of Linus Torvalds, owner of the mark on a world-wide
basis.
vagrant@leaf1:~$ 

上記のような表示になれば、無事にログインできたことを示します。

方法2: ssh コマンドによるログイン

2つ目は、通常通り ssh コマンド(またはターミナルソフトなど)によるログインです。 ログインには以下の接続情報が必要です。(ユーザー1、2はどちらでもOK、お好みで)

接続情報
ホスト localhost
ポート (Vagrantfile で指定したポートフォワーディング用のポート)
ユーザー名1 cumulus
パスワード1 CumulusLinux! (デフォルト)
ユーザー名2 vagrant
パスワード2 vagrant (デフォルト)

ポートフォワーディング用のポート(Vagrantfile 内で指定)は以下のとおりです。

マシン名 ポート
spine1 2211
spine2 2212
leaf1 2221
leaf2 2222

例えば、leaf1 にログインする場合は、Vagrantfile があるでディレクトリで以下のコマンドを実行します。

$ ssh cumulus@localhost -p 2211
cumulus@localhost's password:   ( CumulusLinux! を入力)

Welcome to Cumulus VX (TM)

Cumulus VX (TM) is a community supported virtual appliance designed for
experiencing, testing and prototyping Cumulus Networks' latest technology.
For any questions or technical support, visit our community site at:
http://community.cumulusnetworks.com

The registered trademark Linux (R) is used pursuant to a sublicense from LMI,
the exclusive licensee of Linus Torvalds, owner of the mark on a world-wide
basis.
cumulus@spine1:~$ 

上記のような表示になれば、無事にログインできたことを示します。

状態・疎通確認

ログインができたら、簡単な状態確認をしてみます。

まずは spine1 にて。

  • バージョンの確認
vagrant@spine1:~$ sudo net show version 
NCLU_VERSION=1.0-cl3u30
DISTRIB_ID="Cumulus Linux"
DISTRIB_RELEASE=3.7.10
DISTRIB_DESCRIPTION="Cumulus Linux 3.7.10"
  • インターフェースの確認
vagrant@spine1:~$ sudo net show interface 
State  Name  Spd  MTU    Mode          LLDP            Summary
-----  ----  ---  -----  ------------  --------------  ----------------------
UP     lo    N/A  65536  Loopback                      IP: 127.0.0.1/8
       lo                                              IP: ::1/128
UP     eth0  1G   1500   Mgmt                          IP: 10.0.2.15/24(DHCP)
UP     swp1  1G   1500   Interface/L3  cumulus (swp1)  IP: 10.0.101.1/30
UP     swp2  1G   1500   Interface/L3  cumulus (swp1)  IP: 10.0.102.1/30
vagrant@spine1:~$ ping 10.0.101.2 -c 2
PING 10.0.101.2 (10.0.101.2) 56(84) bytes of data.
64 bytes from 10.0.101.2: icmp_seq=1 ttl=64 time=0.517 ms
64 bytes from 10.0.101.2: icmp_seq=2 ttl=64 time=0.409 ms

--- 10.0.101.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 0.409/0.463/0.517/0.054 ms
vagrant@spine1:~$ ping 10.0.102.2 -c 2
PING 10.0.102.2 (10.0.102.2) 56(84) bytes of data.
64 bytes from 10.0.102.2: icmp_seq=1 ttl=64 time=0.588 ms
64 bytes from 10.0.102.2: icmp_seq=2 ttl=64 time=0.726 ms

--- 10.0.102.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 0.588/0.657/0.726/0.069 ms

spine2 とは直接接続していなく、ルートもないため未到達)

つづいて spine2 にて。

  • インターフェースの確認
vagrant@spine2:~$ sudo net show interface 
State  Name  Spd  MTU    Mode          LLDP            Summary
-----  ----  ---  -----  ------------  --------------  ----------------------
UP     lo    N/A  65536  Loopback                      IP: 127.0.0.1/8
       lo                                              IP: ::1/128
UP     eth0  1G   1500   Mgmt                          IP: 10.0.2.15/24(DHCP)
UP     swp1  1G   1500   Interface/L3  cumulus (swp2)  IP: 10.0.201.1/30
UP     swp2  1G   1500   Interface/L3  cumulus (swp2)  IP: 10.0.202.1/30
vagrant@spine2:~$ ping 10.0.201.2 -c 2
PING 10.0.201.2 (10.0.201.2) 56(84) bytes of data.
64 bytes from 10.0.201.2: icmp_seq=1 ttl=64 time=0.409 ms
64 bytes from 10.0.201.2: icmp_seq=2 ttl=64 time=0.344 ms

--- 10.0.201.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 0.344/0.376/0.409/0.037 ms
vagrant@spine2:~$ ping 10.0.202.2 -c 2
PING 10.0.202.2 (10.0.202.2) 56(84) bytes of data.
64 bytes from 10.0.202.2: icmp_seq=1 ttl=64 time=1.08 ms
64 bytes from 10.0.202.2: icmp_seq=2 ttl=64 time=0.615 ms

--- 10.0.202.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 0.615/0.850/1.086/0.237 ms

Cumulus に触るのは今回が初めてなので、あまり大した確認ができていませんが・・

leaf1leaf2 での確認は省略します。


■ まとめ

この記事では、Vagrant と Virtual Box を利用し、4 台の Cumulus VX を構築する手順をまとめました。

ホワイトボックススイッチは、なかなか遠い存在のように思いっていましたが、このように手軽に検証環境を準備できるのとはとてもありがたたいと思いました。

参考

cumulusnetworks.com

docs.cumulusnetworks.com

docs.cumulusnetworks.com

www.apresiatac.jp

[Ansible] Ansible Tower / AWX のワークフロー定義を YAML で表示する(tower-cli編)

はじめに

Ansible Tower / AWX では、ワークフロービジュアライザーという画面で、ワークフローを可視化できます。

f:id:akira6592:20191114225342p:plain
ワークフローの定義

ビジュアル的に可視化されていると直感的で分かりやすいです。一方で、複数のワークフロー定義を比較したいなどの場合、何かしらのフォーマットのテキストファイルのほうが都合が良いのではないでしょうか。

tower-cli というコマンドツールを利用することで、YAML で表示できます。

この記事では、簡単なサンプルを元にワークフローの定義を tower-cli を使って YAML にする方法をご紹介します。

  • 環境
    • AWX 7.0.0
    • Tower CLI 3.3.7

準備

インストール

tower-cli をインストールしていない場合は以下のコマンドでインストールします。

$ pip install ansible-tower-cli 

設定

接続先を設定をします。

$ tower-cli config host https://[towerかAWXのアドレス]/
$ tower-cli config user [ユーザー名]
$ tower-cli config password [パスワード]
$ tower-cli config verify_ssl false      # 必要に応じて


定義の表示

サンプル1

以下のワークフローテンプレート testwf1YAMLで表示します。

f:id:akira6592:20191114225342p:plain
testfw1のワークフローの定義

tower-cli で以下のコマンドを実行します。

$ tower-cli workflow schema testwf1
- id: 91
  job_template: 17
  success_nodes:
  - id: 92
    job_template: 18

id: はワークフローノード固有に振られるIDです。同じIDジョブテンプレートを別途配置すると別のIDが振られ、区別されます。

なお、-v オプションを付けると、API を叩く様子が確認できます。

$ tower-cli workflow schema testwf1 -v
*** DETAILS: The wfjt field is given as a name; looking it up. ****************
*** DETAILS: Getting the record. **********************************************
GET https://tower/api/v2/workflow_job_templates/
Params: [('name', 'testwf1')]

*** DETAILS: Getting records. *************************************************
GET https://tower/api/v2/workflow_job_template_nodes/
Params: [('workflow_job_template', 16)]

- id: 91
  job_template: 17
  success_nodes:
  - id: 92
    job_template: 18

ここでは、testwf1 というワークフローテンプレート名を指定しましたが、IDでも大丈夫です。 IDはワークフローテンプレートの設定画面を Web UI で開いたときの URL で確認できます。(以下の例の場合 16

https://[towerかAWXのアドレス]#/templates/workflow_job_template/16?(略)

サンプル2

以下のワークフローテンプレート testwf2YAMLで表示します。さきほどより少しノードが増えています。

f:id:akira6592:20191114231537p:plain
testfw2のワークフロー定義

tower-cli で以下のコマンドを実行します。

$ tower-cli workflow schema testwf2
- id: 93
  job_template: 17
  success_nodes:
  - id: 94
    job_template: 18
    success_nodes:
    - id: 95
      job_template: 19


まとめ

ワークフローの定義を tower-cli を使って YAML ファイルにする方法をご紹介しました。なにかしらのテキストフォーマットで確認したいときに、参考にしていただければと思います。

補足

tower-cli のリポジトリによると、本ツールは段階的に廃止され、後継は awx コマンドのようです。

参考

tower-cli/WORKFLOWS.rst at master · ansible/tower-cli · GitHub

[Ansible] Ansible で Ansible Tower / AWX のワークフローを作成する

■ はじめに

Ansible には Ansible Tower の各オブジェクトを管理するモジュールがあります。

ワークフローを管理するモジュールは tower_workflow_template です。

  • 環境
    • Ansible 2.9.0
    • AWX 7.0.0


■ 環境の準備

Ansible 側に ansible-tower-cli が必要なのでインストールします。

(venv)$ pip install ansible-tower-cli

加えて、ansible-tower-cli をインストールした python の環境のインタープリタを変数 ansible_python_interpreter にどこかで仕込んでおきます。

ansible_python_interpreter: /Users/akira/envs/venvs/a2900/bin/python¥¥

これを忘れると、 tower_workflow_template モジュール実行時に、Failed to import the required Python library (ansible-tower-cli) on xxx というエラーが発生し、「インストールしたはずなのにされてないと言われる」という状況になってしまいます。

Ansible Tower / AWX 側は特別な準備は必要ありません。

tower_workflow_template モジュールの基本

tower_workflow_template モジュールの主なオプションは以下のとおりです。

オプション名 概要
tower_host Ansible Tower / AWX のホスト名
tower_username Ansible Tower / AWX ログインユーザー名
tower_password Ansible Tower / AWX ログインパスワード
validate_certs SSL証明書検証の有無
organization ワークフローが所属する組織
name 対象のワークフローの名前
schema ワークフロー定義の schema ファイル(後述)

接続情報系のオプションは、他の tower_* モジュールと共通です。また、タスクのオプションで接続情報系のオプションを指定する以外にも、指定方法はあるようです。その他のぷしょん含め、詳細は tower_workflow_template モジュールのドキュメントを参照してください。


■ schem について

tower_workflow_template モジュールの一番のキモが schema ファイルです。

基本書式

schema ファイルは、YAML または JSON で ワークフローの定義をするファイルです。 YAMLの場合は、以下のような書式です。

- ノード種別: ノード名
  条件1:
    - ノード種別: ノード名
      条件1:
        - ノード種別: ノード名
        - ノード種別: ノード名
  条件2:
    - ノード種別: ノード名

ノード種別

基本書式で示した「ノード種別」には以下のような指定ができます。

GUI 上の名称 schema 上の名称
ジョブテンプレート job_template
ワークフローテンプレート workflow
プロジェクトの同期 project
インベントリーの動機 inventory_source

例えば jt1 という名前のジョブテンプレートを定義する場合は、

job_template: jt1

と指定します。

試した限り、ノード名は「名前」でも「ID」でも可能でした。

条件

基本書式で示した「条件」には以下のような指定ができます。

GUI 上の名称 schema 上の名称
常時 always
成功時 success
障害発生時 failure

例えば、ジョブテンプレート jt1 の実行が正常時に、ジョブテンプレート jt2 を実行したい場合は、

- job_template: jt1
  success:
    - job_template: jt2

と指定します。

■ サンプルと実行結果の確認

Playbook

以下の Playbook を利用します。

- hosts: tower
  gather_facts: no
  connection: local

  vars:
    tower_user: userxxxxx
    tower_password: passxxxxx
    ansible_python_interpreter: /Users/akira/envs/venvs/a2900/bin/python 
    # ^ ansible-tower-cli をインストールした環境の python を指定
    # ここでなくてもインベントリファイルなどで指定しても OK

  tasks:
    - name: set wf
      tower_workflow_template:
        tower_host: "{{ ansible_host }}"
        tower_username: "{{ tower_user }}"
        tower_password: "{{ tower_password }}"
        validate_certs: no
        name: testwf
        schema: "{{ lookup('file', 'schema.yml') }}"

各 schema ファイルと実行結果

schema オプションで指定すた、schema.aml は以下の2パターン試して、それぞれ実行結果を載せます。

1: 簡単な schema

ジョブテンプレート jt1 の実行が正常時に、ジョブテンプレート jt2 を実行する、という簡単なワークフローを定義する shcema です。

- job_template: jt1
  success:
    - job_template: jt2

この schema を利用した Playbook を実行します。

ワークフローテンプレートの定義が作成されました。

f:id:akira6592:20191114084934p:plain
ワークフローテンプレートが作成された

ワークフローは以下のようになりました。

f:id:akira6592:20191114085054p:plain
簡単なワークフロー

2: すこし複雑な schema

様々なノード種別や条件を含めたワークフローを定義する schema です。

- job_template: jt1
  success:
    - project: testpj
      always:
        - job_template: jt4
        - job_template: jt5
- job_template: jt2
  success: 
    - job_template: jt3
  failure:
    - job_template: jt6

この schema を利用した Playbook を実行します。

ワークフローは以下のようになりました。

f:id:akira6592:20191114090145p:plain
すこし複雑なワークフロー

※ 本当は inventory_source も試したかったのですが、あるはずの インベントリーを指定しても tower_cli.exceptions.NotFound: The requested object could not be found. というエラーになってしまいました。Web GUI 上でも対象のインベントリーを選択できなかったので、なにかが間違っているのかもしれないので、エラーが解消したら更新します。。


■ まとめ

tower_workflow_template モジュールを利用して、ワークフローを作成する Playbook をご紹介しました。

schme ファイルの書き方は多少覚える必要はありますが、作成していワークフローが多くて GUI 操作がつらいときには便利そうです、

もちろん、Ansible 以外でも、tower-cliawx-cli のようなコマンドラインツールでも良いかと思います。

参考

tower-cli/WORKFLOWS.rst at master · ansible/tower-cli · GitHub tower-cli/docs/source/cli_ref/examples/data at master · ansible/tower-cli · GitHub

おまけ

複数ノードが一つに合流するようなワークフローの定義は今のところできませんでした。

よこち(yokochi) @ Ansible実践ガイド 第3版 on Twitter: "tower_workflow_template モジュールではこういう合流定義できないのかな・・… "

[Ansible] ネットワーク機器に接続する条件はバージョンやコネクションブラグインによって異なる

はじめに

Ansible では、ネットワークモジュール向けに主に以下の専用コネクションプラグインが用意されています(組み合わせはこちら)。

Ansible のバージョンや、利用するコネクションプラグインによって、ネットワーク機器に接続する条件が異なります。 例えば、file モジュールはネットワーク機器に接続する必要はありませんが、実際の動作としては、接続する場合としない場合があります。

こちらの PR によって、Ansible 2.8 と 2.9 で挙動に差分が入りました。

この挙動の差分によって何が気になるかというと、

  • Ansible をバージョンアップしたら、接続エラーが出るタイミングが変わった
  • コネクションプラグインを変更したら、接続エラーが出るタイミングが変わった

といった場合に、原因に気づきにくいのではないかという点です。公式ドキュメントや CHANGELOG を確認しても、情報が見つかりません。

この記事では、Ansible 2.8 系と 2.9 系でそれぞれ実際に確認した確認した結果をまとめます。

  • 確認環境
    • Ansible 2.8.6、2.9.0


確認用 Playbook

以下の Playbook で確認します。

1つめの file モジュールのタスクは、本来はネットワーク機器に接続する必要はありません。 2つめの *_command モジュールのタスクは、接続する必要があります。

- hosts: all
  gather_facts: no

  tasks:
    - name: create directory
      file:
        state: directory
        path: logs
      run_once: yes

    - name: show version
      ios_command:    # 対象OSに合わせて変える
        commands:
          - show version
      register: result

この Playbook を、意図的に誤った認証情報で実行します。 これにより、もし file モジュールのタスクで、

  • エラーになったら、ネットワーク機器に接続しようとしている
  • エラーにならなかったら、ネットワーク機器に接続しない

ということが分かります。(もちろん他にも確認方法はあると思います)


確認結果

利用するコネクションプラグインやバージョンの組み合わせと、本来接続不要なモジュールでも接続するかどうかは、以下の結果になりました。

コネクションプラグイン Ansible 2.8 Ansible 2.9 確認した ansible_network_os
network_cli 接続する 接続しない ios
netconf 接続する 接続しない junos
httpapi 接続しない 接続しない eos


ping モジュールとの組み合わせは要注意

ネットワーク機器相手としては少しトリッキーですが、Ansible 2.8 までで network_cli か、netconfping モジュールの組み合わせで接続確認ができます。 Ansible 2.9 で同様のことをすると、必ず "ping": "pong" (成功) になってしまい、接続確認になりません。 内部的には、Ansible コントロールノード自身への ping モジュールの実行が成功したら OK という扱いになるためです。この点は注意が必要です。

なお、公式ドキュメントの「Network Debug and Troubleshooting Guide」では切り分けための接続確認として、ping モジュールではなく、eos_command モジュール(ここでは Arista EOS向けの解説)を利用して、? コマンドを実行する方法を掲載しています。この方法であれば、Ansible 2.8 でも 2.9 でも正しく接続確認できます。


まとめ

Ansible のバージョンや、利用するコネクションプラグインによって、ネットワーク機器に接続するタイミングが異なることを確認しました。

Ansible 2.9 では、network_clinetconfhttpapi いずれのでも、実際にネットワーク機器に接続する必要があるまで接続しない仕様でした。

[Ansible] F5 BIG-IP への接続確認には ping モジュールではなく bigip_* を利用するしかないのではという話

はじめに

先日開催された Ansibleもくもく会 (サーバ編 & NW編)2019.11では、ネットワーク編の環境として F5 BIG-IP の環境を割り当ていただきました。

書いていく Playbook は、こんな感じものでした(引用元)。

---
- name: GRAB F5 FACTS
  hosts: f5
  connection: local
  gather_facts: no


  tasks:

    - name: COLLECT BIG-IP FACTS
      bigip_device_facts:
        gather_subset:
         - system-info
        server: "{{private_ip}}"
        user: "{{ansible_user}}"
        password: "{{ansible_ssh_pass}}"
        server_port: 8443
        validate_certs: no
      register: device_facts

先だって、参加者から「ansible all -m ping を実行すると、f5のみ失敗するが、どのように確認すればよいか」という旨の質問がありました。

  • 発生するエラー
f5 | UNREACHABLE! => {
    "changed": false, 
    "msg": "Authentication or permission failure. In some cases, you may have been able to authenticate and did not have permissions on the target directory. Consider changing the remote tmp path in ansible.cfg to a path rooted in \"/tmp\". Failed command was: ( umask 77 && mkdir -p \"` echo ~/.ansible/tmp/ansible-tmp-1573597787.31-66002750839439 `\" && echo ansible-tmp-1573597787.31-66002750839439=\"` echo ~/.ansible/tmp/ansible-tmp-1573597787.31-66002750839439 `\" ), exited with result 1", 
    "unreachable": true
}

メンターとして参加させていただきましたが、当日は私としては答えがなかったのですが、考えた結果、bigip_* モジュールを利用するしかないのでは、となりましたので、その考えをまとめます。

  • 環境
    • Ansible 2.8.5

ping モジュールとネットワーク機器

Ansible における ping モジュールは ICMP による 疎通確認ではなく、Ansible が利用する接続方式(デフォルト SSH)での接続確認です。

そのため、もし Ansible から BIG-IP に HTTP API で接続して利用するのであれば、接続確認としても HTTP を利用するのが良いと考えています。そのため、そもそも ping モジュールは不向きなのではと思いました。

となるともう、bigip_* モジュールを利用して接続確認するしかないのでは、というのが私の考えです。

なお、公式ドキュメントの「Network Debug and Troubleshooting Guide」では切り分けための接続確認として、ping モジュールではなく、eos_command モジュール(ここでは Arista EOS向けの解説)を利用して、? コマンドを実行する方法を掲載しています。この方法は network_cli コネクションプラグインに対応している OS (IOS、EOS、Junos など)向けであって、BIG-IP モジュールでは利用できません

ansible コマンドと bigip モジュールを利用した接続確認

ここでは インベントリファイル hosts 内のグループ lb 内に BIG-IP ホスト f5 を定義しているものとしてます。

  • 接続確認コマンド(長い)
ansible -i hosts lb -m bigip_device_facts -a "gather_subset=system-info server=BIGPのアドレス user=ユーザー名 password=パスワード server_port=8443 validate_certs=no" -c local

やっていることは以下のとおりです。

  • bigip_device_facts モジュールを利用
    • 接続確認なので、設定変更しない当たり障りないモジュールを指定
    • 接続方式はデフォルトの restcli ではなく)
      • 利用したい接続方式に合わせる
    • gather_subset オプションで、戻り値が少ない system-info を指定
    • BIG-IP への接続ポートを 8443 に指定
    • 補足: Ansilbe 2.9 では bigip_device_info に名前変更されてます
  • -c local でコネクションプラグインに local を指定

これで、local コネクションプラグインを利用しつつ、BIG−IP に HTTP API で接続することになります。

以下の通り、fact が返ってこれば、接続成功です、

f5 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "system_info": {
        "base_mac_address": "0a:7f:96:21:a0:75", 
        "chassis_serial": "84a12dec-93f2-65f5-4eaf0ae97801", 
        "hardware_information": [
            {
                "model": "Intel(R) Xeon(R) CPU E5-2686 v4 @ 2.30GHz", 
                "name": "cpus", 
                "type": "base-board", 
                "versions": [
                    {
                        "name": "cpu stepping", 
                        "version": "1"
                    }, 
                    {
                        "name": "cpu sockets", 
                        "version": "1"
                    }, 
                    {
                        "name": "cpu MHz", 
                        "version": "2300.021"
                    }, 
                    {
                        "name": "cores", 
                        "version": "2  (physical:2)"
                    }, 
                    {
                        "name": "cache size", 
                        "version": "46080 KB"
                    }
                ]
            }
        ], 
        "marketing_name": "BIG-IP Virtual Edition", 
        "package_edition": "Point Release 7", 
        "package_version": "Build 0.0.1 - Tue May 15 15:26:30 PDT 2018", 
        "platform": "Z100", 
        "product_build": "0.0.1", 
        "product_build_date": "Tue May 15 15:26:30 PDT 2018", 
        "product_built": 180515152630, 
        "product_changelist": 2557198, 
        "product_code": "BIG-IP", 
        "product_jobid": 1012030, 
        "product_version": "13.1.0.7", 
        "time": {
            "day": 12, 
            "hour": 22, 
            "minute": 53, 
            "month": 11, 
            "second": 19, 
            "year": 2019
        }, 
        "uptime": 67290.0
    }
}

コマンドが長いですね。接続情報系のオプションを provider にまとめたり、変数化したりカスタマイズの余地はあるかとお思います。

もうPlaybook 書いたほうが良くないですか!? という思いが芽生えます。

[ACI] オブジェクトの階層構造を Web で確認できる「Object Store」

はじめに

以前の記事で、WebUI で開いているオブジェクトの DN (Distinguished Name) を調べる方法 をご紹介しました。

今回は、階層構造などを含めてもっと詳細に確認できる画面「Object Store」をご紹介します。


■ 画面の開き方

「Object Store」の呼び出し方には、大きく分けて 2 つあります。それぞれについて簡単に説明します。

APIC 管理画面で対象オブジェクトの右クリックから開く

確認したいオブジェクトを右クリックし、表示されたメニューの Open In Object Store Browser をクリックします。

f:id:akira6592:20191110150044p:plain:w300
右クリックから開く

APIC 管理画面と同じユーザー情報でログインします。(今回の環境では admin

f:id:akira6592:20191110150105p:plain:w400
ログイン

対象オブジェクトについての画面が表示されます。

f:id:akira6592:20191110150131p:plain:w400
オブジェクトの詳細画面

Object Store 画面を直接を開く

https://[APICアドレス]/visore.html

で画面を直接きます。

f:id:akira6592:20191110150105p:plain:w400
ログイン
APIC 管理画面と同じユーザー情報でログインします。(今回の環境では admin

トップ画面が開きます。

f:id:akira6592:20191110150314p:plain:w400
トップ画面


■ 基本操作

オブジェクトを検索する

Show Debug Info などで、対象の DN を予め調べておきます。

検索条件に指定し、検索を実行します。

f:id:akira6592:20191110150331p:plain:w400
検索の実行

結果が表示され、DN をはじめ、各プロパティが確認できます。

f:id:akira6592:20191110150356p:plain:w400
オブジェクトの詳細画面

親オブジェクト、子オブジェクトを表示する

dn のところで、親オブジェクト名をクリックすると親オブジェクトを、 > をクリックすると子オブジェクトを表示できます。

f:id:akira6592:20191110150428p:plain:w400
親子オブジェクト

ここでは、子オブジェクトを表示してみます。

Application Profile ap_test1 の子オブジェクトである EPG epg_test1epg_test2 の詳細情報が表示されます。

f:id:akira6592:20191110150525p:plain:w400
子オブジェクトの表示

API 上の表示を確認する

今開いているオブジェクトを API で市確認する場合の URL とその結果を知るには、 Show URL and response of last query をクリックします。

f:id:akira6592:20191110150753p:plain:w400
Show URL and response of last query

API URL とその実行結果が表示されます。

f:id:akira6592:20191110150825p:plain:w400
API URLと結果

まとめ

階層構造などを含めてもっと詳細に確認できる画面「Object Store」をご紹介しました。 検索や詳細の表示、親オブジェクトや子オブジェクトの確認ができました。

API を利用する場合、オブジェクトの階層を意識することがあるので「Object Store」は便利だと感じました。