メインコンテンツへスキップ
  1. Blogs/

pyvmomiで自動化5 -オブジェクトの取得-

·3644 文字·
Blog VMware VSphere Pyvmomi Python
hiroki
著者
hiroki
クラウドを作るお仕事をしてます。
目次
pyvmomi - 関連記事
5: << この記事 >>

はじめに
#

これまで紹介したように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

img001

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を使うことができます。

VM名ではなく、DNS名になるので、VM名で検索したい場合はこちらの方法は使用不可になります。
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で固定?

img002

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.vmxsample001.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つの方法(searchIndexContainerView)を紹介しました。これらを使うことでpyvmomiでできる幅が大きく広がるので、ぜひ使いこなしてもらえると嬉しいです。

ただこれまでは決まりきったpyvmomiの使い方を紹介しただけで「xxxを取得、実行してみたい」という場合に、「MOBのどこを探せば良いか?」「どんなMethodを使えば良いか?」の最初の一歩については解説していませんでした。

最終的にはMOBをくまなく探す & 試してみるのトライアンドエラーになりますが、いくつかお助け機能もあるので第6回はこれらを紹介したいと思います。

pyvmomi - 関連記事
5: << この記事 >>

Related

pyvmomiで自動化4 -VMに命令実行-
·1587 文字
Blog VMware VSphere Pyvmomi Python
pyvmomiで自動化3 -ESXiに命令実行-
·2981 文字
Blog VMware VSphere Pyvmomi Python
pyvmomiで自動化2 -vCenterにアクセス-
·3692 文字
Blog VMware VSphere Pyvmomi Python