てくなべ (tekunabe)

ansible / network automation / 学習メモ

[Ansible/Terraform] cloud.terraform.terraform モジュールでどんな terraform コマンドが実行される確認する

はじめに

Ansible の cloud.terraform.terraform モジュールは、Ansible から Terraform を呼べるモジュールです。

モジュールで指定するオプションに応じて、さまざま terraform コマンドが実行されます。

で、「このときは実際にどういうコマンドが実行されるんだろう?」と気になることがあります。

調べてみると、Ansible 本体の AnsibleModule クラスの run_command メソッド経由でコマンドが実行されることがわかりました。

このメソッドの中ではログを出力する処理があるので、このログを見ればどんなコマンドが実行されるかが確認できることになります。

ということで、試してみました。

  • 環境
    • ansible-core 2.16.6
    • cloud.terraform コレクション 3.0.0
      • 挙動説明、コードへのリンクも 3.0.0
    • macOS 13.6.7
    • Ansible と Terraform は同一マシンに入れて hosts: localhost で実行

基本的なお作法

run_command メソッド内で実行されるコマンドをデバッグするは、設定項目 DEFAULT_DEBUGデバッグを有効にします(デフォルト無効)。環境変数で設定する場合は ANSIBLE_DEBUG です。

このデバッグを有効にすると、Playbook 実行時にデバッグ情報が no_log: true にしたもの含めて大量に表示されるので注意してください。

(このデバッグほどしなくてもいい方法があれば教えてください)

デフォルトでは、ファシリティ INFO として出力されます。ファシリティを変更する場合は、設置項目 DEFAULT_SYSLOG_FACILITY で変更します。

今回は macOS を使うので、log コマンドで確認します。process はざっくり Python にしておきます。

(確認方法は各環境に合わせてください)

log コマンドは、こちらのページを参考にさせていただきました。ありがとうございます!

ログ出力の待機

% log stream --info --predicate 'process == "Python"'
Filtering the log data using "process == "Python""
(出力待ち)

Playbook 実行:

ANSIBLE_DEBUG=True ansible-playbook -i localhost, ansible_terraform.yml

すると以下のようにログが表示されます。

% log stream --info --predicate 'process == "Python"'
Filtering the log data using "process == "Python""
Timestamp                       Thread     Type        Activity             PID    TTL 
2024-06-09 14:38:02.930838+0900 0xdbbd6    Info        0x0                  18358  0    Python: (syslog.cpython-311-darwin.so) Invoked with project_path=./ state=present force_init=True workspace=default purge_workspace=False complex_vars=False targets=[] lock=True init_reconfigure=False overwrite_init=True check_destroy=False provider_upgrade=False binary_path=None plugin_paths=None variables=None variables_files=None plan_file=None state_file=None lock_timeout=None backend_config=None backend_config_files=None parallelism=None
2024-06-09 14:38:02.932716+0900 0xdbbd6    Info        0x0                  18358  0    Python: (syslog.cpython-311-darwin.so) Executing: /usr/local/bin/terraform version -json
2024-06-09 14:38:06.268688+0900 0xdbbd6    Info        0x0                  18358  0    Python: (syslog.cpython-311-darwin.so) Executing: /usr/local/bin/terraform init -input=false -no-color
2024-06-09 14:38:11.463882+0900 0xdbbd6    Info        0x0                  18358  0    Python: (syslog.cpython-311-darwin.so) Executing: /usr/local/bin/terraform providers schema -json
2024-06-09 14:38:15.128367+0900 0xdbbd6    Info        0x0                  18358  0    Python: (syslog.cpython-311-darwin.so) Executing: /usr/local/bin/terraform show -json

Executing: のあとに各種 terraform コマンドが確認できます。

おためし

いつくかのパターンで試してみます。

見やすさのため、以下からはログのうち Executing: /usr/local/bin/terraformterraform 以降の文字列のみを乗せます。

また、途中でコードの解説を含みますが、ざっと読んだ程度ですので、詳細、正確なところはコードをあたってください。

パターン1: リソースがない状態から作成

ほしいリソースがまだない状態から、terraform init 含めてリソースを作成するパターンです。

Playbook は以下のとおり。

    - name: Call Terraform
      cloud.terraform.terraform:
        project_path: ./
        state: present
        force_init: true

表示された terraform コマンドは以下のとおりです。結構いろいろ表示されますね。

terraform version -json
terraform init -input=false -no-color
terraform providers schema -json -no-color
terraform show -json
terraform workspace list -no-color
terraform plan -lock=true -input=false -no-color -detailed-exitcode -out /var/folders/2s/h6djr0fn3773tj1zy4mg442c0000gn/T/tmphxtb7o8u.tfplan
terraform validate
terraform show -json /var/folders/2s/h6djr0fn3773tj1zy4mg442c0000gn/T/tmphxtb7o8u.tfplan
terraform apply -no-color -input=false -auto-approve -lock=true /var/folders/2s/h6djr0fn3773tj1zy4mg442c0000gn/T/tmphxtb7o8u.tfplan
terraform show -json
terraform output -no-color -json

