Skip to content

Instantly share code, notes, and snippets.

@Syuparn
Created October 11, 2020 06:41
Show Gist options
  • Save Syuparn/a1f1285d62a5c3da339deb41093dae25 to your computer and use it in GitHub Desktop.
Save Syuparn/a1f1285d62a5c3da339deb41093dae25 to your computer and use it in GitHub Desktop.
govmomi-client-test

govmomi-client-test

govmomiのクライアントの動作を調べるために作ったテストです。

preparation

go test実行前に、vcsimを起動(必要ならインストールも)してください。

# `tls: bad certificate`を回避するための設定
$ export GOVC_INSECURE=1
# 認証情報を設定しvcsimを起動
$ vcsim --username taro --password pass

researched version

govmomi 0.23.1 (2020.10.11)

results

clientの関係

  • rest.NewClientgovmomi.Clientから作れる
  • govmomi.Clientvim25.ClientでラップするとClient#URL()が使えなくなる
    • おそらく想定外の使い方のため。govmomi.Client.Clientvim25.Clientを取り出せば問題ない

clientの認証

  • rest.Clientのログインとgovmomi.Clientのログインは独立
    • vapi, カテゴリー作成
      • govmomi.Client, rest.Client両方ログイン→成功
      • govmomi.Clientでログインせずrest.Clientのみログイン→成功
      • govmomi.Clientでログインし、rest.Clientはログインしない→401
