github.com/vmware/govmomi@v0.37.2/simulator/folder_test.go (about)

     1  /*
     2  Copyright (c) 2017 VMware, Inc. All Rights Reserved.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package simulator
    18  
    19  import (
    20  	"context"
    21  	"reflect"
    22  	"testing"
    23  
    24  	"github.com/vmware/govmomi"
    25  	"github.com/vmware/govmomi/find"
    26  	"github.com/vmware/govmomi/object"
    27  	"github.com/vmware/govmomi/simulator/esx"
    28  	"github.com/vmware/govmomi/simulator/vpx"
    29  	"github.com/vmware/govmomi/vim25"
    30  	"github.com/vmware/govmomi/vim25/methods"
    31  	"github.com/vmware/govmomi/vim25/mo"
    32  	"github.com/vmware/govmomi/vim25/soap"
    33  	"github.com/vmware/govmomi/vim25/types"
    34  )
    35  
    36  func addStandaloneHostTask(folder *object.Folder, spec types.HostConnectSpec) (*object.Task, error) {
    37  	// TODO: add govmomi wrapper
    38  	req := types.AddStandaloneHost_Task{
    39  		This:         folder.Reference(),
    40  		Spec:         spec,
    41  		AddConnected: true,
    42  	}
    43  
    44  	res, err := methods.AddStandaloneHost_Task(context.TODO(), folder.Client(), &req)
    45  	if err != nil {
    46  		return nil, err
    47  	}
    48  
    49  	task := object.NewTask(folder.Client(), res.Returnval)
    50  	return task, nil
    51  }
    52  
    53  func TestFolderESX(t *testing.T) {
    54  	content := esx.ServiceContent
    55  	s := New(NewServiceInstance(SpoofContext(), content, esx.RootFolder))
    56  
    57  	ts := s.NewServer()
    58  	defer ts.Close()
    59  
    60  	ctx := context.Background()
    61  	c, err := govmomi.NewClient(ctx, ts.URL, true)
    62  	if err != nil {
    63  		t.Fatal(err)
    64  	}
    65  
    66  	f := object.NewRootFolder(c.Client)
    67  
    68  	_, err = f.CreateFolder(ctx, "foo")
    69  	if err == nil {
    70  		t.Error("expected error")
    71  	}
    72  
    73  	_, err = f.CreateDatacenter(ctx, "foo")
    74  	if err == nil {
    75  		t.Error("expected error")
    76  	}
    77  
    78  	finder := find.NewFinder(c.Client, false)
    79  	dc, err := finder.DatacenterOrDefault(ctx, "")
    80  	if err != nil {
    81  		t.Fatal(err)
    82  	}
    83  
    84  	folders, err := dc.Folders(ctx)
    85  	if err != nil {
    86  		t.Fatal(err)
    87  	}
    88  
    89  	spec := types.HostConnectSpec{}
    90  	_, err = addStandaloneHostTask(folders.HostFolder, spec)
    91  	if err == nil {
    92  		t.Fatal("expected error")
    93  	}
    94  
    95  	_, err = folders.DatastoreFolder.CreateStoragePod(ctx, "pod")
    96  	if err == nil {
    97  		t.Fatal("expected error")
    98  	}
    99  }
   100  
   101  func TestFolderVC(t *testing.T) {
   102  	content := vpx.ServiceContent
   103  	s := New(NewServiceInstance(SpoofContext(), content, vpx.RootFolder))
   104  
   105  	ts := s.NewServer()
   106  	defer ts.Close()
   107  
   108  	ctx := context.Background()
   109  	c, err := govmomi.NewClient(ctx, ts.URL, true)
   110  	if err != nil {
   111  		t.Fatal(err)
   112  	}
   113  
   114  	f := object.NewRootFolder(c.Client)
   115  
   116  	ff, err := f.CreateFolder(ctx, "foo")
   117  	if err != nil {
   118  		t.Error(err)
   119  	}
   120  
   121  	dc, err := f.CreateDatacenter(ctx, "bar")
   122  	if err != nil {
   123  		t.Error(err)
   124  	}
   125  
   126  	for _, ref := range []object.Reference{ff, dc} {
   127  		o := Map.Get(ref.Reference())
   128  		if o == nil {
   129  			t.Fatalf("failed to find %#v", ref)
   130  		}
   131  
   132  		e := o.(mo.Entity).Entity()
   133  		if *e.Parent != f.Reference() {
   134  			t.Fail()
   135  		}
   136  	}
   137  
   138  	dc, err = ff.CreateDatacenter(ctx, "biz")
   139  	if err != nil {
   140  		t.Error(err)
   141  	}
   142  
   143  	folders, err := dc.Folders(ctx)
   144  	if err != nil {
   145  		t.Fatal(err)
   146  	}
   147  
   148  	_, err = folders.VmFolder.CreateStoragePod(ctx, "pod")
   149  	if err == nil {
   150  		t.Error("expected error")
   151  	}
   152  
   153  	_, err = folders.DatastoreFolder.CreateStoragePod(ctx, "pod")
   154  	if err != nil {
   155  		t.Error(err)
   156  	}
   157  
   158  	tests := []struct {
   159  		name  string
   160  		state types.TaskInfoState
   161  	}{
   162  		{"", types.TaskInfoStateError},
   163  		{"foo.local", types.TaskInfoStateSuccess},
   164  	}
   165  
   166  	for _, test := range tests {
   167  		spec := types.HostConnectSpec{
   168  			HostName: test.name,
   169  		}
   170  
   171  		task, err := addStandaloneHostTask(folders.HostFolder, spec)
   172  		if err != nil {
   173  			t.Fatal(err)
   174  		}
   175  
   176  		res, err := task.WaitForResult(ctx, nil)
   177  		if test.state == types.TaskInfoStateError {
   178  			if err == nil {
   179  				t.Error("expected error")
   180  			}
   181  
   182  			if res.Result != nil {
   183  				t.Error("expected nil")
   184  			}
   185  		} else {
   186  			if err != nil {
   187  				t.Fatal(err)
   188  			}
   189  
   190  			ref, ok := res.Result.(types.ManagedObjectReference)
   191  			if !ok {
   192  				t.Errorf("expected moref, got type=%T", res.Result)
   193  			}
   194  			host := Map.Get(ref).(*HostSystem)
   195  			if host.Name != test.name {
   196  				t.Fail()
   197  			}
   198  
   199  			if ref == esx.HostSystem.Self {
   200  				t.Error("expected new host Self reference")
   201  			}
   202  			if *host.Summary.Host == esx.HostSystem.Self {
   203  				t.Error("expected new host summary Self reference")
   204  			}
   205  
   206  			pool := Map.Get(*host.Parent).(*mo.ComputeResource).ResourcePool
   207  			if *pool == esx.ResourcePool.Self {
   208  				t.Error("expected new pool Self reference")
   209  			}
   210  		}
   211  
   212  		if res.State != test.state {
   213  			t.Fatalf("%s", res.State)
   214  		}
   215  	}
   216  }
   217  
   218  func TestFolderSpecialCharaters(t *testing.T) {
   219  	content := vpx.ServiceContent
   220  	s := New(NewServiceInstance(SpoofContext(), content, vpx.RootFolder))
   221  
   222  	ts := s.NewServer()
   223  	defer ts.Close()
   224  
   225  	ctx := context.Background()
   226  	c, err := govmomi.NewClient(ctx, ts.URL, true)
   227  	if err != nil {
   228  		t.Fatal(err)
   229  	}
   230  
   231  	f := object.NewRootFolder(c.Client)
   232  
   233  	tests := []struct {
   234  		name     string
   235  		expected string
   236  	}{
   237  		{`/`, `%2f`},
   238  		{`\`, `%5c`},
   239  		{`%`, `%25`},
   240  		// multiple special characters
   241  		{`%%`, `%25%25`},
   242  	}
   243  
   244  	for _, test := range tests {
   245  		ff, err := f.CreateFolder(ctx, test.name)
   246  		if err != nil {
   247  			t.Fatal(err)
   248  		}
   249  
   250  		o := Map.Get(ff.Reference())
   251  		if o == nil {
   252  			t.Fatalf("failed to find %#v", ff)
   253  		}
   254  
   255  		e := o.(mo.Entity).Entity()
   256  		if e.Name != test.expected {
   257  			t.Errorf("expected %s, got %s", test.expected, e.Name)
   258  		}
   259  	}
   260  }
   261  
   262  func TestFolderFaults(t *testing.T) {
   263  	f := Folder{}
   264  	f.ChildType = []string{"VirtualMachine"}
   265  
   266  	if f.CreateFolder(nil, nil).Fault() == nil {
   267  		t.Error("expected fault")
   268  	}
   269  
   270  	if f.CreateDatacenter(nil, nil).Fault() == nil {
   271  		t.Error("expected fault")
   272  	}
   273  }
   274  
   275  func TestRegisterVm(t *testing.T) {
   276  	ctx := context.Background()
   277  
   278  	for i, model := range []*Model{ESX(), VPX()} {
   279  		match := "*"
   280  		if i == 1 {
   281  			model.App = 1
   282  			match = "*APP*"
   283  		}
   284  		defer model.Remove()
   285  		err := model.Create()
   286  		if err != nil {
   287  			t.Fatal(err)
   288  		}
   289  
   290  		s := model.Service.NewServer()
   291  		defer s.Close()
   292  
   293  		c, err := govmomi.NewClient(ctx, s.URL, true)
   294  		if err != nil {
   295  			t.Fatal(err)
   296  		}
   297  
   298  		finder := find.NewFinder(c.Client, false)
   299  		dc, err := finder.DefaultDatacenter(ctx)
   300  		if err != nil {
   301  			t.Fatal(err)
   302  		}
   303  
   304  		finder.SetDatacenter(dc)
   305  
   306  		folders, err := dc.Folders(ctx)
   307  		if err != nil {
   308  			t.Fatal(err)
   309  		}
   310  
   311  		vmFolder := folders.VmFolder
   312  
   313  		vms, err := finder.VirtualMachineList(ctx, match)
   314  		if err != nil {
   315  			t.Fatal(err)
   316  		}
   317  
   318  		vm := Map.Get(vms[0].Reference()).(*VirtualMachine)
   319  
   320  		req := types.RegisterVM_Task{
   321  			This:       vmFolder.Reference(),
   322  			AsTemplate: true,
   323  		}
   324  
   325  		steps := []struct {
   326  			e interface{}
   327  			f func()
   328  		}{
   329  			{
   330  				new(types.InvalidArgument), func() { req.AsTemplate = false },
   331  			},
   332  			{
   333  				new(types.InvalidArgument), func() { req.Pool = vm.ResourcePool },
   334  			},
   335  			{
   336  				new(types.InvalidArgument), func() { req.Path = "enoent" },
   337  			},
   338  			{
   339  				new(types.InvalidDatastorePath), func() { req.Path = vm.Config.Files.VmPathName + "-enoent" },
   340  			},
   341  			{
   342  				new(types.NotFound), func() { req.Path = vm.Config.Files.VmPathName },
   343  			},
   344  			{
   345  				new(types.AlreadyExists), func() { Map.Remove(SpoofContext(), vm.Reference()) },
   346  			},
   347  			{
   348  				nil, func() {},
   349  			},
   350  		}
   351  
   352  		for _, step := range steps {
   353  			res, err := methods.RegisterVM_Task(ctx, c.Client, &req)
   354  			if err != nil {
   355  				t.Fatal(err)
   356  			}
   357  
   358  			ct := object.NewTask(c.Client, res.Returnval)
   359  			_ = ct.Wait(ctx)
   360  
   361  			rt := Map.Get(res.Returnval).(*Task)
   362  
   363  			if step.e != nil {
   364  				fault := rt.Info.Error.Fault
   365  				if reflect.TypeOf(fault) != reflect.TypeOf(step.e) {
   366  					t.Errorf("%T != %T", fault, step.e)
   367  				}
   368  			} else {
   369  				if rt.Info.Error != nil {
   370  					t.Errorf("unexpected error: %#v", rt.Info.Error)
   371  				}
   372  			}
   373  
   374  			step.f()
   375  		}
   376  
   377  		nvm, err := finder.VirtualMachine(ctx, vm.Name)
   378  		if err != nil {
   379  			t.Fatal(err)
   380  		}
   381  
   382  		if nvm.Reference() == vm.Reference() {
   383  			t.Error("expected new moref")
   384  		}
   385  
   386  		onTask, _ := nvm.PowerOn(ctx)
   387  		_ = onTask.Wait(ctx)
   388  
   389  		steps = []struct {
   390  			e interface{}
   391  			f func()
   392  		}{
   393  			{
   394  				types.InvalidPowerState{}, func() { offTask, _ := nvm.PowerOff(ctx); _ = offTask.Wait(ctx) },
   395  			},
   396  			{
   397  				nil, func() {},
   398  			},
   399  			{
   400  				types.ManagedObjectNotFound{}, func() {},
   401  			},
   402  		}
   403  
   404  		for _, step := range steps {
   405  			err = nvm.Unregister(ctx)
   406  
   407  			if step.e != nil {
   408  				fault := soap.ToSoapFault(err).VimFault()
   409  				if reflect.TypeOf(fault) != reflect.TypeOf(step.e) {
   410  					t.Errorf("%T != %T", fault, step.e)
   411  				}
   412  			} else {
   413  				if err != nil {
   414  					t.Errorf("unexpected error: %#v", err)
   415  				}
   416  			}
   417  
   418  			step.f()
   419  		}
   420  	}
   421  }
   422  
   423  func TestFolderMoveInto(t *testing.T) {
   424  	ctx := context.Background()
   425  	model := VPX()
   426  	defer model.Remove()
   427  	err := model.Create()
   428  	if err != nil {
   429  		t.Fatal(err)
   430  	}
   431  
   432  	s := model.Service.NewServer()
   433  	defer s.Close()
   434  
   435  	c, err := govmomi.NewClient(ctx, s.URL, true)
   436  	if err != nil {
   437  		t.Fatal(err)
   438  	}
   439  
   440  	finder := find.NewFinder(c.Client, false)
   441  
   442  	dc, err := finder.DefaultDatacenter(ctx)
   443  	if err != nil {
   444  		t.Fatal(err)
   445  	}
   446  
   447  	finder.SetDatacenter(dc)
   448  
   449  	folders, err := dc.Folders(ctx)
   450  	if err != nil {
   451  		t.Fatal(err)
   452  	}
   453  
   454  	ds, err := finder.DefaultDatastore(ctx)
   455  	if err != nil {
   456  		t.Fatal(err)
   457  	}
   458  
   459  	// Move Datastore into a vm folder should fail
   460  	task, err := folders.VmFolder.MoveInto(ctx, []types.ManagedObjectReference{ds.Reference()})
   461  	if err != nil {
   462  		t.Fatal(err)
   463  	}
   464  
   465  	err = task.Wait(ctx)
   466  	if err == nil {
   467  		t.Errorf("expected error")
   468  	}
   469  
   470  	// Move Datacenter into a sub folder should pass
   471  	f, err := object.NewRootFolder(c.Client).CreateFolder(ctx, "foo")
   472  	if err != nil {
   473  		t.Error(err)
   474  	}
   475  
   476  	task, _ = f.MoveInto(ctx, []types.ManagedObjectReference{dc.Reference()})
   477  	err = task.Wait(ctx)
   478  	if err != nil {
   479  		t.Error(err)
   480  	}
   481  
   482  	pod, err := folders.DatastoreFolder.CreateStoragePod(ctx, "pod")
   483  	if err != nil {
   484  		t.Error(err)
   485  	}
   486  
   487  	// Moving any type other than Datastore into a StoragePod should fail
   488  	task, _ = pod.MoveInto(ctx, []types.ManagedObjectReference{dc.Reference()})
   489  	err = task.Wait(ctx)
   490  	if err == nil {
   491  		t.Error("expected error")
   492  	}
   493  
   494  	// Move DS into a StoragePod
   495  	task, _ = pod.MoveInto(ctx, []types.ManagedObjectReference{ds.Reference()})
   496  	err = task.Wait(ctx)
   497  	if err != nil {
   498  		t.Error(err)
   499  	}
   500  }
   501  
   502  func TestFolderCreateDVS(t *testing.T) {
   503  	ctx := context.Background()
   504  	model := VPX()
   505  	defer model.Remove()
   506  	err := model.Create()
   507  	if err != nil {
   508  		t.Fatal(err)
   509  	}
   510  
   511  	s := model.Service.NewServer()
   512  	defer s.Close()
   513  
   514  	c, err := govmomi.NewClient(ctx, s.URL, true)
   515  	if err != nil {
   516  		t.Fatal(err)
   517  	}
   518  
   519  	finder := find.NewFinder(c.Client, false)
   520  
   521  	dc, err := finder.DefaultDatacenter(ctx)
   522  	if err != nil {
   523  		t.Fatal(err)
   524  	}
   525  
   526  	finder.SetDatacenter(dc)
   527  
   528  	folders, err := dc.Folders(ctx)
   529  	if err != nil {
   530  		t.Fatal(err)
   531  	}
   532  
   533  	var spec types.DVSCreateSpec
   534  	spec.ConfigSpec = &types.VMwareDVSConfigSpec{}
   535  	spec.ConfigSpec.GetDVSConfigSpec().Name = "foo"
   536  
   537  	task, err := folders.NetworkFolder.CreateDVS(ctx, spec)
   538  	if err != nil {
   539  		t.Fatal(err)
   540  	}
   541  
   542  	err = task.Wait(ctx)
   543  	if err != nil {
   544  		t.Error(err)
   545  	}
   546  
   547  	net, err := finder.Network(ctx, "foo")
   548  	if err != nil {
   549  		t.Error(err)
   550  	}
   551  
   552  	dvs, ok := net.(*object.DistributedVirtualSwitch)
   553  	if !ok {
   554  		t.Fatalf("%T is not of type %T", net, dvs)
   555  	}
   556  
   557  	task, err = folders.NetworkFolder.CreateDVS(ctx, spec)
   558  	if err != nil {
   559  		t.Fatal(err)
   560  	}
   561  
   562  	err = task.Wait(ctx)
   563  	if err == nil {
   564  		t.Error("expected error")
   565  	}
   566  
   567  	pspec := types.DVPortgroupConfigSpec{Name: "xnet"}
   568  	task, err = dvs.AddPortgroup(ctx, []types.DVPortgroupConfigSpec{pspec})
   569  	if err != nil {
   570  		t.Fatal(err)
   571  	}
   572  
   573  	err = task.Wait(ctx)
   574  	if err != nil {
   575  		t.Error(err)
   576  	}
   577  
   578  	net, err = finder.Network(ctx, "xnet")
   579  	if err != nil {
   580  		t.Error(err)
   581  	}
   582  
   583  	pg, ok := net.(*object.DistributedVirtualPortgroup)
   584  	if !ok {
   585  		t.Fatalf("%T is not of type %T", net, pg)
   586  	}
   587  
   588  	backing, err := net.EthernetCardBackingInfo(ctx)
   589  	if err != nil {
   590  		t.Fatal(err)
   591  	}
   592  
   593  	info, ok := backing.(*types.VirtualEthernetCardDistributedVirtualPortBackingInfo)
   594  	if ok {
   595  		if info.Port.SwitchUuid == "" || info.Port.PortgroupKey == "" {
   596  			t.Errorf("invalid port: %#v", info.Port)
   597  		}
   598  	} else {
   599  		t.Fatalf("%T is not of type %T", net, info)
   600  	}
   601  
   602  	task, err = dvs.AddPortgroup(ctx, []types.DVPortgroupConfigSpec{pspec})
   603  	if err != nil {
   604  		t.Fatal(err)
   605  	}
   606  
   607  	err = task.Wait(ctx)
   608  	if err == nil {
   609  		t.Error("expected error")
   610  	}
   611  }
   612  
   613  func TestPlaceVmsXCluster(t *testing.T) {
   614  	vpx := VPX()
   615  	vpx.Cluster = 3
   616  
   617  	Test(func(ctx context.Context, c *vim25.Client) {
   618  		finder := find.NewFinder(c, false)
   619  
   620  		spec := types.PlaceVmsXClusterSpec{}
   621  
   622  		pools, err := finder.ResourcePoolList(ctx, "/DC0/host/DC0_C*/*")
   623  		if err != nil {
   624  			t.Fatal(err)
   625  		}
   626  
   627  		for _, pool := range pools {
   628  			spec.ResourcePools = append(spec.ResourcePools, pool.Reference())
   629  		}
   630  
   631  		spec.VmPlacementSpecs = []types.PlaceVmsXClusterSpecVmPlacementSpec{{
   632  			ConfigSpec: types.VirtualMachineConfigSpec{
   633  				Name: "test-vm",
   634  			},
   635  		}}
   636  
   637  		folder := object.NewRootFolder(c)
   638  		res, err := folder.PlaceVmsXCluster(ctx, spec)
   639  		if err != nil {
   640  			t.Fatal(err)
   641  		}
   642  
   643  		if len(res.PlacementInfos) != len(spec.VmPlacementSpecs) {
   644  			t.Errorf("%d PlacementInfos vs %d VmPlacementSpecs", len(res.PlacementInfos), len(spec.VmPlacementSpecs))
   645  		}
   646  	}, vpx)
   647  }