govmomiでMOBのMethodを実行してみた

govmomiを使ってManagement ObjectのMethodを実行しようとしたところ、findで取得したオブジェクトにMethodが実装されてたりされていなかったりというのに気づきました。
ちなみに、今回はCluster ObjectのGetResourceUsage Methodを実行したかったのですが、findで返ってくるオブジェクトには実装されていなかったのでmethodsに定義されているものを直接使って見ました。

# pyvmomiの例

まずは、pyvmomiでやった時の例です。
実装部分(一部)はこんな感じ。

```python
(snip)
def get_mob_info(content, mob, target=''):
    r = content.viewManager.CreateContainerView(content.rootFolder,
                                                [mob],
                                                True)

    # 返すmobを名前で指定する場合
    if(target):
        for i in r.view:
            if(i.name == target):
                r = i

    return r
(snip)
if __name__ == '__main__':
    (snip)
    cluster = get_mob_info(content, vim.ClusterComputeResource, "")
        for i in cluster.view:
            r = i.GetResourceUsage()
            print(r)
```

これを実行すると、以下のように表示されます。

```bash
vim.cluster.ResourceUsageSummary) {
   dynamicType = <unset>,
   dynamicProperty = (vmodl.DynamicProperty) [],
   cpuUsedMHz = 124,
   cpuCapacityMHz = 49600,
   memUsedMB = 4048,
   memCapacityMB = 64945,
   storageUsedMB = 270712,
   storageCapacityMB = 3268352
}
```

こんなイメージでgovmomiもできるかな？と思ったのですができませんでした。

# govmomiでのMethodを実行する方法

とりあえず、どのように実行しているかを確認してみました。
ここで参考にしたのは [PowerOnVM_Task](https://github.com/vmware/govmomi/blob/master/object/virtual_machine.go#L58) です。

```go
(snip)
func (v VirtualMachine) PowerOn(ctx context.Context) (*Task, error) {
	req := types.PowerOnVM_Task{
		This: v.Reference(),
	}

	res, err := methods.PowerOnVM_Task(ctx, v.c, &req)
	if err != nil {
		return nil, err
	}

	return NewTask(v.c, res.Returnval), nil
}
(snip)
```

処理を見てみると

* typesでMethodに渡す構造体を作る、ここでは構造体にオブジェクトリファレンスを格納
* 実行するMethodに必要な引数を渡す

のような流れだったので、実際にクラスタでもやってみました。

# govmomiでクラスタオブジェクトのGetResourceUsageを実行

```go
package main

import (
	"context"
	"fmt"
	"net/url"
	"os"

	"github.com/vmware/govmomi"
	"github.com/vmware/govmomi/find"
	"github.com/vmware/govmomi/vim25/methods"
	"github.com/vmware/govmomi/vim25/types"
)

const (
	URL      = "https://vCenterIP/sdk"       // ESXi or vCenter URL
	UserName = "administrator@vsphere.local" // ログインユーザー
	Password = "password"                    // ログインパスワード
	Insecure = true                          // 自己証明書の許可 `true`
)

func exit(err error) {
	fmt.Fprintf(os.Stderr, "Error: %s\n", err)
	os.Exit(1)
}

func main() {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	// 接続先のURLをパース
	u, err := url.Parse(URL)
	if err != nil {
		exit(err)
	}

	// ログインユーザーとパスワードをセット
	u.User = url.UserPassword(UserName, Password)

	// ログイン
	c, err := govmomi.NewClient(ctx, u, Insecure)
	if err != nil {
		exit(err)
	}
	f := find.NewFinder(c.Client, true)

	// データセンターを検索
	dc, err := f.DefaultDatacenter(ctx)
	if err != nil {
		exit(err)
	}

	// 見つけたデータセンターのローカルコールを使う
	f.SetDatacenter(dc)

	// データセンター内のクラスタリストを取得
	cls, err := f.ClusterComputeResourceList(ctx, "*")
	if err != nil {
		exit(err)
	}

	// クラスタのGetResourceUsageメソッドを実行する
	for _, i := range cls {
		// GetResourceUsageに渡す構造体を作成
		// https://godoc.org/github.com/vmware/govmomi/vim25/types#GetResourceUsage
		req := types.GetResourceUsage{
			This: i.Reference(),
		}

		// GetResourceUsageメソッドを実行
		// https://godoc.org/github.com/vmware/govmomi/vim25/methods#GetResourceUsage
		r, _ := methods.GetResourceUsage(ctx, c.Client, &req)

		// 結果を出力
		fmt.Println("CapacityMHz :", r.Returnval.CpuCapacityMHz)
		fmt.Println("CpuUsedMHz :", r.Returnval.CpuUsedMHz)
		fmt.Println("MemCapacityMB :", r.Returnval.MemCapacityMB)
		fmt.Println("MemUsedMB :", r.Returnval.MemUsedMB)
		fmt.Println("StorageCapacityMB :", r.Returnval.StorageCapacityMB)
		fmt.Println("StorageUsedMB :", r.Returnval.StorageUsedMB)
	}

}
```

# 実行結果

```bash
$ go run get_cluster_resource.go
CapacityMHz : 49600
CpuUsedMHz : 126
MemCapacityMB : 64945
MemUsedMB : 4047
StorageCapacityMB : 3268352
StorageUsedMB : 270712
```

pyvmomiで取得した情報と同じものが取れました :-)
govmomiでMethodを実行する場合は、ちょっとだけ手間かもしれません。

# 参考

[govmomi GoDoc](https://godoc.org/github.com/vmware/govmom)