はじめに #
これまで紹介したようにpyvmomiではまずESXiやVMなどのオブジェクトを取得する必要がありますが、その取得方法はMOBの階層構造を地道に探すという大変なものでした。
esxi = si.content.rootFolder.childEntity[0].hostFolder.childEntity[0].host[0]
毎回これを実行しては大変ですし、「VM名を検索して取得」「指定したcluster上のVMを全て取得」のような柔軟なオブジェクト取得をする必要もあると思います。 今回は任意のObjectを柔軟に取得する手法をいくつか紹介します。
1. searchIndexを使う #
比較的に簡単にESXiやVMを取得する方法が、searchIndex
を使用する方法です。(簡単:◎、柔軟:△)
これはMOBでServiceInstance → content → searchIndex
と辿ることで確認できる、ESXiやVMを検索するMethodsになります。公式のdocs
FindALLByIp
のようにAll
がついた関数も存在します。これは検索してhitした全てのオブジェクトをlist形式で返却してくれるだけで、基本の動作は変わらないので省略します。
FindByIp
#
IPをキーとしてESXi,VMを取得したい場合は、FindByIp
を使うことができます。
parameter | 説明 |
---|---|
datacenter | [option] 複数Datacenterが存在する場合、指定すれば検索範囲を絞り込める |
ip | [必須] 検索対象のIP |
vmSearch | [必須]検索対象をVMにする場合はTrue、 ESXiにしたい場合はFalse |
return | ESXi/VMのオブジェクト。見つからなかった場合はNone |
si = connect.SmartConnect(
host="*",
user="*",
pwd="*",
disableSslCertValidation=True)
#esxiを検索したいときはFalseに
esxi = si.content.searchIndex.FindByIp(ip="192.168.1.201", vmSearch=False)
print(esxi)
>>>'vim.HostSystem:host-13'
# vmを検索したい時はTrueに (存在しないのでNone)
vm = si.content.searchIndex.FindByIp(ip="192.168.1.201", vmSearch=True)
print(vm)
>>>None
# vmを検索したい時はTrueに
vm = si.content.searchIndex.FindByIp(ip="192.168.1.11", vmSearch=True)
print(vm)
>>>'vim.VirtualMachine:vm-26'
FindByDnsName
#
DNS名をキーとして、ESXi,VMを取得したい場合は、FindByDnsName
を使うことができます。
esxi = si.content.searchIndex.FindByDnsName(dnsName="192.168.1.201", vmSearch=False)
print(esxi)
>>>'vim.HostSystem:host-13'
vm = si.content.searchIndex.FindByDnsName(dnsName="sample001", vmSearch=True)
print(vm) ## VM名では検索不可
>>>None
FindByDatastorePath
#
.vmxファイルのpathをキーとしてVMを探したい場合は、FindByDatastorePath
を使うことができます。
parameter | 説明 |
---|---|
datacenter | [必須] なぜかこの関数はdatacenterのオブジェクト指定が必須 |
path | [必須] .vmxファイルのpath([datastore名] <vmxファイルのpath> ) |
vm = si.content.searchIndex.FindByDatastorePath(
datacenter=si.content.rootFolder.childEntity[0],
path="[v10-nesxi-01-esx-install-datastore] sample001/sample001.vmx"
)
print(vm)
>>>'vim.VirtualMachine:vm-49'
# datacenter指定しないとerror
si.content.searchIndex.FindByDatastorePath(
# datacenter=si.content.rootFolder.childEntity[0],
path="[v10-nesxi-01-esx-install-datastore] sample001/sample001.vmx"
)
>>>TypeError: Required field "datacenter" not provided (not @optional)
vmxファイルのpathの指定方法が特殊ですが、MOBの<vmのobject>.layoutEx.file[<n>]
からも確認できます。おそらく<n>
は0で固定?
FindByUuid
#
UUIDという各オブジェクトに割り振られたuniqueなIDをキーとして検索したい場合は、FindByUuid
を使うことができます。
parameter | 説明 |
---|---|
datacenter | [option] 複数Datacenterが存在する場合、指定すれば検索範囲を絞り込める |
uuid | [必須] uuidは以下で確認可能。 ESXi: <esxiのobj>.hardware.systemInfo.uuid VM: <vmのobj>.config.uuid or <vmのobj>.config.instanceUuid |
vmSearch | [必須] 検索対象をVMにする場合はTrue、 ESXiにしたい場合はFalse |
instanceUuid | [option] VMをinstanceUuidで探す場合はtrue |
# esxiのuuidで検索する場合
si.content.searchIndex.FindByUuid(
uuid="a56c1542-2895-909e-c819-0f0926f54e87",
vmSearch=False
)
# vmのuuid(vmxのuuid.biosのこと)で検索する場合
si.content.searchIndex.FindByUuid(
uuid="4215e36d-d514-7794-d01f-45dfb71faaf7",
vmSearch=True
)
# vmのinstanceUuid(vmxのvc.uuidのこと)で検索する場合
si.content.searchIndex.FindByUuid(
uuid="5015d0f0-e681-6a60-2211-579a9771a192",
vmSearch=True,
instanceUuid=True
)
VMのUUIDとは?
VMを一意に定めるIDでMOBやvmxで確認することができる。 この内uuid.biosは変更することが可能で、backupからの復元、clone、HA復旧の際の挙動に関わってくるらしい。
cat sample001.vmx
---
# 16進数 → uuid表記(4215e36d-d514-7794-d01f-45dfb71faaf7)
uuid.bios = "42 15 e3 6d d5 14 77 94-d0 1f 45 df b7 1f aa f7"
# 16進数 → uuid表記(5015d0f0-e681-6a60-2211-579a9771a192)
vc.uuid = "50 15 d0 f0 e6 81 6a 60-22 11 57 9a 97 71 a1 92"
このため
sample002.vmx
をsample001.vmx
と同じuuid.biosに書き換える。- vmをunregist→registしてvmxの変更を反映
FindAllByUuid
というAll
がついた関数を使う
とuniqueなはずのuuid検索でも、複数VMがhitするので注意
vms = si.content.searchIndex.FindAllByUuid(
uuid="4215e36d-d514-7794-d01f-45dfb71faaf7",
vmSearch=True
)
for vm in vms:
print(f"{vm}: {vm.name}")
>>>'vim.VirtualMachine:vm-49': sample001
>>>'vim.VirtualMachine:vm-51': sample002
またinstanceUuid(vc.uuid)はvCenterがvmに対して付与するので、変更不可で必ず一意に定まる。従ってVM必ず一意に特定したい場合はinstanceUuid(vc.uuid)の方が好ましい。
2. ContainerViewを使う #
searchIndex
では予めMethodsがあり簡単に取得できましたが、「ESXiとVMしか検索できない」「名前で検索できない」といった欠点もありました。
これに対してContainerView
は、任意のObjectTypeを指定し、該当のObjectを全取得することができます。(簡単:△、柔軟:◎)
これにより一手間かかりますが全VMのObjectを取得した後に、任意のProperties(name, cpu数など)で検索するなど柔軟に検索が可能になります。
ContainerViewの引数
parameter | 説明 |
---|---|
container | [必須] 検索する範囲のオブジェクト(rootFolder, Datacenter, Cluster, ResourcePool, HostSystem, vmFolderなど) |
type | [必須] 検索対象のオブジェクト(VM, ESXi, Datastore, Portgroup等々) |
recursive | [option]再起的にオブジェクトを検索するか。Trueでcontainerで指定した配下全て検索。Falseで直下のオブジェクトのみ検索。 |
pyvmomiで使用されるオブジェクトのタイプ
オブジェクト名 | type |
---|---|
vm | vim.VirtualMachine |
host | vim.HostSystem |
cluster | vim.ClusterComputeResource |
datastore | vim.Datastore |
portgroup | vim.Network |
例1 全VMを取得 #
from pyVim import connect
from pyVmomi import vim # pyVmomi.vimの中に、Objectのtypeが格納されている。
cv = si.content.viewManager.CreateContainerView(
container=si.content.rootFolder, # 範囲はvCenter全体なので、rootFolderを指定
type=[vim.VirtualMachine], # 取得対象がVMであれば、vim.VirtualMachineを指定する。
recursive=True # 配下の全て検索して欲しいのでTrue
)
print(cv.view) # containerView.viewに検索対象のオブジェクトが入っている
# >>>(ManagedObject) [
# 'vim.VirtualMachine:vm-19',
# 'vim.VirtualMachine:vm-23',
# 'vim.VirtualMachine:vm-20',
# 'vim.VirtualMachine:vm-25',
# 'vim.VirtualMachine:vm-26'
# ]
cv.Destroy() # 不要になったcvは壊しておく
例2 全ESXiを取得 #
from pyVim import connect
from pyVmomi import vim
cv = si.content.viewManager.CreateContainerView(
container=si.content.rootFolder, # 範囲はvCenter全体なので、rootFolderを指定
type=[vim.HostSystem], # 取得対象がESXiであれば、vim.HostSystemを指定
recursive=True # 配下の全て検索して欲しいのでTrue
)
print(cv.view)
# >>>(ManagedObject) [
# 'vim.HostSystem:host-14',
# 'vim.HostSystem:host-40',
# 'vim.HostSystem:host-43',
# 'vim.HostSystem:host-45'
# ]
cv.Destroy() # 不要になったcvは壊しておく
例3 Cluster配下のESXi・VMを取得 #
from pyVim import connect
from pyVmomi import vim
cluster = si.content.rootFolder.childEntity[0].hostFolder.childEntity[0]
print(cluster.name)
# >>> v_cluster
cv = si.content.viewManager.CreateContainerView(
container=cluster, # 範囲を特定のクラスタに絞りたい場合は、そのクラスタを指定
type=[vim.HostSystem, vim.VirtualMachine], # 複数指定もOK
recursive=True # 配下の全て検索して欲しいのでTrue
)
print(cv.view)
# >>>(ManagedObject) [
# 'vim.HostSystem:host-40',
# 'vim.HostSystem:host-43',
# 'vim.HostSystem:host-45',
# 'vim.VirtualMachine:vm-48',
# 'vim.VirtualMachine:vm-51',
# 'vim.VirtualMachine:vm-47',
# 'vim.VirtualMachine:vm-49',
# 'vim.VirtualMachine:vm-42'
# ]
cv.Destroy()
例4 powerONのVMを取得 #
if vm.runtime.powerState == "poweredOn":
を変えれば好きな条件で絞ることが可能です。
from pyVim import connect
from pyVmomi import vim
cv = si.content.viewManager.CreateContainerView(
container=si.content.rootFolder,
type=[vim.VirtualMachine],
recursive=True
)
vms = cv.view
cv.Destroy()
for vm in vms:
if vm.runtime.powerState == "poweredOn":
print(vm.name)
# >>> v10-nesxi-03
# v10-nesxi-02
# v10-nesxi-01
# v0-k8s-01
# v0-k8s-03
# v0-k8s-02
# vCLS-b40f3a56-1ca4-4b69-a1df-44d211cd9e08
# vCLS-e833f00a-a25f-451a-bdfd-84f96dd9080d
# vCLS-d52cd7a2-f480-49be-9013-984a796ef551
例5 CD/DVDがついてるVMの検索 #
ストレージを空にしたと思ったのにCD/DVDが接続されているVMが隠れて存在し、ストレージを切断できないという状況が運用中にたまに見かけます。 その際に1つ1つVMの詳細を見て、CD/DVDがついているか判断するのは非常に大変なのでpyvmomiで検索してみます。
from pyVim import connect
from pyVmomi import vim
def get_cd_info(vm) -> str | None:
for device in vm.config.hardware.device:
if isinstance(device, vim.vm.device.VirtualCdrom):
return device.deviceInfo.summary
return None
def main():
si = connect.SmartConnect(
host="***",
user="***",
pwd="***",
disableSslCertValidation=True
)
cv = si.content.viewManager.CreateContainerView(
container=si.content.rootFolder,
type=[vim.VirtualMachine],
recursive=True
)
vms = cv.view
print("vm_name, cdrom")
for vm in vms:
if get_cd_info(vm):
print(f"{vm.name}, {get_cd_info(vm)}")
cv.Destroy()
connect.Disconnect(si) # 終了時にはserviceInstanceは、閉じておくと余計なsessionが残らない。
if __name__ == "__main__":
main()
# >>> vm_name, cdrom
# sample-001, ISO [localhost-esx-install-datastore] mock.iso
# sample-002, Remote device
3. おわりに #
今回はpyvmomiで柔軟にオブジェクトを取得する2つの方法(searchIndex
とContainerView
)を紹介しました。これらを使うことでpyvmomiでできる幅が大きく広がるので、ぜひ使いこなしてもらえると嬉しいです。
ただこれまでは決まりきったpyvmomiの使い方を紹介しただけで「xxxを取得、実行してみたい」という場合に、「MOBのどこを探せば良いか?」「どんなMethodを使えば良いか?」の最初の一歩については解説していませんでした。
最終的にはMOBをくまなく探す & 試してみるのトライアンドエラーになりますが、いくつかお助け機能もあるので第6回はこれらを紹介したいと思います。