てくなべ (tekunabe)

ansible / network automation / 学習メモ

[Ansible] ansible-lint で hosts ディレクティブに変数が含まれると発生するエラーの対処案2つ

はじめに

hosts: "{{ targets }}" のように、hosts に変数を利用していると、ansible-lint のチェックで変数未定義のエラーになってしまいます。

$ ansible-lint debug.yml 
WARNING  Listing 1 violation(s) that are fatal
syntax-check[specific]: The field 'hosts' has an invalid value, which includes an undefined variable. The error was: 'targets' is undefined. 'targets' is undefined
assert.yml:2:3


                  Rule Violation Summary                   
 count tag                    profile rule associated tags 
     1 syntax-check[specific] min     core, unskippable    

Failed: 1 failure(s), 0 warning(s) on 1 files.

これにひっかかると、他のチェックがされなくなるのでどうにかしたいところです。

かといって、このチェックは .config/ansible-lint.yml の設定の skip_list に指定してスキップすることはできません。

私が分かっている範囲では、これを回避するには2つの方法があります。

  • 検証環境
    • ansible-lint 6.22.2

対処案1: default フィルターを利用

ルール syntax-check の説明ページにもありますが、変数未定義時の代わりの値を指定する default フィルターを利用する方法です。これ自体はもともと Ansible でも利用できる機能です。

---
- name: Test play
  hosts: "{{ targets | default([]) }}"
  gather_facts: false
  connection: local

  tasks:
    - name: Debug
      ansible.builtin.debug:
        msg: Hello

こんな風にしておけば、変数未定義のエラーは起こらなくなります。

対処案2: ansible-lint としての extra_vars で定義しておく

対処案1では Playbook を修正する必要がありますが、修正したくない場合こちらの案が候補になります。

ansible-lint の設定ファイル内の extra_vars で変数を定義しておけばエラーは起こらなくなります。

  • .config/ansible.yml:
---
extra_vars:
  targets: []

Playbook は以下の通り。default フィルターは利用しません。

---
- name: Test play
  hosts: "{{ targets }}"
  gather_facts: false
  connection: local

  tasks:
    - name: Debug
      ansible.builtin.debug:
        msg: Hello

おわりに

設定ファイルが思いのほか気が利いてるので、一度目を通すと新しい発見があるかもしれません。

ansible.readthedocs.io

参考

関連 issue

github.com

[Ansible] 公式ドキュメントのあのページ、どこにいった?を探す

はじめに

コレクションというモジュール類の管理単位がだいぶ浸透してきてると思いますが、それに伴ってか、ドキュメント上にも変化が見られます。

もともとAnsible本体側にあったページがコレクション側に移動してたりします。

コレクション側に移動しているページ

一部ですが、コレクション側に移動しているクラウド・仮想化系ページの例をご紹介します。

分野 以前のページ 現在のページ(コレクション側)
AWS 以前のページ 現在のページ(コレクション側)
VMware 以前のページ 現在のページ(コレクション側)
VMware REST 以前のページ 現在のページ(コレクション側)

おわりに

あれどこいったかな?というときは、どのコレクションか見当がつくのであれば Collection Index から追ってみると見つかるかもしれません。

たとえば、community.general コレクショには、現状 2つのガイドがあります。結構詳しいです。各モジュールやプラグインのページで情報が足りないときに便利です。

docs.ansible.com

[TTP] スペース含めて値を取得する

はじめに

ネットワーク機器の show コマンドのパーサーとして TextFSM や TTP (Template Text Parser) を使い分けています。

個人的には TTP が直感的に使える一方で、ちょっとしたことでつまずくことがあります。

例えば今回紹介する、スペースを含めて値を取得する場合です。

何も考えずにやると・・

例えば以下のコンフィグがある場合、

interface GigabitEthernet0/0
 description kingyo ugui oikawa
 negotiation auto

なんとなくで、以下のテンプレートにすると

<group name="interfaces">
interface {{ interface }}
 description {{ description }}
</group>

以下の結果になります。description が拾えてません。マッチしていないためです。

[
    {
        "interfaces": {
            "interface": "GigabitEthernet0/0"
        }
    }
]

description kingyo のような値であれば単純なテンプレートで取得できるのですが。

| re(".+") を添える

re を使って、スペースでもマッチする正規表現を指定します。

<group name="interfaces">
interface {{ interface }}
 description {{ description | re(".+") }}
</group>

これで、スペース含めて取得できます。

[
    {
        "interfaces": {
            "description": "kingyo ugui oikawa",
            "interface": "GigabitEthernet0/0"
        }
    }
]

公式ドキュメントの例 の例を参考にしました。

(おまけ) ignore(".+") だと

<group name="interfaces">
interface {{ interface }}
 description {{ description }} {{ ignore(".+") }}
</group>

だと、以下のように、スペースで区切られた値の最初のところだけしか取得できません。

[
    {
        "interfaces": {
            "description": "kingyo",
            "interface": "GigabitEthernet0/0"
        }
    }
]

参考

zaki-hmkc.hatenablog.com

[Ansible] 組織内でのみ使うコレクションの名前空間「local」が公式ドキュメントに明示された

