ChatGPTでvSphereの自動化を試してみる

## はじめに
* クラウドを使う側ではなく、作る側の仕事をしているインフラエンジニアのhiroki783です。
* ChatGPTのCodeCaptureが信じられないぐらい凄いと言う噂を聞いたので、レアケースであろうvSphereの自動化(pyvmomi)を試してみました。


## 1. VMのpowerON
* まずは人が書くとしたら簡単な部類の、chatGPT-testと名前のVMのpowerONです。

### chatGPT
* 紫のアイコンが、私の入力
* 緑のアイコンが、chatGPTからの返答です。
* 今回は英文のみで日本語でも可能かどうかは未確認です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3113848/70431f31-2d18-5f47-1ddb-b08294451cdd.png)
### code
- chatGPTが生成したコード + 認証情報を自分で付与
```python
from pyVim.connect import SmartConnect
from pyVmomi import vim

def power_on_vm(si, name):
    content = si.RetrieveContent()
    vm = None
    container = content.rootFolder
    viewType = [vim.VirtualMachine]
    recursive = True
    containerView = content.viewManager.CreateContainerView(container, viewType, recursive)
    for c in containerView.view:
        if c.name == name:
            vm = c
            break
    if vm:
        task = vm.PowerOn()
        return task
    else:
        return None

# 認証情報だけ追加した
si = SmartConnect(
    host="v10-vcsa-01.lab.local",
    user="administrator@vsphere.local",
    pwd="***",
    disableSslCertValidation=True
)

# power on vm named "chatGPT-test"
task = power_on_vm(si, "chatGPT-test")

# wait for the task to complete
if task:
    task.wait()
else:
    print("Virtual machine not found.")
```
### 結果
* 最後のpowerONのtaskに`wait()`methodが無いと怒られていますが、それ以外は完璧に動作しています。
* これをAIが生成したと言うのですから、意味が分からなくなってきますね。。。
```
$ python chatGPT-sample1.py
Traceback (most recent call last):
  File "/root/projects/tmp/s.py", line 31, in <module>
    task.wait()
    ^^^^^^^^^
AttributeError: 'vim.Task' object has no attribute 'wait'
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3113848/633128b7-dfd8-45ae-598d-d6b40b4e3bad.png)

## 2. CD/DVDが接続されているVMを抽出
* VMのpowerONするscriptが自動で生成されるだけでも驚きですが、更に難易度を上げて特殊なVMの抽出を試してみます。
* ストレージを空にしたと思ったのにCD/DVDが接続されているVMが隠れて存在し、ストレージを切断できないという状況がvSphere運用中にたまに見かけます。
* その際に1つ1つVMの詳細を見て、CD/DVDがついているか判断するのは非常に大変なのでこれも自動化を試してみましょう。
### chatGPT
　　　　　![スクリーンショット 2023-01-15 21.29.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3113848/6a674881-2735-db1c-2d88-446f21ae10a0.png)
### code
- chatGPTが生成したコード + 認証情報を自分で付与
```python
from pyVim.connect import SmartConnect
from pyVmomi import vim


def get_vm_cd(si):
    content = si.RetrieveContent()
    for child in content.rootFolder.childEntity:
        if hasattr(child, 'vmFolder'):
            datacenter = child
        else:
            datacenter = None
    vm_folder = datacenter.vmFolder
    vms = vm_folder.childEntity
    for vm in vms:
        devices = vm.config.hardware.device
        for device in devices:
            if isinstance(device, vim.vm.device.VirtualCdrom) and device.connectable.connected:
                print(vm.config.name)

# 認証情報だけ追加した
si = SmartConnect(
    host="v10-vcsa-01.lab.local",
    user="administrator@vsphere.local",
    pwd="***",
    disableSslCertValidation=True)
