コンテンツにスキップ

モジュール

setup

ansible.builtin.setup – Gathers facts about remote hosts — Ansible Documentation

facts変数を収集する。
ad-hocで実行する方が多いかも?

$ ansible -i inventory.ini all -m setup 

assert

ansible.builtin.assert – Asserts given expressions are true — Ansible Documentation

  - name: assert sample
    vars:
      hoge: "zzz"
      foo: "bar"
      baz: False
    ansible.builtin.assert:
      that:
        - "hoge is defined"
        - foo is defined
        - baz is defined and baz
      fail_msg: "'hoge','bar' must be defined, 'baz' must be true"
    register: assert_result

thatで指定した各値がtrueでなければタスクが失敗する。
変数ではなく文字列で指定するので、:を含む文字はYAMLのキーとしてparseされてしまうため、ダブルクォートなどで囲む必要がある。

  - name: assert
    ansible.builtin.assert:
      that:
      - 'sample_text | regex_search("could not found: foobar")'

uri

HTTPをしゃべる。
以下はAWX/AAPで通知テストをkickするRESTを叩くタスク。
basic認証+HTTPSでSSL検証無効の設定で、レスポンスコードが200or201or202を期待している。

  ansible.builtin.uri:
    method: POST
    url: "https://{{ aap_address }}/api/v2/notification_templates/{{ notify_id }}/test/"
    url_username: "{{ username }}"
    url_password: "{{ password }}"
    validate_certs: false
    force_basic_auth: true
    status_code: [200, 201, 202]

lineinfile

ansible.builtin.lineinfile – Manage lines in text files — Ansible Documentation

      lineinfile:
        path: lineinfile.txt
        regexp: '^port: 80'
        line: 'port: 8080'

lineinfile.txtファイルの中の^port: 80最後に マッチする行をport: 8080に変更。
port: 8080が有る場合は、他に^port: 80にマッチしてもそれは対象外。

最初に マッチする行を対象にする場合はfirstmatch: trueを指定。

ファイル内にマッチする行が見つからなかった場合は、デフォルトではファイル末尾に追記される。
ファイル末尾以外に追記したい場合は、insertafterまたはinsertbeforeを使うことで、指定行直下・または直前に挿入できる。 insertafterinsertbeforeは指定できるのはどちらか片方。(両方同時指定は不可)

blockinfile

ansible.builtin.blockinfile – Insert/update/remove a text block surrounded by marker lines — Ansible Documentation

マーカー行が複数ある場合は、「ファイル内一番末尾の開始マーカー・終了マーカー」の間が処理対象になった。(ansible 2.10 / ansible 2.11で確認)

# /share/www configure begin
1
# /share/www configure end

# /share/www configure begin
2
# /share/www configure end

<IfModule dir_module>
    DirectoryIndex index.html
</IfModule>

# /share/www configure begin
3
# /share/www configure end

こんな入力ファイルに対して

    - name: blockinfile sample
      blockinfile:
        path: blockinfile-test.txt
        marker_begin: begin
        marker_end: end
        marker: '# /share/www configure {mark}'
        block: |
          ...

を実行すると、更新されるのは 3 の部分のみ。
(複数のbegin行がある場合は最後のものが使用される)

入力ファイルが以下の場合は、1から3までの範囲が更新される。
(end行も複数ある場合は最後のものが使用される)

# /share/www configure begin
1
# /share/www configure end

2
# /share/www configure end

<IfModule dir_module>
    DirectoryIndex index.html
</IfModule>

3
# /share/www configure end

これなら一度で確かめられた。
↓のファイルなら、blockinfileが更新するのは3から5まで。

# /share/www configure begin
1

# /share/www configure begin
2

# /share/www configure begin
3
# /share/www configure end

<IfModule dir_module>
    DirectoryIndex index.html
</IfModule>

4
# /share/www configure end

5
# /share/www configure end

replace

ansible.builtin.replace – Replace all instances of a particular string in a file using a back-referenced regular expression — Ansible Documentation

after/beforeで「ここからここまでの間」を指定できる。

    - name: replace sample
      replace:
        path: duplicate-test.txt
        regexp: ^[0-9]+$
        replace: zzz
        after: '# /share/www configure begin'
        before: '# /share/www configure end'

入力ファイルが↓のように複数マッチする場合は

# /share/www configure begin
1

# /share/www configure begin
2

# /share/www configure begin
3
# /share/www configure end

<IfModule dir_module>
    DirectoryIndex index.html
</IfModule>

4
# /share/www configure end

5
# /share/www configure end

1から3までが対象だった。(afterbeforeも最初にマッチした部分が対象)

redhat_subscription

community.general.redhat_subscription – Manage registration and subscriptions to RHSM using the subscription-manager command — Ansible Documentation

