0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

vcsimの小ネタ: ID生成の仕組み

Posted at

(この記事は個人ブログの再投稿です)

vcsimの小ネタシリーズです。今回はかなりマニアックな実装の話。

TL; DR

  • vcsimの各リソースのIDは何度起動しても変わらない
    • ただし、vapi (REST API)で操作するリソースのIDは完全ランダム
  • vcsimがバージョンアップした際には
    • MOID: 変わるかも
    • UUID: パスが同じ限り変わらない

はじめに

vcsimの各リソースには、実際のvCenter同様一意なIDが割り振られます。
基本的にこのIDは何度起動しても同じなので、ツールのテストに使用する際には固定値で試せてありがたいです。

# DC0_H0_VM0 の moid (vcsim v0.27.4)
$ govc vm.info -json DC0_H0_VM0 | jq .VirtualMachines[].Self
{
  "Type": "VirtualMachine",
  "Value": "vm-54"
}

ただし、vcsimのバージョンが変わるとIDがずれることもよくあり、その際はテストを書き直して回る必要があります。
今回は、vcsimがどのように各種IDを生成しているのか内部実装を紹介したいと思います。

バージョン

  • vcsim v0.27.4+ (記事投稿時点のmasterブランチ)1

MOID

各リソースのMOIDはオートインクリメントで払い出されています。
vcsim全体でロックをとっているため、常に一意性が担保されます。

実装としては、作成されたManaged Objectが親フォルダの子エンティティ一覧に追加される際に設定されます。

例として、vm作成のコードを見ていきます。

func NewVirtualMachine(ctx *Context, parent types.ManagedObjectReference, spec *types.VirtualMachineConfigSpec) (*VirtualMachine, types.BaseMethodFault) {
	vm := &VirtualMachine{}

	// ...

	folder := ctx.Map.Get(parent)
	f, _ := asFolderMO(folder)
	// ここで親folderに新規作成したvmをセット
	folderPutChild(ctx, f, vm)
}

folderPutChild はフォルダに子エンティティを追加する関数です。

ctx.Map.reference(o) はoのMOIDを参照するメソッドですが、副作用としてMOIDを持っていない場合に新規生成する役目も担っています。

func folderPutChild(ctx *Context, f *mo.Folder, o mo.Entity) {
	ctx.WithLock(f, func() {
		// Need to update ChildEntity before Map.Put for ContainerView updates to work properly
		f.ChildEntity = append(f.ChildEntity, ctx.Map.reference(o)) // ★
		ctx.Map.PutEntity(f, o)

		folderUpdate(ctx, f, o, ctx.Map.AddReference)

		ctx.WithLock(o, func() {
			switch e := o.(type) {
			case *mo.Network:
				e.Summary = networkSummary(e)
			case *mo.OpaqueNetwork:
				e.Summary = networkSummary(&e.Network)
			case *DistributedVirtualPortgroup:
				e.Summary = networkSummary(&e.Network)
			}
		})
	})
}

reference の実装です。typeかvalueが空文字の場合に新規生成しセットしています。

func (r *Registry) reference(item mo.Reference) types.ManagedObjectReference {
	ref := item.Reference()
	if ref.Type == "" || ref.Value == "" {
		ref = r.newReference(item)
		r.setReference(item, ref)
	}
	return ref
}

func (r *Registry) newReference(item mo.Reference) types.ManagedObjectReference {
	ref := item.Reference()

	if ref.Type == "" {
		ref.Type = typeName(item)
	}

	if ref.Value == "" {
		n := atomic.AddInt64(&r.counter, 1)
		ref.Value = fmt.Sprintf("%s%d", valuePrefix(ref.Type), n)
	}

	return ref
}

実装からもわかるように

  • Type: エンティティの型名(ここでは VirtualMachine)
  • Value: 型名に応じたprefix + オートインクリメントの整数(例: vm-123

が生成され、晴れて一意なMOIDとして利用可能になります。

MOIDのずれ

上記のように、MOIDの整数部分はオートインクリメントなので、デフォルトのManaged Objectが新規追加されるとその分だけずれます。

DC0_H0_VM0 は現在54番目に作られているのでMOIDが vm-54 ですが、仮に次のリリースで1つManaged Objectが増え、その生成タイミングが DC0_H0_VM0 よりも前なら vm-55 に繰り下げになります。

(もちろん、上記以外にもバグ修正によって変な名前だったMOIDがvCenterに準拠する形式に修正されることもあるでしょう)

UUID

UUIDはリソースのパス文字列をもとに生成されます。

生成には github.com/google/uuid.NewSHA1 が使用され、Version 5のUUIDが作られます。

func sha1UUID(s string) uuid.UUID {
	return uuid.NewSHA1(uuid.NameSpaceOID, []byte(s))
}

文字列として与えられる内容は以下の通りです。

  • vmのUUID: .Config.Files.VmPathName
  • vmのInstanceUUID .Config.Files.VmPathName を大文字化した文字列
  • hostのUUID: ホスト名
  • diskのUUID: Datacenter:${所属データセンターのMOID} + .Backing.FileName

詳しくは以前書いたGist をご覧ください(v0.26.0当時の内容ですが、v0.27.4でも実装は同じです)。

名前やパスに依存しているため、基本的にvcsimのバージョンアップでは変化しません(ディスクだけはデータセンターのMOIDが入っているので怪しいかも)。

vapiのリソースのID

上記のようにvSphere Web Services API (SOAP API)のリソースのIDは基本的に固定値です。

一方、カテゴリやタグ等、vapi (REST API)で操作するリソースのIDは完全ランダムです。残念ながら起動のたびに値が変わってしまいます。

vapi/simulator/simulator.go
func newID(kind string) string {
	return fmt.Sprintf("urn:vmomi:InventoryService%s:%s:GLOBAL", kind, uuid.New().String())
}

おわりに

以上、vcsimのIDについてでした。変更リスクを上手く見定めて、上手くテストに組み込んでいきたいですね。

  1. と思ったら投稿直前に v0.28.0が出ていました :tada:

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?