ESXi上でvim-cmdを使ってVM操作するAnsibleコレクション (無償ライセンス利用可)

本記事は「[エーピーコミュニケーションズ Advent Calendar 2020](https://qiita.com/advent-calendar/2020/ap-com)」の4日目のエントリとなります。
今年入社しまして自動化とコンテナをいろいろ頑張りたいです。よろしくお願いします。

2020.12.16追記: コレクション作成と公開の記事へのリンク追加 ([こちら](https://qiita.com/zaki-lknr/items/4771b65b2385591e0678))

# 概要

ESXiのSSH機能を使ってVM作成などの操作を行うAnsibleコレクションを作ってみました。
無償ライセンスのESXiでも使えます。

[Ansible Galaxy / esxissh - VM operation on ESXi with enabled SSH](https://galaxy.ansible.com/zaki_lknr/esxissh)

Python3で動作し、Ansible 2.9以上、ESXiは6.5と6.7で動作確認しています。
また、SSH接続用に[Parmiko](http://www.paramiko.org/)を使用するのでAnsible実行ノードに`pip`で別途インストールしてください。

※ まだ「とりあえず最低限VMができる」くらいなので、利用の際ははあくまで検証用でお願いします。

ソースはGitHubにあります。
[Ansible Collection - zaki_lknr.esxissh](https://github.com/zaki-lknr/esxissh-ansible)

モジュール作成の練習をしてたらいい感じになってきたのでコレクションとして公開してみました。

本記事ではこのコレクションの使い方と仕組みについて記載します。
作った自作モジュールをコレクション構成にしてGalaxyに公開する内容については、以下にまとめました。

[[Ansible] 自作のコレクションを作ってGalaxyで公開するまで - Qiita](https://qiita.com/zaki-lknr/items/4771b65b2385591e0678)

# 使い方

## (準備)ESXi設定

ESXiのSSHを有効にします。
このコレクションで使うモジュールは、ESXiにSSH接続してから処理を行います。

![20200910214002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256859/341560e8-f7e6-7711-dda0-7255457a144c.png)

## (準備)Paramikoインストール

```
pip install paramiko
```

## コレクションインストール

```
ansible-galaxy collection install zaki_lknr.esxissh
```

デフォルトで`$HOME/.ansible`以下にインストールされるので、venv環境の場合は、他の環境と混ざらないように[`collections_path`を使ってコレクションパスをvenv環境内に設定](https://docs.ansible.com/ansible/latest/reference_appendices/config.html#collections-paths)しておくと良いです。

## playbook例

以下のようなplaybookでVM作ったり出来ます。
(基本的に[vmware_guestで使うplaybookベース](https://docs.ansible.com/ansible/latest/collections/community/vmware/vmware_guest_module.html#id5)に、ESXiだと不要な`datacenter`や`folder`などを省略しています)

`esxiaddr`や`esxiuser`などは、環境に合わせてinventory変数などを参照するようにしてください。
VMの削除は`state: absent`で可能です。

```yaml:playbook.yml
- hosts: localhost
  gather_facts: no

  tasks:
  - name: create vm
    zaki_lknr.esxissh.esxissh_guest:
      esxiaddress: '{{ esxiaddr }}'
      esxiusername: '{{ esxiuser }}'
      esxipassword: '{{ esxipass }}'
      name: example
      guest_id: centos7_64Guest
      datastore: datastore1
      hardware:
        memory_mb: 4096
        num_cpus: 2
      networks:
        - name: VM Network
          device_type: vmxnet3
        - name: private-network-1
          device_type: vmxnet3
      disk:
        - size_gb: 40
          type: thin
        - size_gb: 20
          type: eagerzeroedthick
      cdrom:
        - type: iso
          iso_path: cheddar-share/disk2/archive/iso/CentOS-7-x86_64-Minimal-1908.iso
        - type: iso
          iso_path: cheddar-share/disk2/archive/iso/CentOS-8.2.2004-x86_64-minimal.iso
      state: present
```

現時点で、電源on/off・VM作成/削除に対応しています。[サンプルのplaybook](https://github.com/zaki-lknr/esxissh-ansible/tree/main/sample-playbook)を参考にしてください。

実行するとこんな感じになります。  
(`eagerzeroedthick`で20GBプロビジョニングすると時間がかかるので↑からは除きました)

```
(2.10) [zaki@cloud-dev sample-playbook (main)]$ ansible-playbook -i inventory.ini create_vm.yml -v
Using /home/zaki/src/esxi-ansible/sample-playbook/ansible.cfg as config file
[WARNING]: provided hosts list is empty, only localhost is available. Note that
the implicit localhost does not match 'all'

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

TASK [create vm] ***************************************************************
changed: [localhost] => changed=true 
  cdrom:
  - iso_path: cheddar-share/disk2/archive/iso/CentOS-7-x86_64-Minimal-1908.iso
    type: iso
  - iso_path: cheddar-share/disk2/archive/iso/CentOS-8.2.2004-x86_64-minimal.iso
    type: iso
  datastore: WDS100T2B0A
  disk:
  - size_gb: 10
    type: thin
  guest_id: centos7_64Guest
  hardware:
    memory_mb: 4096
    num_cpus: 2
  name: vm-example
  networks:
  - device_type: vmxnet3
    name: VM Network
  - device_type: vmxnet3
    name: private-network-1

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

(2.10) [zaki@cloud-dev sample-playbook (main)]$ 
```

作成されたVM

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256859/5e7e584f-ba1a-60b2-c75b-4c0fbea807ff.png)

基本的に以上なのですが、簡単に趣旨と仕組みを解説します。

# ESXiの無償ライセンス

無償でも利用できるESXi、個人の検証環境用などに使用されている方は多いのではないでしょうか。
ただし[無償ライセンスの制限として、write系のAPIが使用できない](https://zaki-hmkc.hatenablog.com/entry/2019/10/02/075333)という縛りがあります。
これはつまり、[`govc`](https://github.com/vmware/govmomi/tree/master/govc)や[`vmware_guest`](https://docs.ansible.com/ansible/latest/collections/community/vmware/vmware_guest_module.html)などのツールを使って「VMを作ったり」「VMの設定を変更したり」「VMの電源on/offを制御したり」することができません。(VMの情報を参照するくらいはできます。スクリーンショット取得も実は可能)

ちなみに無償ライセンスを適用する前であれば、期間限定の評価ライセンス状態となり、[60日間はwrite系のAPIも使用できます](https://zaki-hmkc.hatenablog.com/entry/2020/08/26/080404)。

以前は[vsphere_guestというAnsibleモジュールを使えば無償ライセンスでもゲストOS操作が出来ました](https://zaki-hmkc.hatenablog.com/entry/2019/10/15/071344)が、現在はメンテナンスされておらず、deprecatedのためAnsible 2.9で削除され、Python3でも動作しません。

# ESXiのCLIツール

普段ESXi使ってる方は、webの画面からぽちぽちと操作してVM管理をするか、無償ライセンスでなければpyVmomiやPowerCLIなどを使った自動化ツールを使用しているかと思いますが、実は[ESXiの内蔵SSHを有効にしてログインすると、`vim-cmd`というCLIツールを使って__ある程度の__VM操作が可能](https://zaki-hmkc.hatenablog.com/entry/2020/09/10/215454)です。

引数無しで実行すると、サブコマンド(末尾に`/`が付いていてディレクトリ名に見えるけどサブコマンド)一覧が出力されます。

```
[root@localhost:~] vim-cmd
Commands available under /:
hbrsvc/       internalsvc/  solo/         vmsvc/
hostsvc/      proxysvc/     vimsvc/       help
```

作成済みVMの定義ファイル関連は`/vmfs/volumes/<datastore>`以下にあります。
このディレクトリ配下に「VM名のサブディレクトリ」があり、そのサブディレクトリ内にVMの定義ファイル類があります。

VM定義ファイル: `<vmname>.vmx`
ディスクイメージ: `<任意のファイル名>.vmdk`

今回作成したAnsibleコレクションは、この`vim-cmd`コマンドを使ってVM操作を行っています。

`vim-cmd`コマンドは情報が少ないので、使っているコマンドを一通り説明します。
なお、文中の`WDS100T2B0A`は私の手元の環境のデータストア名です。

## VM作成

VM作成というより、名前の通りダミーのVMを作成します。

```
[root@localhost:~] vim-cmd vmsvc/createdummyvm
Insufficient arguments.
Usage: createdummyvm vm_name datastore_path [hw_version]

Create a pre-configured dummy vm.

```

このコマンドでvmxファイルが生成されESXi上にもVMが登録されます。
が、ほぼほぼ設定無しの以下のスペックのskelton状態なので、いろいろと定義追加してあげる必要があります。

- 1 vCPU
- RAM 32 MB
- HDD 1 MB
- OS種別はother

ダミーVMの作成に成功すると、VMIDという一意の番号が出力されます。

```
[root@localhost:~] vim-cmd vmsvc/createdummyvm example /vmfs/volumes/WDS100T2B0A/
253
```

VMに対する操作をコマンドで実行する際は、このVMIDが必要になります。

1点注意点があり、webの画面だと出来ない「同じ名前のVMの作成ができてしまう」点があります。
同じ名前のVMを作成すると`<vmname>_1/<vmname>_1.vmx`というファイル構成になり、webの画面だと見分けがつきづらいので、使わない方が良いでしょう。

![2020-12-01_09h04_12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256859/74a28831-4df2-8743-d964-af65b68100c5.png)

## VMIDの一覧取得

ESXi上の全VMのID・ファイルパス、ゲストOS種別などの一覧を取得するコマンドです。

```
[root@localhost:~] vim-cmd vmsvc/getallvms
Vmid              Name                                                 File                                          Guest OS       Version   Annotation
:
:
250    vm-example                    [WDS100T2B0A] vm-example/vm-example.vmx                                     centos7_64Guest    vmx-14
253    example                       [WDS100T2B0A] example/example.vmx                                           otherGuest         vmx-14
254    example                       [WDS100T2B0A] example_1/example_1.vmx                                       otherGuest         vmx-14
:
:
```

単純にスペースで区切って取り出そうとすると、VM名にスペースが入っていると分断されてしまうので注意。

## vmxファイル状態のリロード

`vim-cmd`を使ってVM定義を更新した場合は即時ESXi上に反映されますが、VMの定義ファイルであるvmxファイルを直接編集した場合は、手動で変更内容を反映させる必要があります。

```
[root@localhost:~] vim-cmd vmsvc/reload 253
```

実行すると、対象VMのvmxファイルの内容がESXiに反映され、webの画面でも変更内容を確認できるようになります。

## CPU/メモリ設定

あいにく設定用のコマンドを見つけられませんでした。
よって、vmxファイルを直接編集して設定します。

といっても、既存の作成済みvmxファイルを参考に、CPUとメモリの設定行を真似すれば問題ないです。

```ini:vmxファイル設定例
numvcpus = "2"
memSize = "4096"
```

ただし、vmxファイルを手動編集しただけだとESXiが変更内容を認識しないため「リロード」してESXiに認識させる必要があります。
また、vmxファイルを手動編集したあとにリロードをせずに、後述の「NIC追加のコマンド」などを実行すると、ESXiが認識している状態の編集前の内容で上書きされます。

## ゲストOS設定

OS種別の設定もコマンドが見つかりませんでした。
ので、これもvmxファイルを直接編集します。

例えば「CentOS 7 (64 ビット)」を指定した場合のvmxファイルは以下の通り。

```
guestOS = "centos7-64"
```

ただし、ゲストOSを表す文字列はちょっと注意が必要で、APIを使う場合のゲストOSのID文字列と、実際にvmxファイルに出力される文字列が異なります。

例えば、前述同様にCentOS 7 (x64)であれば、`centos7_64Guest`になります。

[VirtualMachineGuestOsIden.. - vSphere Web Services API - VMware {code}](https://code.vmware.com/apis/358/doc/vim.vm.GuestOsDescriptor.GuestOsIdentifier.html)

例えばこんな感じです。

| guestOS        | API                   | description                               |
| -------------- | --------------------- | ----------------------------------------- |
| centos         | centosGuest           | CentOS 4/5 x32                            |
| centos-64      | centos64Guest         | CentOS 4/5 x64                            |
| centos7-64     | centos7_64Guest       | CentOS 7 x64                              |
| coreos-64      | coreos64Guest         | CoreOS Linux                              |
| other-64       | otherGuest64          | Other x64                                 |
| other          | otherGuest            | Other x32                                 |
| rhel2          | rhel2Guest            | RHEL 2.1                                  |
| rhel3          | rhel3Guest            | RHEL 3                                    |
| rhel3-64       | rhel3_64Guest         | RHEL 3 x64                                |
| rhel7-64       | rhel7_64Guest         | RHEL 7 x64                                |
| ubuntu         | ubuntuGuest           | Ubuntu x32                                |
| ubuntu-64      | ubuntu64Guest         | Ubuntu x64                                |
| windows9-64    | windows9_64Guest      | Windows 10 x64                            |
| windows8-64    | windows8_64Guest      | Windows 8 x64                             |
| windows7srv-64 | windows7Server64Guest | Microsoft Windows Server 2008 R2 (64 ビット) |
| windows8srv-64 | windows8Server64Guest | Microsoft Windows Server 2012 (64 ビット)    |
| windows9srv-64 | windows9Server64Guest | Microsoft Windows Server 2016 以降 (64 ビット) |
| vmkernel65     | vmkernel65Guest       | VMware ESX 6.5                            |

[guest_idに指定するGuestOSのidが内部ファイルで使用するものになっている · Issue #3 · zaki-lknr/esxissh-ansible](https://github.com/zaki-lknr/esxissh-ansible/issues/3)

## NIC追加

NICの追加は`vmsvc/devices.createnic`で出来ます。

```
[root@localhost:~] vim-cmd vmsvc/devices.createnic
Insufficient arguments.
Usage: devices.createnic vmid adapter-type network-id [network-type]

Add a NIC to this virtual machine.
```

ESXiをインストールしたときにデフォルトで作成される`VM Network`をVMに追加するには以下の通り。

```
[root@localhost:~] vim-cmd vmsvc/devices.createnic 253 "vmxnet3" "VM Network"
```

これでvmxファイルに以下の定義が追加されます。

```ini:vmxファイル内NIC設定
ethernet0.virtualDev = "vmxnet3"
ethernet0.networkName = "VM Network"
ethernet0.uptCompatibility = "TRUE"
ethernet0.present = "TRUE"
```

別のNICを追加する場合は続けて実行すればよく、アダプタ番号は追加順に自動で割り当てられます。

```
[root@localhost:~] vim-cmd vmsvc/devices.createnic 253 "vmxnet3" "restricted-network-1"
```

```ini:vmxファイル内NIC設定
ethernet1.virtualDev = "vmxnet3"
ethernet1.networkName = "restricted-network-1"
ethernet1.uptCompatibility = "TRUE"
ethernet1.present = "TRUE"
```

ポートグループ自体の作成までは調べてないので機会があれば…(あるのかな？)

## ディスク管理

ディスク自体(vmdkファイル)の操作と、VMの定義のvmxファイル内におけるディスク定義の操作の2種類があります。

### vmdkファイル

vmdkファイルを作ったり削除するには`vmkfstools`コマンドを使います。
VM用のファイル操作は主に「OPTIONS FOR VIRTUAL DISKS」の部分です。

```
[root@localhost:~] vmkfstools
No valid command specified

:
:

OPTIONS FOR VIRTUAL DISKS:

vmkfstools -c --createvirtualdisk #[bBsSkKmMgGtT]
               -d --diskformat [zeroedthick
                               |thin
                               |eagerzeroedthick
                               ]
               -a --adaptertype [deprecated]
               -W --objecttype [file|vsan|vvol|pmem|upit]
               --policyFile <fileName>
           -w --writezeros
           -j --inflatedisk
           -k --eagerzero
           -K --punchzero
           -U --deletevirtualdisk
           -E --renamevirtualdisk srcDisk
           -i --clonevirtualdisk srcDisk
               -d --diskformat [zeroedthick
                               |thin
                               |eagerzeroedthick
                               |rdm:<device>|rdmp:<device>
                               |2gbsparse]
               -W --object [file|vsan|vvol]:
:
```

#### vmdkファイル削除

`vim-cmd vmsvc/createdummyvm`でVMと一緒に作成された(平たく言うと使い道のない)32MBのvmdkファイルを削除するには、フルパスでvmdkファイル(`-flat`ではない方)を指定します。

```
[root@localhost:~] ls -l /vmfs/volumes/WDS100T2B0A/example/*vmdk
-rw-------    1 root     root       1048576 Dec  1 00:00 /vmfs/volumes/WDS100T2B0A/example/example-flat.vmdk
-rw-------    1 root     root           439 Dec  1 00:00 /vmfs/volumes/WDS100T2B0A/example/example.vmdk
[root@localhost:~] ls -1 /vmfs/volumes/WDS100T2B0A/example/
example-flat.vmdk
example.vmdk
example.vmsd
example.vmx
[root@localhost:~] vmkfstools --deletevirtualdisk /vmfs/volumes/WDS100T2B0A/example/example.vmdk
[root@localhost:~] ls -1 /vmfs/volumes/WDS100T2B0A/example/
example.vmsd
example.vmx
```

#### vmdkファイル作成

新しくディスクを作成するには`vmkfstools --createvirtualdisk`を使用します。
5GBの`thin`プロビジョニングであれば以下の通り。
作成先のフルパスも必要です。

```
[root@localhost:~] vmkfstools --createvirtualdisk 5GB --diskformat thin /vmfs/volumes/WDS100T2B0A/example/example_0.vmdk
Create: 100% done.
[root@localhost:~] ls -1l /vmfs/volumes/WDS100T2B0A/example/
total 0
-rw-r--r--    1 root     root             0 Dec  1 00:00 example.vmsd
-rwxr-xr-x    1 root     root          1278 Dec  1 00:07 example.vmx
-rw-------    1 root     root     5368709120 Dec  1 00:33 example_0-flat.vmdk
-rw-------    1 root     root           474 Dec  1 00:33 example_0.vmdk
```

ちなみにディスク(vmdkファイル)の作成も削除も、ディスク自体のファイル操作になり、VMの設定(vmxファイル内定義)には影響しないので、別途更新する必要があります。

### ディスク定義

vmxファイルの下記定義を操作します。

```ini:vmxファイル内ディスク設定
scsi0:0.deviceType = "scsi-hardDisk"
scsi0:0.fileName = "example.vmdk"
scsi0:0.present = "TRUE"
```

#### 定義の削除

`vim-cmd vmsvc/device.diskremove`を使用します。

```
[root@localhost:~] vim-cmd vmsvc/device.diskremove
Insufficient arguments.
Usage: device.diskremove vmid controller_number unit_number delete_file [controller_type]

Remove a disk from this virtual machine. If controller type is not set, the command will look for a SCSI disk.

```

実行にはコントローラ番号とユニット番号の指定に加えて、ファイル名も指定する必要があります。
`scsiX:Y`の場合、コントローラ番号が`X`でユニット番号は`Y`です。

```
[root@localhost:~] vim-cmd vmsvc/device.diskremove 253 0 0 example.vmdk
```

これで`scsi0:0`の定義が削除されます。

#### 定義の追加(既存ディスク設定)

作成済みvmdkをVMに追加するには`vim-cmd vmsvc/device.diskaddexisting`を使用します。

```
[root@localhost:~] vim-cmd vmsvc/device.diskaddexisting
Insufficient arguments.
Usage: device.diskaddexisting vmid disk_file controller_number unit_number [ctlr_type]

Add an existing disk to this virtual machine. If controller type is not set, the command will create a SCSI disk.

```

削除と同様、コントローラ番号とユニット番号を指定します。
NICのように「追加した順番に番号が自動で割り振られる」ことはないので、手動で採番が必要です。

```
[root@localhost:~] vim-cmd vmsvc/device.diskaddexisting 253 /vmfs/volumes/WDS100T2B0A/example/example_0.vmdk 0 0
[root@localhost:~]
```

```ini:vmxファイル内ディスク設定
scsi0:0.deviceType = "scsi-hardDisk"
scsi0:0.fileName = "example_0.vmdk"
scsi0:0.present = "TRUE"
```

2台目のディスクは`unit_number`を増やしていけばOK

```
[root@localhost:~] vim-cmd vmsvc/device.diskaddexisting 253 /vmfs/volumes/WDS100T2B0A/example/example_1.vmdk 0 1
```

```ini:vmxファイル内ディスク設定
scsi0:1.deviceType = "scsi-hardDisk"
scsi0:1.fileName = "example_1.vmdk"
scsi0:1.present = "TRUE"
```

## CD/DVD追加

たとえばデータストア上にあるisoファイルのマウント設定はvmxファイルでは、設定済みのVMの定義を見ると以下の通り。

```ini:vmxファイル内CD/DVD設定
ide1:0.deviceType = "cdrom-image"
ide1:0.fileName = "/vmfs/volumes/6d9f7290-6ab63077-0000-000000000000/disk2/archive/iso/CentOS-7-x86_64-Minimal-1908.iso"
ide1:0.present = "TRUE"
```

残念ながら`deviceType: cdrom-iamge`として設定を追加するコマンドは見つけられなかった。
(`vim-cmd vmsvc/device.diskaddexisting`もオプションの引数に`ide`を指定すれば`ide1:0`の部分は設定できるけど、`deviceType`の設定がわからなかった)

よってここは手動で編集してリロード。

なお、設定済みVMを見るとデータストアのパスがUUIDのようになってますが、普通に`/vmfs/volumes/<datastore>/path/to/foobar-image.iso`で認識します。

## VM削除

VMの削除は`vim-cmd vmsvc/destroy`で出来ます。

```
[root@localhost:~] vim-cmd vmsvc/destroy
Insufficient arguments.
Usage: destroy vmid

Deletes the vm.

```

VMIDを指定して実行すれば特に何も出力されず、シュッと消えます。
(`echo $0`すれば`0`を確認できます)

```
[root@localhost:~] vim-cmd vmsvc/destroy 254
```

## 電源操作

### 電源on

`vim-cmd vmsvc/power.on`を使用します。

```
[root@localhost:~] vim-cmd vmsvc/power.on 253
Powering on VM:
```

### 電源off

`vim-cmd vmsvc/power.off`を使用します。
ESXiのwebの画面での「パワーオフ」操作なので、いわゆる強制電源オフです。

```
[root@localhost:~] vim-cmd vmsvc/power.off 253
Powering off VM:
```

### シャットダウン

`vim-cmd vmsvc/power.shutdown`を使用します。
OSのシャットダウンを行うので、VM上にVMware Toolsが必要です。
無い場合はエラーになります。

```
[root@localhost:~] vim-cmd vmsvc/power.shutdown 253
(vim.fault.ToolsUnavailable) {
   faultCause = (vmodl.MethodFault) null,
   faultMessage = <unset>
   msg = "Received SOAP response fault from [<cs p:0000002122005370, TCP:localhost:8307>]: shutdownGuest
Cannot complete operation because VMware Tools is not running in this virtual machine."
}
```

### 電源状態の取得

`vim-cmd vmsvc/power.getstate`を使用します。

```
[root@localhost:~] vim-cmd vmsvc/power.getstate 253
Retrieved runtime info
Powered off
[root@localhost:~] vim-cmd vmsvc/power.getstate 106
Retrieved runtime info
Powered on
```

# コレクション化について

以下の記事にまとめました。
[[Ansible] 自作のコレクションを作ってGalaxyで公開するまで - Qiita](https://qiita.com/zaki-lknr/items/4771b65b2385591e0678)

# まとめ

ESXiのSSHを有効にするという「穴あけ」は必要ですが、SSH接続して直接ファイルを操作することで大抵のことは操作可能なので、良い感じにパッケージングできるという例でした。
今回はCLIツールを内部で操作するAnsibleコレクションを使うことで、無償ライセンスでは難しくなってしまったVM作成や操作の自動化ができるようになりました。

作成したVMはOSは入っていませんが、そちらはkickstartインストールなどで自動化しましょう。

# 参考情報

- [community.vmware.vmware_guest – Manages virtual machines in vCenter — Ansible Documentation](https://docs.ansible.com/ansible/latest/collections/community/vmware/vmware_guest_module.html)
- [VMware ESXiをSSHでがんばるぞい(コマンドライン操作色々) - Qiita](https://qiita.com/binzume/items/096ce77f73b6e853c342)
- [[ESXi / Ansible] ssh接続してvmi-cmdを使ったVM操作が可能かお試し - zaki work log](https://zaki-hmkc.hatenablog.com/entry/2020/09/10/215454)
- [[VMware / Ansible] 評価版ライセンスのESXiにvmware_guestモジュールを使ってVMを作成する - zaki work log](https://zaki-hmkc.hatenablog.com/entry/2020/08/26/080404)
- [［Ansible］ deprecatedになってるvsphere_guestを使ってESXi上でVMを自動生成する - zaki work log](https://zaki-hmkc.hatenablog.com/entry/2019/10/15/071344)
- [vsphere_guest – Create/delete/manage a guest VM through VMware vSphere — Ansible Documentation](https://docs.ansible.com/ansible/2.8/modules/vsphere_guest_module.html)