最初に terraform version を実行しています。これはあとで、バージョンによってオプションを切り替えるために取得しているようです。見つけた範囲ですと、apply 時に自動で yes して進めるオプションを -auto-approve にするか -auto-approve=true にするか、の判断に使われていました。

force_init: true を指定していて overwrite_init もデフォルトの true のままなので、init が実行されています(参考)。他のコマンド含め、-input=false が指定されているので、変数の値を入力するプロンプトは表示されず、未割り当ての変数があっても処理を続行します。Ansible から見ると terraform コマンド実行後の対話処理はないほうがいいのでこうなっているのだと思います。

いきなり terraform applyするのではなく terraform plan.tfplan ファイルを作成してから terraform applyしているのが特徴でしょうか。plan_file の指定がない場合は、一時ファイルとして作成されます。

validate が実行されるのは意外でした。project_pathbin_path妥当性をチェックする流れで validate もするようです。

3回 terraform show を実行しているのは、事前事後で diff を取得するためのようです。 それぞれの概要は以下のとおりです。

  • 1回目は、事前状態の取得
  • 2回目は、事前に terraform plan -out して生成した .tfplan ファイルからの状態の取得
    • 通常(チェックモードでない)は、ここの情報はその後とくに利用されないように見える
  • 3回目は、事後(apply後)状態の取得
    • 後述のチェックモードの場合は、2回目の結果が事後結果として扱われる

terraform apply にある -detailed-exitcode オプションは、終了コードによって、変更有無を判断するためのオプションです。

パターン2: リソース作成済みから再実行

最後は、リソースがある状態から再度同じ Playbook を実行するパターンです。タスクのステータス的には OK です。

表示された terraform コマンドは以下のとおりです。

terraform version -json
terraform init -input=false -no-color
terraform providers schema -json
terraform show -json
terraform workspace list -no-color
terraform plan -lock=true -input=false -no-color -detailed-exitcode -out /var/folders/2s/h6djr0fn3773tj1zy4smg442c0000gn/T/tmpscohbatx.tfplan
terraform validate
terraform show -json /var/folders/2s/h6djr0fn3773tj1zy4mg442c0000gn/T/tmpscohbatx.tfplan
terraform show -json
terraform output -no-color -json

terraform applyコマンドがないですね。

コード的には terraform applyを担当するメソッドは呼ばれますが、terraform plan 時に変更が検出されなかったため、terraform apply不要(needs_applicationfalse)という扱いで処理されているようです。

パターン3: チェックモード

ドキュメントに terraform plan したいときは Playbook をチェックモードで実行してね、と記載があります。

リソースがまだない状態から試してみます。

terraform version -json
terraform init -input=false -no-color
terraform providers schema -json
terraform show -json
terraform workspace list -no-color
terraform plan -lock=true -input=false -no-color -detailed-exitcode -out /var/folders/2s/h6djr0fn3773tj1zy4mg442c0000gn/T/tmpr0m76lku.tfplan
terraform validate
terraform show -json /var/folders/2s/h6djr0fn3773tj1zy4mg442c0000gn/T/tmpr0m76lku.tfplan
terraform output -no-color -json

やはり terraform applyがないですね。

3回目の terraform show(事後状態) がないのも特徴です。チェックモードだと実行されないようになっています。

パターン4: リソースの削除

最後は、リソースがある状態からリソースを削除するパターンです。

Playbook は以下のとおりです。

    - name: Call Terraform
      cloud.terraform.terraform:
        project_path: ./
        state: absent     # destroy 相当

表示された terraform コマンドは以下のとおりです。

terraform version -json
terraform init -input=false -no-color
terraform providers schema -json
terraform show -json
terraform workspace list -no-color
terraform plan -lock=true -input=false -no-color -detailed-exitcode -out /var/folders/2s/h6djr0fn3773tj1zy4mg442c0000gn/T/tmpu74d8r3v.tfplan -destroy
terraform validate
terraform show -json /var/folders/2s/h6djr0fn3773tj1zy4mg442c0000gn/T/tmpu74d8r3v.tfplan
terraform apply -no-color -input=false -auto-approve -lock=true /var/folders/2s/h6djr0fn3773tj1zy4mg442c0000gn/T/tmpu74d8r3v.tfplan
terraform show -json
terraform output -no-color -json

直接 terraform destroyするのではなく、terraform plan 時に -destroy オプションを付けてできた .tfplan ファイルを terraform applyしています。

Ansible としては、変更の有無を検出しながら段階をおって処理するための工夫なのかなと思います。

おわりに

実際にどんなコマンドが実行されているかわかるとスッキリしますね。

今回はとてもシンプルなPlaybookで試しましたが、例えば、variables を指定したり workspace を指定があるときは色々変化があって、確認するとおもしろいかもしれません。