そもそもコレクションとは

Ansible は現在、モジュール類の管理はコレクションという単位でまとめられています。

このコレクションは「名前空間(namespace).コレクション名」という形式で識別されます。例えば、ansible.utislcisco.ios などです。

コレクションは Ansible Galaxy でインターネット上に公開されてるので、名前空間は一意であるあることが求められます。

組織内だけで利用するコレクション

ただ、Ansible Galaxy では公開せず、組織の中だけで使うコレクションもあるかと思います。

この場合、組織内で独自に名前空間を付けたとしても、その名前空間が第三者によって Ansible Galaxy に登録されるとトラブルの元です。

それを防ぐには、自らが Ansible Galaxy でその名前空間を予約しておくことが対策になります。

気軽に使える名前空間「local」

とはいえ「そこまでするほどでもないけど、とにかく組織内だけでコレクションの体裁を保つための名前空間があればいいなぁ」というときに有効なのが「local」です。

今まで、中身が空の名前空間としてあることはありましたが、最近ドキュメント上に用途が明示されました。

docs.ansible.com

The local namespace does not contain any collection on Ansible Galaxy, and the intention is that this will never change. You can use the local namespace for collections that are locally on your machine or locally in your git repositories, without having to fear collisions with actually existing collections on Ansible Galaxy.

Galaxy に公開せず、一意性を気にせずに組織内でコレクションの名前空間を使いたいときに便利です。

経緯

私が気になっていたことで、Forum で質問したら local の持ち主さんに回答いただき、ドキュメントに記載していただた、という流れです。

とても助かりました。

forum.ansible.com

[Ansible] コレクションが置いてある場所を基準に分類してみる

はじめに

コレクションの分類の仕方にはいろいろな観点があります。

例えば、どこからそのコレクションを入手できるか、マネージドノードはどいういう特性か(サーバー、ネットワーク、クラウドなど)などです。

最近私の周りで少し話題になったので、この記事ではコレクションが置いてある場所を基準に、例とともに分類してみます。いずれも特定の組織内のみではなく、インターネット上に置いてあることが前提です。

歪な感じもしますが、図で示すと以下のケースがありえます。

分類

場所の説明

まず、置いてある場所についてそれぞれ説明します。

Ansible Galaxy にある

以下のサイトで公開されているコレクションを指します。様々なコレクションがあり、個人でもアップロードもできます。

Automation Hub にある

Red Hat Ansible Automation Platform のサービズ内のAutomation Hub で公開されているコレクションを指します。ざっくり、Ansible Galaxy の Red Hat 社提供版と捉えています。

What is included in Red Hat Ansible Automation Platform subscription? の言葉を 引用すると、以下のとおりです。

This hosted service is the official location to discover and download supported and certified Ansible Content Collections, included as part of your Ansible Automation Platform subscription.

Web UI としてはhttps://cloud.redhat.com からログインしてアクセスできます。

cloud.redhat.com

CLIansible-galaxy コマンドでコレクションをインストールする場合の参照先を Ansible Galaxy ではなく Automation Hub にするには設定変更が必要です。

Ansible Community Package にある

ansible-core に加えてコミュニティが選別したコレクションを同梱したパッケージに含まれるコレクションを指します。

pip でいうと pip install ansible で一緒にインストールされるコレクションたちです。

どのコレクションを含むかは、議論の上、以下のリポジトリで管理されています。

github.com

公式ドキュメントの Collection Indexで、含まれるコレクションを確認できます。

docs.ansible.com

「Ansible に対応モジュールがあるか?」を調べるときはまず Collection Indexを調べることが多いのではないでしょうか。

ここに含むかどうかは時々議論が発生し、新たにコレクションが含まれるようになったり、逆に外れたりもします。

各ケースの例

分類(再掲)

図で示した各ケースの説明をします。

[1] Ansible Galaxy のみにある

Ansible Galaxy にはあるけど、Ansible Community Package には選ばれていないし、Automation Hub にもないケースです。

例:

[2] Automation Hub のみにある

Automation Hub にはあるけど、Ansible Community Package には選ばれていないし、 Ansible Galaxy にもないケースです。

例:

[3] Ansible Galaxy とAnsible Community Package にある

Ansible Galaxy にはあるし、Ansible Community Package にも選ばれているけど、Automation Hub にはないケースです。

例:

[4] Ansible Galaxy と Automation Hub にある

Ansible Galaxy と Automation Hub にはあるけど、Ansible Community Package には選ばれていないケースです。

例:

[5] いずれにもある

Ansible Galaxy にも Automation Hub にもあるし、Ansible Community Package にも選ばれている。

例:

[Ansible] ロールの実行に必要な変数のチェック「だけ」する(ロールの処理自体はしない)

はじめに

以前の記事でもご紹介しましたが、ロールの実行に必要な変数をチェックする「Role argument validation」という機能があります。

tekunabe.hatenablog.jp

ロールの meta/argument_specs.yml というファイルに、どういう変数が必須か、型は何かなどを定義すると、Playbook からロールを呼ぶ際に、冒頭で変数のチェックをしてくれます。要件を満たさない場合はロールが実行されません。

