Ansible:さらにPlaybookをきわめる
本連載の第4回、第5回では「Ansible応用編」と題して、Ansibleの応用的な使い方やTipsについて詳しく解説していきます。前回(第4回)は、Ansibleのベストプラクティスに沿ってPlaybookを再整理する方法を紹介しました。今回は、Ansibleの持つ各種機能を活かしたPlaybookの効率的な記述方法やつまずきやすいポイントの回避方法を紹介します。
Playbookを効率的に書く
同種の処理をまとめる
同じ処理を何度も実行する際には、Loop構文を使うことで処理をまとめて記述できます。処理をまとめることで記述を簡潔にし、Playbookのメンテナンス性を高めることができます。
基本的なLoop構文
基本的なLoopの記述方法は、以下のようになります。「with_items」アトリビュートに、YAML記法のシーケンス(配列に相当)形式で定義しておくと、実行時に各要素が順次展開され実行されます。
- name: echo tasks command: echo "{{ item }}" with_items: - foo - bar - baz
また、yumモジュールやaptモジュールは、「with_items」アトリビュートで指定した複数パッケージを1トランザクションにまとめて適用するため、処理の高速化にも寄与します。
さらに、以下のようにYAML記法のマッピング(ハッシュや連想配列に相当)として定義し、各要素にアクセスすることも可能です。
- name: add user user: name={{ item.name }} groups={{ item.groups }} with_items: - { name: 'user1', groups: 'wheel' } - { name: 'user2', groups: 'root' }
以下のように、変数を用いて処理することも可能です。
- hosts: all vars: users: satoh: directory: /home/satoh shell: /bin/bash groups: developers tanaka: directory: /home/tanaka shell: /bin/zsh groups: developers become: yes tasks: - name: "user add" user: name={{ item.key }} shell={{ item.value.shell }} groups={{item.value.groups}} with_dict: "{{ users }}"
コマンド結果を使った Loop 構文
以下のようにコマンドの実行結果を元にLoop処理を行うことで、動的なリストに対して処理を行うことも可能です。例示したPlaybookは、「/opt以下にある拡張子が『.dat』のファイルのパーミッションを全て『600』の状態にする」ものです。「.dat」ファイルが増減した場合にも、状態が管理され続ける動的なPlaybookとなっています。
- hosts: all tasks: - name: Assign command output as variable shell: find /opt -type f -name "*.dat" register: command_result - name: Change permission each "*.dat" files file: path={{ item }} mode=600 with_items: "{{ command_result.stdout_lines }}"
本稿で挙げた以外にも、Ansibleでは様々なLoop処理の記述が可能です。その他のLoop構文に関しては Ansible 公式ドキュメントの「Loops」の項を参照ください。
条件に応じて処理を切り替える
様々な条件に応じて処理を切り替えることで、より複雑な処理を記述できるようになります。
変数による条件分岐
管理対象の状態や変数の内容を条件に、次に実行するタスクを制御する際には、「when」アトリビュートを利用します。以下の例は、管理対象がCentOSの場合はyumを、Debianの場合はaptを使ってパッケージ管理を行う例です。
- hosts: all tasks: - name: install package by yum yum: name=vim state=latest when: ansible_os_family == 'CentOS' - name: install package by apt apt: name=vim state=latest when: ansible_os_family == 'Debian'
コマンド結果による条件分岐
「変数による条件分岐」の応用として、コマンドの実行結果を条件に、その結果に応じて次に実行するタスクを制御することができます。
以下の例では最初のコマンド実行が成功すると「success」かつ「changed」の結果となり、実行に失敗すると「failed」の結果に遷移します。また遷移しないステータスは「skipped」としてパスされます。ステータス以外にも、標準出力の結果を条件とすることも可能です。
- hosts: all tasks: - name: exec command command: /bin/true register: result ignore_errors: True - name: exec success debug: msg="echo success" when: result|success - name: exec changed debug: msg="echo changed" when: result|changed - name: exec skipped debug: msg="echo skipped" when: result|skipped - name: exec failed debug: msg="echo failed" when: result|failed"
Taskの終了状態による条件分岐
Taskの結果が「Changed」になることを条件として、実行される後処理を入れたい場合には、以下の例のように「notify」と「handler」を組み合わせて記述します。
Taskが「Changed」で終了すると、一連のPlaybookの最後にnotifyで指定した名前のTaskが実行されます。その際、同じhandlerタスクが複数回呼ばれたとしても、全てまとめて1度だけ実行されます。例えば、設定反映のための再起動をnotifyで指定したTaskが複数回実行さても、実際に再起動が行われるのは1度だけ、という制御が可能になります。
また、Playbookが途中で終了した場合、デフォルトではhandlerタスクは実行されませんが、
- コマンドに「--force-handlers」オプションをつけて実行
- Playbook内で、「force_handlers: True」と指定
- ansible.cfg設定ファイル内で「force_handlers = True」と設定
上記いずれかを実施しておくと、Playbookが途中で異常終了しても、その時点までにnotifyで指定を受けたhandlerタスクだけは、最後に実行できます。
- hosts: all tasks: - name: exec command(always change) command: /bin/true notify: handler handlers: - name: handler debug: msg="handler"
グルーピングした処理の終了状態による条件分岐
Block構文を使うことで、個別のTaskをひとまとめのグループとして扱うことができます。グループ化したTask内のいずれかでエラーが発生した場合に実行される処理を「rescue」内に、Block内Taskの成否に関わらず常に実行される後処理を「always」内に記述することができます。
- hosts: all tasks: - block: - name: install tomcat7 yum: pkg={{ item }} state=installed with_items: - java-1.7.0-openjdk - tomcat7 - name: configure tomcat settings template: src=tomcat7.conf.j2 dest=/etc/tomcat7/tomcat7.conf - name: start tomcat7 service: name=tomcat7 state=started enabled=yes rescue: - name: exec when error happened in block. debug: msg="error happened." always: - name: exec always. debug: msg="always execute."
管理対象を効率的に管理する
管理対象の増加や改廃などによって、inventory fileの見通しが悪くなり、管理性が低下します。inventory fileも以下のようにすることで記述を簡潔にし、管理性を高めることが可能となります。
ルールに基づいた管理
IPアドレスや、ホスト名が英数字の連番で構成されている場合には以下のように[begin:end:step]の書式でまとめて記述することが可能です。「begin」には開始の数字又は英字を、「end」には終了を、そして「step」にはカウントアップの単位を指定します。「step」は省略可能で、その場合は1ずつカウントアップされることになります。
[webservers] web-[1-9:1] [apservers] app-[01:99:1] 192.168.[0:4:1].[1:30:1] [dbservers] db-[a-Z:1]
外部ソースに基づいた管理
管理対照の情報を外部で管理している場合、Dynamic Inventory機能を利用することで外部ソースの情報を元にした動的なinventory情報を利用できます。
以下は、OpenStackをデータソースにしたDynamic Inventoryの例です。まず必要なソフトウェアの導入と管理対象の設定を行います。今回は管理対象にTagを振ることで、Playbookの適用先を特定する環境を想定します。
まず、必要なソフトウェアの導入と事前準備を行います。
# 環境準備 $ sudo yum install -y python-pip python-devel gcc $ sudo pip install os_client_config shade $ curl -O https://raw.githubusercontent.com/ansible/ansible/devel/contrib/inventory/openstack.py $ chmod +x openstack.py # Tagの付与 # (実際にはインスタンス作成時やHeat Template等に自動でTagが振られるようにしておきます) $ openstack server list -c ID -c Name -c Properties --long +--------------------------------------+---------------------+------------+ | ID | Name | Properties | +--------------------------------------+---------------------+------------+ | 949639ae-4ab0-447d-b559-f484040353b8 | db-instance-01 | | | f17af9bf-50cf-4243-b2c1-150024d2be3b | web-instance-01 | | | 435f8643-d0ff-4708-b5e7-6c0c9b0bfb85 | app-instance-01 | | | 1fbf91a4-b9a9-42d5-a350-231509058e81 | bastion-instance-01 | | +--------------------------------------+---------------------+------------+ $ openstack server set --property tags=db 949639ae-4ab0-447d-b559-f484040353b8 $ openstack server set --property tags=web f17af9bf-50cf-4243-b2c1-150024d2be3b $ openstack server set --property tags=app 435f8643-d0ff-4708-b5e7-6c0c9b0bfb85 $ openstack server set --property tags=app 1fbf91a4-b9a9-42d5-a350-231509058e81 $ openstack server list -c ID -c Name -c Properties --long +--------------------------------------+---------------------+---------------+ | ID | Name | Properties | +--------------------------------------+---------------------+---------------+ | 949639ae-4ab0-447d-b559-f484040353b8 | db-instance-01 | tags='db' | | f17af9bf-50cf-4243-b2c1-150024d2be3b | web-instance-01 | tags='web' | | 435f8643-d0ff-4708-b5e7-6c0c9b0bfb85 | app-instance-01 | tags='app' | | 1fbf91a4-b9a9-42d5-a350-231509058e81 | app-instance-02 | tags='app' | +--------------------------------------+---------------------+---------------+
ソフトウェアの導入結果は、以下のコマンドで確認します。
$ ./openstack.py --list
準備が整ったら、以下のように実行します。
# 全体に実行する場合 $ ansible -i openstack.py all -m ping # tags=appの対象にのみ実行する場合 $ ansible -i openstack.py meta-tags_app -m ping
今回例示したOpenStack以外にも、AWSやCobblerに対応したDynamic Inventory用スクリプトも公開されています。詳細はAnsible公式ドキュメントの「Dynamic Inventory」の項を参照してください。また、必要に応じて独自に作成することで、対応データソースの拡充も可能です。
このように、Dynamic Inventory機能を利用することで、管理対照の情報を多重管理する必要がなくなりますし、管理対象の頻繁な改廃にも容易に対応可能となります。
デバッグを効率的に行う
Playbook実行前のチェック
事前に各種チェックを行うことで、Playbookを実行する前に不具合に気付けるようになります。
構文チェック
ansibleコマンドに「--syntax-check」オプションをつけて以下のように実行すると、Playbookの構文をチェックできます(チェックのみで、Playbookの実行はされません)。Playbookを新規作成した際や修正を行った際には、必ずチェックすることをお勧めします。
ansible-playbook -i <hosts> <playbook.yml> --syntax-check
Task一覧のチェック
ansible コマンドに「--list-tasks」オプションをつけて以下のように実行すると、実行されるTaskとTagの一覧が表示されます。事前にTask一覧を確認し、想定するTaskがリストアップされているか、想定外のTaskが実行されることがないか、あらかじめ確認しておきます。
ansible-playbook -i <hosts> <playbook.yml> --list-tasks
実行時影響のチェック(Dry Run)
ansibleコマンドに「--check」オプションをつけて以下のように実行すると、対象への変更は行わずに、Playbookを適用した結果起きる変化を確認できます。
さらに併せて「--diff」オプションも指定すると、テンプレートによってリモートファイルにどのような変更が行われるかも事前に確認できるようになります。
ただし、コマンドは実際には実行されませんので、対象の状態変化を前提にした後続タスクや、結果を変数に格納しての処理は正常に実施されない点には注意が必要です。
ansible-playbook -i <hosts> <playbook.yml> --check --diff
Playbook実行中のチェックを行う
debug モジュールを使ったチェック
debugモジュールを使うことで、以下のようにPlaybook中で任意のメッセージを表示したり、変数に代入された値を確認したりできます。
- hosts: all tasks: - name: exec uptime command: /usr/bin/uptime register: result - debug: var=result - debug: msg="debug message"
上記のPlaybookを実行すると以下のように結果が表示され、変数に代入された値が確認できます。
PLAY [all] ********************************************************************* TASK [exec uptime] ************************************************************* changed: [127.0.0.1] TASK [debug] ******************************************************************* ok: [127.0.0.1] => { "result": { "changed": true, "cmd": [ "/usr/bin/uptime" ], "delta": "0:00:00.001574", "end": "2016-06-07 06:56:29.955837", "rc": 0, "start": "2016-06-07 06:56:29.954263", "stderr": "", "stdout": " 06:56:29 up 5 days, 4:45, 1 user, load average: 0.00, 0.01, 0.05", "stdout_lines": [ " 06:56:29 up 5 days, 4:45, 1 user, load average: 0.00, 0.01, 0.05" ], "warnings": [] } } TASK [debug] ******************************************************************* ok: [127.0.0.1] => { "msg": "debug message" } PLAY RECAP ********************************************************************* 127.0.0.1 : ok=3 changed=1 unreachable=0 failed=0"
verboseモードを使ったチェック
Playbook実行時に「-v」オプションをつけることで、管理対象の状態やPlaybookの実行状況をより詳細に確認することができます。さらに「-vvv」オプションをつけると、より詳細にSSH接続の状況なども確認できるようになります。
PLAY [all] ********************************************************************* TASK [exec uptime] ************************************************************* changed: [127.0.0.1] => {"changed": true, "cmd": ["/usr/bin/uptime"], "delta": "0:00:00.001550", "end": TASK [debug] ******************************************************************* ok: [127.0.0.1] => { "result": { "changed": true, "cmd": [ "/usr/bin/uptime" ], "delta": "0:00:00.001550", "end": "2016-06-07 07:04:14.418680", "rc": 0, "start": "2016-06-07 07:04:14.417130", "stderr": "", "stdout": " 07:04:14 up 5 days, 4:52, 1 user, load average: 0.00, 0.01, 0.05", "stdout_lines": [ " 07:04:14 up 5 days, 4:52, 1 user, load average: 0.00, 0.01, 0.05" ], "warnings": [] } } TASK [debug] ******************************************************************* ok: [127.0.0.1] => { "msg": "debug message" } PLAY RECAP ********************************************************************* 127.0.0.1 : ok=3 changed=1 unreachable=0 failed=0
PLAYBOOK: debug_module.yml ***************************************************** 1 plays in debug_module.yml PLAY [all] ********************************************************************* TASK [exec uptime] ************************************************************* task path: /home/centos/debug_module.yml:4 <127.0.0.1> ESTABLISH SSH CONNECTION FOR USER: None <127.0.0.1> SSH: EXEC ssh -C -q -o ControlMaster=auto -o ControlPersist=3600s –o StrictHostKeyCheckin changed: [127.0.0.1] => {"changed": true, "cmd": ["/usr/bin/uptime"], "delta": "0:00:00.001628", "end": TASK [debug] ******************************************************************* task path: /home/centos/debug_module.yml:8 ok: [127.0.0.1] => { "result": { "changed": true, "cmd": [ "/usr/bin/uptime" ], "delta": "0:00:00.001628", "end": "2016-06-07 07:05:57.062392", "rc": 0, "start": "2016-06-07 07:05:57.060764", "stderr": "", "stdout": " 07:05:57 up 5 days, 4:54, 1 user, load average: 0.00, 0.01, 0.05" "stdout_lines": [ " 07:05:57 up 5 days, 4:54, 1 user, load average: 0.00, 0.01, 0.05" ], "warnings": [] } } TASK [debug] ******************************************************************* task path: /home/centos/debug_module.yml:10 ok: [127.0.0.1] => { "msg": "debug message" } PLAY RECAP ********************************************************************* 127.0.0.1 : ok=3 changed=1 unreachable=0 failed=0"
指定タスクの実行
あるTaskの実行を試したいときには、「--tags」オプションを使い下記のように実行することで、特定のtagのついたタスクのみの実行が可能です。
ansible-playbook -i <hosts> <playbook.yml> --tags <tag_name>
tagは以下のように各タスクや、Blockに対して「tags」アトリビュートを使い任意の数だけ設定することができます。
- hosts: all tasks: - block: - name: install tomcat7 yum: pkg={{ item }} state=installed with_items: - java-1.7.0-openjdk - tomcat7 tags: - setup - name: configure tomcat settings template: src=tomcat7.conf.j2 dest=/etc/tomcat7/tomcat7.conf tags: - configure - name: start tomcat7 service: name=tomcat7 state=started enabled=yes tags: - setup tags: - tomcat rescue: - name: exec when error happened in block. debug: msg="error happened." always: - name: exec always. debug: msg="always execute."
指定タスク以降の実行
Playbook実行中のある特定Taskの処理が失敗した場合には、「--start-at」オプションを使って指定したTask以降の全てを再実行できます。
ansible-playbook -i <hosts> <playbook.yml> --start-at ’<task_name>’
もし、一連のタスク内の一部だけをピックアップして実行したい場合には「--step」オプションも併せて実行し、不要なタスクはスキップさせるという使い方も可能です。
その他のTips
Proxy経由でのネットワーク接続を行う
実行環境によっては、インターネットアクセスのためにProxy設定が必要な場合があります。Ansibleでは「environment」アトリビュートで環境変数が指定できるため、下記の例のようにすることでProxyの設定ができます。
環境によってProxy設定の有無を使い分けたい場合は、proxy_envに空白を指定しておけばProxy設定なしで接続されます。
- hosts: all vars: proxy_env: http_proxy: http://proxy.example.com:8080 https_proxy: https://proxy.example.com:8080 tasks: - yum: name=httpd state=latest environment: "{{proxy_env}}"
一部タスクを別ホストで実行する
「delegate_to」アトリビュートを使うことで、指定したタスクを別ホスト上で実行できます。この機能は、一連の処理の中に特定ホストのみでしか実行できないTaskがある場合などに有効です。以下の例は、OpenStackのLBaaS配下のサーバーをアップデートするもので、OpenStackサーバーへの通信やコマンド実行が特定のホストでのみ可能なケースを想定し、次の手順を実行しています。
- LBの負荷分散グループから一部のサーバーを離脱
- Webサーバーのアップデート
- アップデート完了後負荷分散グループへ再度追加
- hosts: webservers serial: "30%" vars: ops-cli-server: 10.0.0.1 pool-name: "demo-pool01" protocol-port: 8080 tasks: - name: take out of balancing pool command: neutron lb-member-delete {{ ansible_default_ipv4.address }} delegate_to: {{ ops-cli-server }} - name: update server yum: name=* state=latest - name: add to balancing member command: neutron lb-member-create --address {{ ansible_default_ipv4.address }} --protocol-port delegate_to: {{ ops-cli-server }}
また今回の例のように、負荷分散グループやクラスタ内の一部を順にアップデートしていく処理などの場合、一度に全台を更新するのではなく一部を順にアップデートすることで、サービスダウンを防ぎつつ処理を進められます。「serial」アトリビュートを指定することで同時に処理する台数や、割合を指定して実行することが可能となります。Task実行先に自サーバーを指定する際は「local_action」アトリビュートで代替することも可能です。より詳しい情報を知りたい場合はAnsible公式ドキュメント、「Delegation」の項を参照ください。
再起動からの復帰が完了するまで待機する
変更処理のなかには、Kernelのアップデートなどのように、管理対象が再起動されるまで反映されないものがあります。後続のタスクが、反映後の状態を前提とする場合には管理対象の再起動を行ったうえで復帰を待ち、後続タスクを再開する必要があります。こうした場合には、以下の例のようにローカルモードと「wait_for」モジュールを組み合わせることで管理対象の復帰状況を定期的に確認し、管理対象の再起動を待って後続のタスクを継続させることが容易になります。
- hosts: all tasks: - name: reboot server command: shutdown -r now become: true async: 0 poll: 0 - name: wait for shutdown local_action: | wait_for host={{ inventory_hostname }} state=stopped - name: wait for start local_action: | wait_for host={{ inventory_hostname }} state=started"
機密情報を暗号化する
Playbookを書いていると、認証情報やAPIキーなど平文で保存したくない機密情報の扱いに困ることがあります。Ansibleでは「Vault」機能を使うことで、指定のファイルを暗号化し保存できます。ファイルを暗号化するには、以下のようにansible-vaultコマンドを実行します。
ansible-vault create secret.yml Vault password: Confirm Vault password: Encryption successful
このように暗号化しておくことで、機密情報も含めてソースコード管理システムで管理できるようになるといったメリットも得られます。
暗号化したファイルを使うには、以下のように実行時にパスワードを入力します。
ansible-playbook -i hosts site.yml --ask-vault-pass Vault password:
また、暗号化したファイルを再度編集するには、一度復号して修正したのち再度暗号化する必要があります。当然のことながら、暗号化するとどんな変数が定義されているのか復号するまで分からなくなります。Vaultはファイル単位で暗号化するので、暗号化したい内容と暗号化不要な内容はファイルを分けて管理するのがお勧めです。
第4回で紹介したベストプラクティスに則った構成をとると、inventoryファイルに対応したディレクトリ配下の全ファイルをvarsファイルとして読み込むため、以下のようにファイルを分けて配置しておけば、public_settings.ymlは暗号化不要な内容を平文で記述し、private_settings.ymlには機密情報を記述し暗号化するという使い分けができます。
- group_vars/<group_name>/public_settings.yml
- group_vars/<group_name>/private_settings.yml
実行を高速化する
初期設定のままAnsibleを利用していると、Playbookの大規模化や管理対象の増加に伴いPlaybookの実行にかかる時間も長くなってしまいます。Ansibleでは各種設定を工夫することで、処理時間を短縮することが可能です。
並列実行数の設定(forks)
Ansibleでは、同じグループに対する処理を並列実行します。初期状態では5並列となっていますが、これを増やすことで並列度を増やすことができます。並列度の設定は、以下の箇所で指定可能です
- ANSIBLE_CONFIG(環境変数)
- ansible.cfg(カレントディレクトリ)
- .ansible.cfg(ホームディレクトリ)
- /etc/ansible/ansible.cfg
- 実行時のコマンド引数
また、並列実行は同じグループ内にのみ適用される点には注意が必要です。例えば以下のようなinventoryファイルを利用すると、webserversに対する処理が3並列で実行されたのち、dbserversに対する処理が2並列で実行されるという挙動になります。
[webservers] 192.168.0.10 192.168.0.11 192.168.0.12 [dbservers] 192.168.0.20 192.168.0.21
SSH接続の高速化
Ansibleでは、SSHを利用してタスクごとに管理対象に接続し処理を行います。そのため、SSH接続のオーバーヘッド低減は高速化に非常に有効です。
・ControlMaster
OpenSSHは、最初に接続した1つのセッションを複数セッション間で共有できる「ControlMaster」という機能を持っています。この機能を使うことで1度確立されたセッションを再利用し、使いまわすことができます。Ansibleではタスク実行ごとにSSH接続を行いますが、この機能を使うことでセッション確立のためのオーバーヘッドを低減しPlaybook実行全体での処理時間を削減することができます。
この機能を使うには、ansible.cfg設定ファイルの[ssh_connection]ディレクティブに、以下の設定を追加します。
ssh_args = -o ControlMaster=auto -o ControlPersist=3600s
ControlPersistには、セッションを維持し続ける時間を指定します。
・Pipelining
Ansibleでは通常、「一時ディレクトリに各タスク用の実行スクリプトを生成し、それを管理対象へsftp又はscpで転送したのちに、再度SSH接続してそのスクリプトを実行する」という処理がタスクごとに行われています。
Pipeliningを有効化すると、スクリプトファイルの転送処理は行わず、実行するスクリプトの内容を標準入力としてSSHでリモート実行するようになります。こうすることで、SSH接続処理とファイル転送処理の時間の分処理時間を削減できます。この機能を使うには、ansible.cfg設定ファイルの[ssh_connection]ディレクティブに、以下の設定を追加して、有効化します。
pipelining = True
Gathering factsの省略
Ansibleでは、Playbook実行前にまずは管理対象の情報を収集しています。これをGathering facts処理と呼びますが、ここにも時間がかかっています。
もし、収集した情報が不要であればこの処理自体を止めることで高速化できます。ansible.cfg設定ファイルに以下の設定を追加することで、情報収集を無効化できます。
gathering = explicit
ただし、無効化すると管理対象サーバーの情報を利用できなくなりますので、適用するPlaybookがansibleの取得した情報を利用していないかどうか確認のうえ、無効化するようにしてください。
対話処理を自動化する
自動化が難しい処理に、対話型の入力が必要なコマンドやインストーラーの実行があります。アプリケーションによっては、コマンドライン引数による指定やサイレントモードといった代替手段が提供されず、文字列をリダイレクトで渡してもうまく動作しないものがあります。そのような場合でも、Ansibleでは、「expect」モジュールを使うことで簡単に自動化できます。
以下では、MariaDBインストール後にセキュリティ対策実行する「mysql_secure_installation」コマンドを自動実行する方法を例に挙げて説明していきます。MariaDB Server 5.5にて動作を確認しています。また、管理対象サーバー側に「pexpect」python moduleの導入が必要となります。
- hosts: dbservers vars: password: "password" tasks: - name:"/usr/bin/mysql_secure_installation" expect: command: /usr/bin/mysql_secure_installation responses: "Enter current password for root \\(enter for none\\): " : "" "Set root password\\? \\[Y\\/n\\] " : "Y" "New password: " : "{{ password }}" "Re-enter new password: " : "{{ password }}" "Remove anonymous users\\?" : "y" "Disallow root login remotely\\?" : "y" "Remove test database and access to it\\?" : "y" "Reload privilege tables now\\?" : "y"
上記の例では、6 行目に「expect」モジュールの利用を宣言し、続く「command」アトリビュートで実行コマンドを指定しています。その後の「responses」ブロックでは
<対話型の待ち受けメッセージ(正規表現)> : <入力文字列>
の形で入力文字列を指定することで、対話型の待ち受けメッセージに応じた入力をエミュレートし、自動で処理が進みます。
expectによる自動化は、対話処理を自動化する非常に強力で便利なツールですが、コマンド文字列の応答タイミングや期待する応答内容が少し変更されるだけで、動作しなくなってしまう可能性があります。対話型の入力を必要とするコマンドと等価な処理を記述することなども検討したうえで、最終手段として使うことをお勧めします。
まとめと次回予告
今回は、AnsibleのPlaybookを記述するうえで、知っていると便利な実践的なTipsについて解説してまいりました。
Ansibleの持つ機能を活かすことで、様々な処理を効率的に記述できることが理解いただけたかと思います。次回は、Ansibleのテストにおける考え方や方法論を解説していきます。