RHELのサブスクリプション割り当てを行う。 開発者ライセンスならプールIDは1個しかないので

    - name: subscription
      community.general.redhat_subscription:
        state: present
        username: "{{ rh_username }}"
        password: "{{ rh_password }}"
        auto_attach: true

ですべて完了する。

制限ネットワーク環境のRHEL7でproxy経由でサブスクリプション登録とDockerインストール - zaki work log

これでいうとsubscription-manager registerしてsubscription-manager attach --pool=****まで終わった状態になる。

alternatives

community.general.alternatives – Manages alternative programs for common commands — Ansible Documentation

community.general.alternativesalternativesコマンドを使ったコマンド切り替え設定を行う。

- name: alternatives python
  community.general.alternatives:
    name: python
    link: /usr/bin/python
    path: /usr/bin/python3
  become: true

これで、/usr/bin/python -> /etc/alternatives/python -> /usr/bin/python3へのリンクがpythonという名前で登録される。
コマンドとしては以下と同等。
(priorityはデフォルト50)

# update-alternatives --install /usr/bin/python python /usr/bin/python3 50

パッケージ

dnf

CentOS7(yum環境)に使える? => NG

fatal: [cloud-dev]: FAILED! => changed=false 
  msg: Could not import the dnf python module using /usr/bin/python (2.7.5 (default, Nov 16 2020, 22:23:17) [GCC 4.8.5 20150623 (Red Hat 4.8.5-44)]). Please install `python3-dnf` or `python2-dnf` package or ensure you have specified the correct ansible_python_interpreter. (attempted ['/usr/libexec/platform-python', '/usr/bin/python3', '/usr/bin/python2', '/usr/bin/python'])
  results: []

ただし、CentOS7でsudo yum install python2-dnfを入れると動く。
dnfモジュールでパッケージインストールし、CentOS7上でrpm -qaとかしても確認できる。

yum

Fedora34 / RHEL8に使える? => OK

apt_repository