ロールの実行と変数のチェックがセットであるため、ただ変数のチェックのみしたい(テスト目的など)場合は少々不都合です。

そこで利用できるのが、ansible.builtin.validate_argument_spec モジュールです。

この記事では簡単な検証をした結果をまとめます。

  • 検証環境
    • ansible-core 2.16.0

サンプル

roles ディレクトリ配下に myapp ロールを作成し、その中の meta/argument_specs.yml に以下のファイルを用意します。

myapp_intint で必須、myapp_strstr で任意、という定義です。

---
argument_specs:
  main:          # main.yml に対応
    short_description: The main entry point for the myapp role
    options:    #ここから変数の仕様定義
      myapp_int:
        type: "int"
        required: true
        description: "The integer value"

      myapp_str:
        type: "str"
        description: "The string value"

上記のファイルを利用し、変数のチェックをする Playbook は以下の通りです。

---
- name: Test Play
  hosts: localhost
  connection: local
  gather_facts: false

  tasks:
    - name: Verify variables by argument_specs.yml
      ansible.builtin.validate_argument_spec:
        argument_spec: "{{ (lookup('ansible.builtin.file', spec_file) | from_yaml)['argument_specs']['main']['options'] }}"
        provided_arguments: "{{ my_parameters }}"   # チェックさせたい変数
      vars:
        spec_file: roles/myapp/meta/argument_specs.yml
        my_parameters:    # チェックさせたい変数を束ねてる
          myapp_int: 12345   # チェックさせたい変数
          myapp_str: sakana  # チェックさせたい変数

argument_spec オプションに、argument_specs.yml の中身を渡しています。

provided_arguments オプションにはチェックさせたい変数を指定します。ここでは、vars ディレクティブ配下の my_parameters の中身(myapp_intmyapp_str)がチェックさせたい変数です。provided_arguments オプションの指定なので、チェックしたい変数が別の場所(インベントリ変数、Play 変数、extra vars など)してあるなら指定不要です。

正常時の結果

先程の my_parameters は要件を満たしています。この状態で Playbook を実行します。

PLAY [Test Play] *****************************************************************************************************

TASK [Verify variables by argument_specs.yml] *************************************************************************
ok: [localhost]

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

ok になりました。

チェックだけなので、ロール自体の処理は実行されません。

異常時の結果

今度は要件を満たさないようにしてみます。

        # 略
        my_parameters:    # チェックさせたい変数を束ねてる
          myapp_int: damedesuyo   # int にすべきところを意図的に文字列
          myapp_str: sakana

Playbook 実行結果は以下のとおりです。myapp_intint にできないという親切なメッセージが表示されました。

fatal: [localhost]: FAILED! => {
    "argument_errors": [
        "argument 'myapp_int' is of type <class 'str'> and we were unable to convert to int: <class 'str'> cannot be converted to an int"
    ],
    "argument_spec_data": {
        "myapp_int": {
            "description": "The integer value",
            "required": true,
            "type": "int"
        },
        "myapp_str": {
            "description": "The string value",
            "required": true,
            "type": "str"
        }
    },
    "changed": false,
    "msg": "Validation of arguments failed:\nargument 'myapp_int' is of type <class 'str'> and we were unable to convert to int: <class 'str'> cannot be converted to an int",
    "validate_args_context": {}
}

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

まとめ

用途は限られるかもしれませんが、ロールの処理はしたくないけど変数のチェックだけしたい、というときには有効な手段だと思います。

参考

docs.ansible.com

おまけ

ロールの実行に必要な変数のチェックという用途とは異なりますが、何かしらの変数のチェックを JSON Schema で行いたい場合は、ansible.utils コレクション内の validate モジュールなどが利用できます。

[Ansible] antsibull の発音とスペル

はじめに

Ansible の周辺にはさまざまなツールがあります。

その中に、antsibullantsibull-docsantsibull-changelogのように、antsibull という言葉を含むツールがあります。

この antsibull (よくスペルを間違えます)が、なぜこのようなスペルなのか、どのように発音するのか前から気になっていたので、Forum で聞いてみました。

antsibull の発音

とくに t を発音するかどうかが気になっていました。たとえば、castlet は発音しないと思うので。

聞いた限りでは、 t は発音する方のみでした。

そうしないと、antsibull-docsansible-doc が聞き分けにくすぎますよね・・・。

なお、Ansible についてYouTubeで情報発信されている Ansiblle Pilot チャンネルの antsibull-changelog についての動画で、は t の発音の有無はうまく聞き取れませんでした(ヒアリング能力不足)。この場合は、antsibull-docs と違い、他に類似の発音のツールがないので、あまり気にしなくてもいいのかもしれません。

antsibull のスペル

コマンド入力時に、ansible と区別しやすくする意図があったそうです。

ansibull という候補もあったそうですが、antsibull のほうが 3文字目で ansible と区別がつく(タブ補完が効く)ということです。

forum.ansible.com

おわりに

個人的に、発音が分からないと口頭で伝えるときちょっと抵抗を感じてしまいます・・。

あと、Ansible と牛の話(?)も教えていただきました。

jpmens.net