pyvmomiを使ってvCenterの仮想マシン情報の取得をAPIで行う際に、情報取得にかなり時間がかかる(1分程度)という事象に遭遇しました。
調べたところ、対象のvCenterが2000台超の仮想マシンを管理しており、viewを作って仮想マシンをループして検索するところで時間がかかっていたようです。
今回仮想マシンの台数が多い際にも、対象の仮想マシンオブジェクトを素早く取得する方法が分かりましたので(あまり類似記事が日本語でなかったこともあり)、備忘として記しておきます。
元々利用していたコード
元々以下のようにviewを作成しfor文でループさせ、仮想マシン名が一致する仮想マシンMOBを取得するコードを書いていました。日本語でpyvmomiを検索するとよく出てくるコードから真似をしております。
def get_mob_info(content, target):
"""
指定した名前を持つ仮想マシンのManagement Objectを取得する。
:type content: vim.ServiceInstanceContent
:param content: ServiceContent
:type target: str
:param target: 返すmobの仮想マシン名を指定
:rtype: Management Object
:return: 指定したManagement Object又はContainerViewを返す
"""
container = content.viewManager.CreateContainerView(content.rootFolder, [vim.VirtualMachine], True)
# 返す仮想マシンmobを名前で指定する
for mob in container.view:
if mob.name == target:
r = mob
break
return r
このコード自体は正しく動作しますが、管理対象の仮想マシンが増えるほど時間がかかるようになります。今回計測したところ1ループに0.02秒程度かかっており、2000台超の仮想マシンがいることで運が悪いと1分弱程度時間がかかるようになっていたようです。
改良したコード
時間短縮のために修正したコードは下記となります。viewでのループではなくパスで指定してvCenterのデータベースからクエリする方法となります。この方法で実施したところ実行時間は0.01秒以下となりました。
副次的ですが、コードとしてもスッキリし読みやすくなりました。
def get_mob_info(content, target):
"""
指定した名前を持つ仮想マシンのManagement Objectを取得する。
:type content: vim.ServiceInstanceContent
:param content: ServiceContent
:type target: str
:param target: 返すmobの仮想マシン名を指定
:rtype: Management Object
:return: 指定したManagement Object又はContainerViewを返す
"""
search_index = content.searchIndex
r = search_index.FindByInventoryPath("/<DataCenter名>/vm/" + target)
return r
viewを使用した場合、すべてのオブジェクトを取得してからローカルでforループを実行するため、対象となるオブジェクトが多い場合に処理時間がかかりすぎるようです。一方、SearchIndexを使うとデータベースのクエリを使用して直接目的のオブジェクトを見つけるので時間が短縮されたようです。
最後に
ちなみにこの改良は軽くググって解決できずChatGPT(3.5)君に聞いて教えてもらいました。その後でこの記事を書く際に再度pyvmomiのサンプル集Gitを確認したところ、普通にサンプルに載っていたのでやはり確認すべきは公式ドキュメントですね。
ただ検索弱者にもプロンプトの書き方次第でいろいろ教えてくれるGPT君は心強い存在です。