get_vm_cd(si)
```
### 結果
* こちらも驚くべきことに問題なく取得できています。
* ただしvm用のfolderが存在するとエラーが出たりと、お手持ちのvSphere環境によって左右される部分があるので注意は必要です。
* (またより良いものはpowerOFFVMもcheckできる`config.hardware.device[16000].backing.fileName`ですが）
* とはいえ、自動化の参考にするには十分すぎる出来です。
```
$ python chatgpt_sample2.py 
chatGPT-test
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3113848/35c0fa93-0aee-a721-8171-a46d918b61b5.png)

## 3. VMの作成
* 最後に最難関と思われるVMの作成です。
* GUIから実施すると簡単なVMの作成ですが、APIを使うとVMの詳細設定1つ1つ入力する必要があるので慣れていても非常に難しいです。
* pyvmomiでVMを作りたい場合はこちらのブログ([pyvmomiで仮想マシンを作成してみる](https://sky-joker.tech/2016/12/24/pyvmomiで仮想マシンを作成してみる/))を参考にするのがおすすめです。
### chatGPT
- 長いので、一部のみの紹介です。(全文は以下のcodeを参照ください)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3113848/a59073a8-6b8b-747d-cefb-d34d62e939c9.png)
### code
- chatGPTが生成したコード(何も変更を加えていません)
```python
from pyVim.connect import SmartConnect
from pyVmomi import vim

def create_vm(si, name, num_cpus, memory_mb, disk_gb, guestId):
    content = si.RetrieveContent()
    datacenter = content.rootFolder.childEntity[0]
    vm_folder = datacenter.vmFolder
    datastore = datacenter.datastore[0]
    resource_pool = datacenter.hostFolder.childEntity[0].resourcePool

    config = vim.vm.ConfigSpec()
    config.numCPUs = num_cpus
    config.memoryMB = memory_mb
    config.files = vim.vm.FileInfo(logDirectory=None,
                                   snapshotDirectory=None,
                                   suspendDirectory=None,
                                   vmPathName="["+datastore.name+"] "+name+"/"+name+".vmx")
    config.guestId = guestId 
    #create virtual disk
    controller = vim.vm.device.VirtualLsiLogicController()
    disk_spec = vim.vm.device.VirtualDeviceSpec()
    disk_spec.fileOperation = "create"
    disk_spec.operation = vim.vm.device.VirtualDeviceSpec.Operation.add
    disk_spec.device = vim.vm.device.VirtualDisk()
    disk_spec.device.backing = vim.vm.device.VirtualDisk.FlatVer2BackingInfo()
    disk_spec.device.backing.diskMode = 'persistent'
    disk_spec.device.backing.fileName = "["+datastore.name+"] "+name+"/"+name+".vmdk"
    disk_spec.device.unitNumber = 0
    disk_spec.device.capacityInKB = disk_gb * 1024 * 1024
    disk_spec.device.controllerKey = controller.key
    config.deviceChange = [disk_spec]

    vm_create_task = vm_folder.CreateVM_Task(config=config, pool=resource_pool)
    return vm_create_task

si = SmartConnect()

# create a Ubuntu vm with 1 vCPU, 100MB memory and 1GB disk
vm = create_vm(si, "vm", 1, 100, 1024, 'ubuntu64Guest')

# wait for the task to complete
vm.wait()
```

### 結果
- さすがに今回はうまくいかずいくつか問題点があります。
- 問題点1
    - 作成するVM名を指定する必須optionの`config.name`がないので作成に失敗する。
    - chatGPTに明確に名前を伝えることで改善するかも知れません。
- 問題点2
    - SCSI controllerを作成するscriptが無いため、diskの作成に失敗する。
    - 既に存在するVMにdiskを追加する場合には、改めてSCSI controllerを作る必要はないので、chatGPTがこちらの方法を参照しているような気がします。
- 問題点3
    - commentには1GB diskを作成したと記載がありますが、(そもそもコメントも自動生成されるのが驚きですが。。。)実際は1024GBとなっており、単位のずれが生じています。


### 結果(修正版)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3113848/c9533d50-c357-7471-d3da-1081c731e067.png)
- これでVMが作成できるようになりますが、実際にはnicの追加等も必要になるので更にコードとしては大変になります。
- ちなみにnicの追加まで含めてchatGPTにお願いすると、timeoutになり途中でコード生成が止まってしまいました。
```python
from pyVim.connect import SmartConnect
from pyVmomi import vim


def create_vm(si, name, num_cpus, memory_mb, disk_gb, guestId):
    content = si.RetrieveContent()
    datacenter = content.rootFolder.childEntity[0]
    vm_folder = datacenter.vmFolder
    datastore = datacenter.datastore[0]
    resource_pool = datacenter.hostFolder.childEntity[0].resourcePool

    config = vim.vm.ConfigSpec()
    config.numCPUs = num_cpus
    # [自分で修正]　vm名を追加
    config.name = name
    config.memoryMB = memory_mb
    config.files = vim.vm.FileInfo(logDirectory=None,
                                   snapshotDirectory=None,
                                   suspendDirectory=None,
                                   vmPathName="[" + datastore.name + "] " + name + "/" + name + ".vmx")
    config.guestId = guestId

    # [自分で修正]　ParaVirtualSCSIControllerの作成を追加
    pvc_spec = vim.vm.device.VirtualDeviceSpec()
    pvc_spec.operation = vim.vm.device.VirtualDeviceSpec.Operation.add
    pvc_spec.device = vim.vm.device.ParaVirtualSCSIController()
    pvc_spec.device.sharedBus = vim.vm.device.VirtualSCSIController.Sharing.noSharing
    config.deviceChange = [pvc_spec]

    # create virtual disk
    controller = vim.vm.device.VirtualLsiLogicController()
    disk_spec = vim.vm.device.VirtualDeviceSpec()
    disk_spec.fileOperation = "create"
    disk_spec.operation = vim.vm.device.VirtualDeviceSpec.Operation.add
    disk_spec.device = vim.vm.device.VirtualDisk()
    disk_spec.device.backing = vim.vm.device.VirtualDisk.FlatVer2BackingInfo()
    disk_spec.device.backing.diskMode = 'persistent'
    disk_spec.device.backing.fileName = "[" + datastore.name + "] " + name + "/" + name + ".vmdk"
    disk_spec.device.unitNumber = 0
    disk_spec.device.capacityInKB = disk_gb * 1024 * 1024
    disk_spec.device.controllerKey = controller.key
    # [自分で修正]　deviceChange:list に追加する形に
    config.deviceChange.append(disk_spec)

    vm_create_task = vm_folder.CreateVM_Task(config=config, pool=resource_pool)
    return vm_create_task


# [自分で修正]　認証情報を追加
si = SmartConnect(
    host="v10-vcsa-01.lab.local",
    user="administrator@vsphere.local",
    pwd="***",
    disableSslCertValidation=True)


# create a Ubuntu vm with 1 vCPU, 100MB memory and 1GB disk
# [自分で修正]　disk-sizeを1024GB → 1GBへ
vm = create_vm(si, "vm", 1, 100, 1, 'ubuntu64Guest')
```

## まとめ
- 話題のchatGPTを使ってみましたが、100点とは行かないものの、80点ぐらいのコードを生成してくれるという衝撃的な結果でした。
- これが将来のITツールになると考えると、近未来ではエンジニアをサポートするツールに
    - より洗練されたcodeのsuggestion
    - コードを軽く忘れた時のsnippet代わり
    - 新人の教育ツールとして
- 遠未来では、エンジニアが要らない or 1/10で良いような世界に
    - chatGPT(AI)を前提とした、プログラミング言語の発展
    - 今回のような曖昧さが消えた、100点のコード生成
- どうなるにしても、インフラエンジニアのようにAIとはちょっと離れていても、気にせずにはいられなそうです。