はじめに
azure.azcollection.azure_rm_virtualmachineモジュールの generalized
オプションを利用すると、VMを generalize できます。
Azure CLI でいう az vm generalize
、PowerShell でいうSet-AzVm -Generalized
です。(後述しますが、VMの状態遷移の挙動が微妙に異なります)
このモジュールは多機能でオプションも多く、モジュールの公式ドキュメント上も generalize する例も掲載されていなかったため、試行錯誤してしまいました。
せっかくですのでまとめておきます。
- 動作確認環境
- ansible 5.1.0 (ansible-core 2.12.1)
- azure.azcollection collection 1.10.0
- VM の OS は Windows
基本形
Widows の VM を sysprep /generalize /oobe /shutdown
して、OSがシャットダウンされたあとに実行するシナリオです。そのため VM の状態は「停止済み」の想定です。「停止済み (割り当て解除)」ではありません。
generalize するタスクは以下のとおりです。
- name: generalize vm
azure.azcollection.azure_rm_virtualmachine:
resource_group: "{{ resource_name }}"
name: "{{ vm_name }}"
started: false
generalized: true
generalized: true
が一番のポイントです。started: false
は、VMを起動状態にしない指定です。
実行後、az vm get-instance-view
で状態を確認すると code: OSState/generalized
が表れます。
$ az vm get-instance-view -g rg-test -n win01 --query instanceView.statuses -o yaml
- code: OSState/generalized
displayStatus: VM generalized
level: Info
message: null
time: null
- code: ProvisioningState/succeeded
displayStatus: Provisioning succeeded
level: Info
message: null
time: '2021-12-29T08:35:21.523725+00:00'
- code: PowerState/stopped
displayStatus: VM stopped
level: Info
message: null
time: null
azure.azcollection.azure_rm_virtualmachine_info
モジュールで状態を取得すると、power_state
は generalized
となりました。
VMの状態と azure_rm_virtualmachine モジュールの generalized: true
の関係まとめ
azure_rm_virtualmachine モジュールの generalized: true
を指定するだけで、必ず generalized されるとは限りません。事前の VM の状態や started
オプションの指定の仕方によって、generalized: true
が効かないパターンがあります。モジュールのコードをデバッグしながら実行して検証した結果を、以下のようにまとめました。
パターン |
事前のVMの状態 |
started オプションの値 |
動作 |
事後のVMの状態 |
備考 |
1 |
実行中 |
true (デフォルト) |
VMを停止して、generalizeする |
停止済み、generalized |
VM課金状態が続く |
2 |
実行中 |
false |
VMを停止するのみ |
停止済み |
実質 generalized: true が効かない |
3 |
停止済み |
true (デフォルト) |
VMを起動するのみ |
実行中 |
実質 generalized: true が効かない |
4 |
停止済み |
false |
VMを停止済みのまま、generalizeする |
停止済み、generalized |
前述のタスクの想定ケース、VM課金状態が続く |
5 |
停止済み (割り当て解除) |
true (デフォルト) |
VMを起動するのみ |
実行中 |
実質 generalized: true が効かない |
6 |
停止済み (割り当て解除) |
false |
VMを停止済みにして(割当解除ではなく)、generalizeする |
停止済み、generalized |
課金されない状態からされる状態に遷移する |
パターン4が、前述のタスクの実行する想定ケースです。
generalized: true
が効かないパターンがある(パターン2、3、5)
パターン2、3、5 については、generalized: true
を指定しても効きません。generalized するかどうかの判定が後ろの方にあり、その前に、実行してたら停止、停止してたら実行のような判断がされます。
課金されない状態から課金される状態に遷移するパターンがある(パターン6)
パターン6については、意外な結果で注意が必要だと思いました。generalize はされますが、VMとしては課金されない状態である「停止済み (割り当て解除)」から、課金される「停止済み」に遷移するためです。
(az vm generalize
や Set-AzVm -Generalized
は「停止済み (割り当て解除)」のまま、または「停止済み」のまま generalize するので、この点が異なります。)
モジュール内で、generalize
すると判定されると power_off_vm()
と generalize_vm()
が順に呼び出されます。power_off_vm
の実行の段階で、「停止済み (割り当て解除)」から、「停止済み」に遷移しました。
generalize と deallocate をするプレイブック
これまでの結果かから、generalize が有効なパターンでは実行後に「停止済み」になることが分かりました。VM 課金を止めるためには「停止済み (割り当て解除)」状態にする必要があります。deallocate です。deallocate には azure.azcollection.azure_rm_virtualmachine
モジュールで allocated: false
を指定します。
プレイブックとしては、generalize するタスク、deallocate するタスクのように分けて定義します。基本形と同じく「停止済み」から実行する想定です。
---
- hosts: localhost
connection: local
gather_facts: false
tasks:
- name: vm generalized
azure.azcollection.azure_rm_virtualmachine:
resource_group: "{{ resource_name }}"
name: "{{ vm_name }}"
started: false
generalized: true
- name: vm deallocate
azure.azcollection.azure_rm_virtualmachine:
resource_group: "{{ resource_name }}"
name: "{{ vm_name }}"
allocated: false
deallocate まで実行したあとの状態は以下の通りです。
% az vm get-instance-view -g rg-test -n win01 --query instanceView.statuses -o yaml
- code: OSState/generalized
displayStatus: VM generalized
level: Info
message: null
time: null
- code: ProvisioningState/succeeded
displayStatus: Provisioning succeeded
level: Info
message: null
time: '2021-12-30T02:54:28.537511+00:00'
- code: PowerState/deallocated
displayStatus: VM deallocated
level: Info
message: null
time: null
azure.azcollection.azure_rm_virtualmachine_info
モジュールで状態を取得すると、power_state
は generalized
となりました。この状態確認だと、一度 generalized すると、stopped
なのか deallocated
なのか分からないのが少々難点でしょうか。
なお、azure.azcollection.azure_rm_virtualmachine
モジュールの1つのタスクで generalized: true
とallocated: false
を両方指定してしまうと、deallocate されるだけで、generalize されないのでご注意ください。
まとめ
azure.azcollection.azure_rm_virtualmachine
モジュールは便利ですが、オプションの数が多いと依存関係がパッと見でわからなかったのがつまずいたポイントでした。
今回はデバッグしながら挙動を確認しました。
参考: [Ansible] 「つまずき Ansible 【Part19】モジュールのコードをデバッグしたい」ふりかえり - てくなべ (tekunabe)
補足
azure.azcollection.azure_rm_image
モジュール で、generalize していない VM からイメージを作成しようとすると、Generalized
になってっている必要がある、という旨のエラーが表示されます。
fatal: [localhost]: FAILED! => {"changed": false, "msg": "Error creating image win-image01 - Azure Error: OperationNotAllowed\nMessage: The operation 'Create Image' requires the Virtual Machine 'win01' to be Generalized."}
ポータル上で、generalize してない VM からイメージ作成をするときはエラーが出ずに、途中で「仮想マシンが一般化されました 」と表示されます。暗黙的に行われるようです。