- name: add apt repository
  ansible.builtin.apt_repository:
    repo: deb [arch=arm64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu focal stable
    filename: docker

これで以下のファイルが作成される。

$ cat /etc/apt/sources.list.d/docker.list
deb [arch=arm64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu focal stable

このとき、/etc/apt/sources.list.d/docker.list以外のファイルですでに同じ設定がある場合はdocker.listは作成されずにokとなる。

ファイル

state

file

対象ファイルがない場合はエラーになる。
逆手にとってファイル存在チェックに使える(その場合エラーは無視するようにする必要はある)

以下は/var/tmp/ansible-fileが無い場合に最初のタスクが失敗(ignore_errorsにより無視)し、次のタスクでfile not existが出力される。ファイルがある場合は最初のタスクは成功し、続くタスクはwhenの条件を満たさないためスキップされる。

- name: exist file?
  file:
    path: /var/tmp/ansible-file
    state: file
  register: result
  ignore_errors: true

- debug:
    msg: file not exist
  when: result is failed

failed_whenを使うなら以下

  - name: dounaru
    file:
      path: /var/tmp/ansible-file
      state: file
    register: result
    failed_when: false

  - debug:
      msg: file not exist
    when: result.state == "absent"

モード

- name: create file
  file:
    path: /var/tmp/file_permission
    mode: "0755"
    state: directory

これなら

$ ll -d /var/tmp/file_permission/
drwxr-xr-x. 2 zaki zaki 6  7月 31 10:27 /var/tmp/file_permission/
mode 実体
"0755" (str) drwxr-xr-x
0755 (int) drwxr-xr-x
"755" (str) drwxr-xr-x
755 (int) d-wxrw--wt

755にすると、10進数の755入力を8進数と解釈し1363としてモード設定される動作になる。 モード設定は8進数の数値か文字列型の数値が入力なのと、先頭ゼロの数値は8進数としてYAMLが解釈するので、先頭ゼロを付けずにintの数値を指定すると想定外の動作になる。

fetch

ターゲットノードのファイルをコントロールノードへコピーする。
ディレクトリは不可。(srcのパスがディレクトリの場合は失敗する)

fatal: [fedora-node]: FAILED! => changed=false 
  file: /home/zaki/src/docker-images/
  msg: remote file is a directory, fetch cannot work on directories

ドキュメントのsrcパラメタの項にも記載あり。

This must be a file, not a directory.

fetchモジュールの使い方全般ははてブに書いた。
[Ansible] fetchモジュールを使ってリモートのファイルを実行ノードへ転送・集約する - zaki work log

slurp

ターゲットノード上のファイルの中身を取得する。
fetchと異なりファイルシステム上へ保存せずにオンメモリ処理。
base64エンコードされているのででコードして使用する。

  - name: get private key
    ansible.builtin.slurp:
      src: /home/ec2-user/.ssh/id_rsa
    register: ssh_private_key

  - name: create repository credential on awx
    awx.awx.credential:
      name: git-repository-credential
      organization: Default
      credential_type: Source Control
      inputs:
        username: ec2-user
        ssh_key_data: "{{ ssh_private_key.content | b64decode }}"

make

/path/to/awx-operatorディレクトリ上でmake deploy IMG=zakihmkc/awx-operator:0.17.0を実行するタスクであれば以下の通り。

- name: deploy awx-operator
  community.general.make:
    chdir: /path/to/awx-operator
    target: deploy
    params:
      IMG: zakihmkc/awx-operator:0.17.0

ターゲットファイル作成済みでmakeが何も処理しない場合は、実行ステータスはokとなる。

meta

再接続

たとえば、OSユーザーのグループを更新した場合、通常であればログインし直さなければ変更が反映されない。
Ansibleも同様で、タスクでグループの更新を行っても、後続のタスクは接続が維持されているため、更新されたグループの状態でタスクが実行されない。
この場合、metaモジュールreset_connectionを使って再接続を行い、変更を反映して後続のタスクを実行できる。

  - name: グループを変更するタスク
    ...

  - name: refresh connection
    ansible.builtin.meta: reset_connection

  - name: 変更したグループ前提のタスク
    ...

playの終了

プログラムにおけるexit(0)みたいなやつ。
任意のタイミングでplayを正常終了させることができる。

  tasks:
  - name: task1
    debug:
      msg: task1

  - name: task2
    debug:
      msg: task2

  - name: end play
    ansible.builtin.meta: end_play

  - name: task3
    debug:
      msg: task3

このplaybookの内容でAnsible実行すると、以下の通りtask3は実行されずに終了する。

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

TASK [task1] ********************************************************************
ok: [localhost] => 
  msg: task1

TASK [task2] ********************************************************************
ok: [localhost] => 
  msg: task2

TASK [end play] *****************************************************************

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

インベントリの再読み込み

ダイナミックインベントリでホスト情報を再収集したい場合、など。

- name: refresh inventory
  ansible.builtin.meta: refresh_inventory

[Ansible] 任意のタイミングでダイナミックインベントリのホスト情報収集を行う - zaki work log

Docker

push image

docker_imageを使用しパラメタにpush: trueを指定。

- name: push container image
  community.docker.docker_image:
    name: quay.io/ansible/awx-ee
    repository: zakihmkc/awx-ee:0.6.0
    push: true
    source: local

このタスクの場合は、ローカルにあるquay.io/ansible/awx-eeイメージをDocker Hubへzakihmkc/awx-ee:0.6.0としてpushする。
このとき、zakihmkc/awx-ee:0.6.0が既にローカルにある場合はtagの上書きが発生しないため、pushされない。ここでpushしたい場合は、tag設定を上書きするforce_tag: trueも追加する。

git

  ansible.builtin.git:
    repo: https://github.com/zaki-lknr/awx_build_and_deploy.git
    version: feature/awx-ver-21.13.0
    dest: /var/tmp/work-dir

destのディレクトリは事前に作成しておく。
GitモジュールはCLIのgit cloneと異なり、上の例でいうとawx_build_and_deployサブディレクトリは作成されない。

ssh

openssh_keypair

ssh key pair作成

    community.crypto.openssh_keypair:
      path: "{{ ansible_env.HOME }}/.ssh/id_rsa"
      size: 4096  # default
      type: rsa   # default
    register: ssh_keypair_result

authorized_key

authorized_keysへの公開鍵登録

    ansible.posix.authorized_key:
      user: "{{ ansible_env.USER }}"
      key: "{{ ssh_keypair_result.public_key }}"
      # key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"
    delegate_to: localhost
    run_once: true

pause

sleepする

  - name: sleep
    ansible.builtin.pause:
      seconds: 10

単純なsleepでなく、最大で指定時間だけwaitがかかり、その間にCtrl-c押下で「即再開 or 処理中断」の選択が可能になる。
aで中断した場合はそこで処理が終了する。

TASK [sleep] *************************************************************************
Pausing for 10 seconds
(ctrl+C then 'C' = continue early, ctrl+C then 'A' = abort)
Press 'C' to continue the play or 'A' to abort 
fatal: [localhost]: FAILED! => 
  msg: user requested abort!

debug

msgを使えば(変数を含め)任意の文字列をプリントする。
変数だけで良ければvarを使う方が楽。

---
- hosts: localhost
  gather_facts: false
  vars:
    val1: 1234

  tasks:
    - debug:
        var: val1

ただしvarの場合はリスト出力は不可

debug:
  var:
  - val1
  - val2
  # 不可