package sample
import (
"context"
"testing"
"github.com/vmware/govmomi"
"github.com/vmware/govmomi/find"
"github.com/vmware/govmomi/session"
"github.com/vmware/govmomi/vapi/rest"
"github.com/vmware/govmomi/vapi/tags"
"github.com/vmware/govmomi/vim25"
"github.com/vmware/govmomi/vim25/soap"
)
func sampleCategory() *tags.Category {
return &tags.Category{
AssociableTypes: []string{},
Cardinality: "SINGLE",
Description: "description",
Name: "my-category",
}
}
func TestSettings(t *testing.T) {
url_ := vcsimURL()
if url_ == nil {
t.Fatalf("URL must not be nil")
}
expected := "https://taro:pass@127.0.0.1:8989/sdk"
if url_.String() != expected {
t.Errorf("URL is wrong. got=%s, expected=%s", url_.String(), expected)
}
}
func TestRequestFromGovmomiClient(t *testing.T) {
// logged in inside NewClient
client, err := govmomi.NewClient(context.TODO(), vcsimURL(), true)
if err != nil {
t.Fatalf("failed to create client: " + err.Error())
}
dc, err := find.NewFinder(client.Client).Datacenter(context.TODO(), "DC0")
if err != nil {
t.Fatalf("failed to find dc: " + err.Error())
}
if dc == nil {
t.Errorf("dc must not be nil.")
}
}
func TestRequestFromRestClient(t *testing.T) {
// logged in inside NewClient
client, err := govmomi.NewClient(context.TODO(), vcsimURL(), true)
if err != nil {
t.Fatalf("failed to create govmomi client: " + err.Error())
}
restClient := rest.NewClient(client.Client)
// login with rest client
_ = restClient.Login(context.TODO(), userInfo())
m := tags.NewManager(restClient)
// send request while creating
id, err := m.CreateCategory(context.TODO(), sampleCategory())
if err != nil {
t.Errorf("failed to create category: " + err.Error())
}
category, err := m.GetCategory(context.TODO(), id)
if err != nil {
t.Errorf("failed to get category: " + err.Error())
}
// delete new category for following tests
err = m.DeleteCategory(context.TODO(), category)
if err != nil {
t.Errorf("failed to delete category: " + err.Error())
}
}
func TestVim25Client_URL_Panics(t *testing.T) {
// logged in inside NewClient
client, err := govmomi.NewClient(context.TODO(), vcsimURL(), true)
if err != nil {
t.Fatalf("failed to create govmomi client: " + err.Error())
}
// NOTE: govmomi.Client implements soap.RoundTripper
vim25Client, err := vim25.NewClient(context.TODO(), client)
if err != nil {
t.Fatalf("failed to create vim25 client: " + err.Error())
}
// NOTE: vim25Client.URL() panics because userinfo is removed in NewClient()
// https://github.com/vmware/govmomi/blob/master/vim25/soap/client.go#L158
// https://github.com/vmware/govmomi/blob/master/vim25/soap/client.go#L444
defer func() {
if r := recover(); r == nil {
t.Errorf("The code did not panic")
}
}()
_ = vim25Client.URL()
}
func TestRestNewClient_From_Vim25Client_Panics(t *testing.T) {
client, err := govmomi.NewClient(context.TODO(), vcsimURL(), true)
if err != nil {
t.Fatalf("failed to create govmomi client: " + err.Error())
}
// NOTE: govmomi.Client implements soap.RoundTripper
vim25Client, err := vim25.NewClient(context.TODO(), client)
if err != nil {
t.Fatalf("failed to create vim25 client: " + err.Error())
}
// NOTE: rest.NewClient(vim25Client) panics because it calls soap.Client#URL()
// which refers vim25.Client.u (== vim25.Client#URL())
// https://github.com/vmware/govmomi/blob/master/vapi/rest/client.go#L64
// https://github.com/vmware/govmomi/blob/master/vim25/soap/client.go#L172
// https://github.com/vmware/govmomi/blob/master/vim25/soap/client.go#L444
defer func() {
if r := recover(); r == nil {
t.Errorf("The code did not panic")
}
}()
_ = rest.NewClient(vim25Client)
}
// error if rest.Client is not logged in even though govmomi.Client is logged in
func TestRequestFromRestClient_Without_RestClient_Login_Error(t *testing.T) {
// logged in inside NewClient
client, err := govmomi.NewClient(context.TODO(), vcsimURL(), true)
if err != nil {
t.Fatalf("failed to create govmomi client: " + err.Error())
}
restClient := rest.NewClient(client.Client)
// skip restClient login
m := tags.NewManager(restClient)
// send request while creating
_, err = m.CreateCategory(context.TODO(), sampleCategory())
if err == nil {
t.Errorf("error must occur")
}
expectedErr := "POST https://127.0.0.1:8989/rest/com/vmware/cis/tagging/category: 401 Unauthorized"
if err.Error() != expectedErr {
t.Errorf("error must be `%s`\ngot=`%s`", expectedErr, err.Error())
}
}
// ok if rest.Client is logged in even though govmomi.Client is not logged in
func TestRequestFromRestClient_Without_GovmomiClient_Login(t *testing.T) {
// skip govmomi login
// NOTE: govmomi.NewClient() cannot be used here because it logins inside
soapClient := soap.NewClient(vcsimURL(), true)
vimClient, err := vim25.NewClient(context.TODO(), soapClient)
if err != nil {
t.Fatalf("failed to create vimClient client: " + err.Error())
}
client := &govmomi.Client{
Client: vimClient,
SessionManager: session.NewManager(vimClient),
}
restClient := rest.NewClient(client.Client)
// login with rest client
_ = restClient.Login(context.TODO(), userInfo())
m := tags.NewManager(restClient)
// send request while creating
id, err := m.CreateCategory(context.TODO(), sampleCategory())
if err != nil {
t.Errorf("failed to create category: " + err.Error())
}
category, err := m.GetCategory(context.TODO(), id)
if err != nil {
t.Errorf("failed to get category: " + err.Error())
}
// delete new category for following tests
err = m.DeleteCategory(context.TODO(), category)
if err != nil {
t.Errorf("failed to delete category: " + err.Error())
}
}
module github.com/syuparn/govmomi-client-test
go 1.13
require github.com/vmware/govmomi v0.23.1
github.com/davecgh/go-xdr v0.0.0-20161123171359-e6a2ba005892/go.mod h1:CTDl0pzVzE5DEzZhPfvhY/9sPFMQIxaJ9VAMs9AagrE=
github.com/google/uuid v0.0.0-20170306145142-6a5e28554805 h1:skl44gU1qEIcRpwKjb9bhlRwjvr96wLdvpTogCBBJe8=
github.com/google/uuid v0.0.0-20170306145142-6a5e28554805/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/vmware/govmomi v0.23.1 h1:vU09hxnNR/I7e+4zCJvW+5vHu5dO64Aoe2Lw7Yi/KRg=
github.com/vmware/govmomi v0.23.1/go.mod h1:Y+Wq4lst78L85Ge/F8+ORXIWiKYqaro1vhAulACy9Lc=
github.com/vmware/vmw-guestinfo v0.0.0-20170707015358-25eff159a728/go.mod h1:x9oS4Wk2s2u4tS29nEaDLdzvuHdB19CvSGJjPgkZJNk=
package sample
import (
"net/url"
)
func userInfo() *url.Userinfo {
return url.UserPassword("taro", "pass")
}
func vcsimURL() *url.URL {
// or use wrapper vim25.soap.ParseURL() instead
var url_, _ = url.Parse("https://127.0.0.1:8989/sdk")
// NOTE: userinfo is neccessary because govmomi.NewClient() logins by url's userinfo
url_.User = userInfo()
return url_
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment