github.com/vmware/govmomi@v0.51.0/eam/simulator/simulator_test.go (about)

     1  // © Broadcom. All Rights Reserved.
     2  // The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
     3  // SPDX-License-Identifier: Apache-2.0
     4  
     5  package simulator_test
     6  
     7  import (
     8  	"context"
     9  	"flag"
    10  	"fmt"
    11  	"os"
    12  	"os/signal"
    13  	"sync"
    14  	"testing"
    15  	"time"
    16  
    17  	"github.com/vmware/govmomi/eam"
    18  	"github.com/vmware/govmomi/eam/object"
    19  	"github.com/vmware/govmomi/eam/types"
    20  	"github.com/vmware/govmomi/fault"
    21  	"github.com/vmware/govmomi/find"
    22  	vimobject "github.com/vmware/govmomi/object"
    23  	"github.com/vmware/govmomi/session"
    24  	vcsim "github.com/vmware/govmomi/simulator"
    25  	"github.com/vmware/govmomi/vim25"
    26  	"github.com/vmware/govmomi/vim25/soap"
    27  	vim "github.com/vmware/govmomi/vim25/types"
    28  
    29  	// making sure the SDK endpoint is registered
    30  	_ "github.com/vmware/govmomi/eam/simulator"
    31  )
    32  
    33  const waitLoopMessage = `
    34  
    35  ################################################################################
    36  # When executed with the flags -powerOnVMs and -waitForExit, this test will    #
    37  # pause here and update the screen with the status of the agent VMs until      #
    38  # SIGINT is sent to this process.                                              #
    39  ################################################################################
    40  `
    41  
    42  var (
    43  	flagPowerOnVMs = flag.Bool("powerOnVMs", false, "Powers on the VMs in the test with Docker")
    44  	flagWaitToExit = flag.Bool("waitToExit", false, "Waits for user input to exit the test")
    45  )
    46  
    47  func TestSimulator(t *testing.T) {
    48  	vcsim.Test(func(ctx context.Context, vimClient *vim25.Client) {
    49  		// Create a finder that sets the default datacenter.
    50  		finder := find.NewFinder(vimClient, true)
    51  
    52  		// Get the datacenter to use when creating the agency.
    53  		datacenter, err := finder.DefaultDatacenter(ctx)
    54  		if err != nil {
    55  			t.Fatal(err)
    56  		}
    57  		finder.SetDatacenter(datacenter)
    58  
    59  		// Get the "vm" folder.
    60  		folder, err := finder.DefaultFolder(ctx)
    61  		if err != nil {
    62  			t.Fatal(err)
    63  		}
    64  
    65  		// Get the cluster to use when creating the agency.
    66  		computeResource, err := finder.ClusterComputeResourceOrDefault(ctx, "")
    67  		if err != nil {
    68  			t.Fatal(err)
    69  		}
    70  
    71  		// Get the resource pool to use when creating the agency.
    72  		pool, err := computeResource.ResourcePool(ctx)
    73  		if err != nil {
    74  			t.Fatal(err)
    75  		}
    76  
    77  		// Get the datastore to use when creating the agency.
    78  		datastore, err := finder.DatastoreOrDefault(ctx, "")
    79  		if err != nil {
    80  			t.Fatal(err)
    81  		}
    82  
    83  		// Get the network to use when creating the agency.
    84  		network, err := finder.NetworkOrDefault(ctx, "DVS0")
    85  		if err != nil {
    86  			t.Fatal(err)
    87  		}
    88  
    89  		// Get an EAM client.
    90  		eamClient := eam.NewClient(vimClient)
    91  
    92  		// Get the EAM root object.
    93  		mgr := object.NewEsxAgentManager(eamClient, eam.EsxAgentManager)
    94  
    95  		// Define a function that will list and print the agency MoRefs.
    96  		listAgencies := func() int {
    97  			t.Log("listing agencies")
    98  			agencies, err := mgr.Agencies(ctx)
    99  			if err != nil {
   100  				t.Fatal(err)
   101  			}
   102  			if len(agencies) == 0 {
   103  				t.Log("no agencies")
   104  				return 0
   105  			}
   106  			for _, obj := range agencies {
   107  				t.Logf("agency: %v", obj.Reference())
   108  				config, err := obj.Config(ctx)
   109  				if err != nil {
   110  					t.Fatal(err)
   111  				}
   112  				t.Logf("agency config: %+v", config)
   113  				runtime, err := obj.Runtime(ctx)
   114  				if err != nil {
   115  					t.Fatal(err)
   116  				}
   117  				t.Logf("agency runtime: %+v", runtime)
   118  
   119  				agents, err := obj.Agents(ctx)
   120  				if err != nil {
   121  					t.Fatal(err)
   122  				}
   123  				if len(agents) == 0 {
   124  					t.Log("no agents")
   125  				} else {
   126  					for _, a := range agents {
   127  						t.Logf("agent: %v", a.Reference())
   128  						config, err := a.Config(ctx)
   129  						if err != nil {
   130  							t.Fatal(err)
   131  						}
   132  						t.Logf("agent config: %+v", config)
   133  						runtime, err := a.Runtime(ctx)
   134  						if err != nil {
   135  							t.Fatal(err)
   136  						}
   137  						t.Logf("agent runtime: %+v", runtime)
   138  					}
   139  				}
   140  			}
   141  			return len(agencies)
   142  		}
   143  
   144  		// List and print the agency MoRefs. There are none.
   145  		if listAgencies() > 0 {
   146  			t.Fatal("no agencies expected")
   147  		}
   148  
   149  		// Create a new agency.
   150  		t.Log("creating a new agency")
   151  		agency, err := mgr.CreateAgency(
   152  			ctx,
   153  			&types.AgencyConfigInfo{
   154  				AgencyName: "nginx",
   155  				AgentVmDatastore: []vim.ManagedObjectReference{
   156  					datastore.Reference(),
   157  				},
   158  				Folders: []types.AgencyVMFolder{
   159  					{
   160  						FolderId:     folder.Reference(),
   161  						DatacenterId: datacenter.Reference(),
   162  					},
   163  				},
   164  				ResourcePools: []types.AgencyVMResourcePool{
   165  					{
   166  						ResourcePoolId:    pool.Reference(),
   167  						ComputeResourceId: computeResource.Reference(),
   168  					},
   169  				},
   170  				AgentVmNetwork: []vim.ManagedObjectReference{
   171  					network.Reference(),
   172  				},
   173  				AgentConfig: []types.AgentConfigInfo{
   174  					{
   175  						OvfPackageUrl: "nginx",
   176  					},
   177  					{
   178  						OvfPackageUrl: "nginx",
   179  					},
   180  				},
   181  			},
   182  			string(types.EamObjectRuntimeInfoGoalStateEnabled),
   183  		)
   184  		if err != nil {
   185  			if soap.IsSoapFault(err) {
   186  				fault := soap.ToSoapFault(err).VimFault()
   187  				t.Fatalf("%[1]T %[1]v", fault)
   188  			} else {
   189  				t.Fatalf("%[1]T %[1]v", err)
   190  			}
   191  		}
   192  		t.Logf("created agency: %v", agency.Reference())
   193  
   194  		// List the agencies again, and this time the newly created agency will be
   195  		// printed to the console.
   196  		if listAgencies() != 1 {
   197  			t.Fatal("one agency expected")
   198  		}
   199  
   200  		// Check whether or not we want to power on the VMs with Docker.
   201  		if *flagPowerOnVMs {
   202  			agencies, err := mgr.Agencies(ctx)
   203  			if err != nil {
   204  				t.Fatal(err)
   205  			}
   206  			if len(agencies) == 0 {
   207  				t.Fatal("no agencies")
   208  			}
   209  			agency := agencies[0]
   210  
   211  			// Wait for the agent VMs to have IP addresses
   212  			{
   213  				agents, err := agency.Agents(ctx)
   214  				if err != nil {
   215  					t.Fatal(err)
   216  				}
   217  				if len(agents) == 0 {
   218  					t.Fatal("no agents")
   219  				}
   220  
   221  				wait := make(chan struct{})
   222  				done := make(chan struct{})
   223  				errs := make(chan error)
   224  				msgs := make(chan string)
   225  				var wg sync.WaitGroup
   226  				wg.Add(len(agents))
   227  
   228  				for _, agent := range agents {
   229  					agent := agent
   230  					go func() {
   231  						var (
   232  							vmPowerState string
   233  							vmIp         string
   234  							once         sync.Once
   235  							vmon         = map[vim.ManagedObjectReference]struct{}{}
   236  						)
   237  						for {
   238  							runtime, err := agent.Runtime(ctx)
   239  							if err != nil {
   240  								errs <- err
   241  								return
   242  							}
   243  							if runtime.Vm == nil {
   244  								errs <- fmt.Errorf("vm is nil for agent %s", agent.Reference())
   245  								return
   246  							}
   247  							if _, ok := vmon[*runtime.Vm]; !ok {
   248  								vm := vimobject.NewVirtualMachine(vimClient, *runtime.Vm)
   249  								if _, err := vm.PowerOn(ctx); err != nil {
   250  									errs <- err
   251  									return
   252  								}
   253  								vmon[*runtime.Vm] = struct{}{}
   254  							}
   255  
   256  							if vmIp != runtime.VmIp || vmPowerState != string(runtime.VmPowerState) {
   257  								vmIp = runtime.VmIp
   258  								vmPowerState = string(runtime.VmPowerState)
   259  								msgs <- fmt.Sprintf(
   260  									"%v: name=%s, powerState=%s, ipAddr=%s",
   261  									*runtime.Vm,
   262  									runtime.VmName,
   263  									vmPowerState,
   264  									vmIp)
   265  							}
   266  							if vmIp != "" {
   267  								once.Do(func() {
   268  									wg.Done()
   269  								})
   270  							}
   271  							select {
   272  							case <-time.After(1 * time.Second):
   273  							case <-done:
   274  								return
   275  							}
   276  						}
   277  					}()
   278  				}
   279  
   280  				go func() {
   281  					wg.Wait()
   282  					if *flagWaitToExit {
   283  						<-wait
   284  					}
   285  					close(done)
   286  				}()
   287  
   288  				go func() {
   289  					defer close(wait)
   290  					if !*flagWaitToExit {
   291  						return
   292  					}
   293  					t.Log(waitLoopMessage)
   294  					c := make(chan os.Signal, 1)
   295  					signal.Notify(c, os.Interrupt)
   296  					for {
   297  						select {
   298  						case <-time.After(1 * time.Second):
   299  						case <-c:
   300  							return
   301  						}
   302  					}
   303  				}()
   304  
   305  				t.Log("waiting for the agent VMs to power on and get IP addresses")
   306  				timeout := time.After(10 * time.Minute)
   307  				func() {
   308  					for {
   309  						select {
   310  						case msg := <-msgs:
   311  							t.Log(msg)
   312  						case err := <-errs:
   313  							t.Fatal(err)
   314  						case <-done:
   315  							return
   316  						case <-timeout:
   317  							t.Fatal("timed out waiting for agent VMs to power on and get IP addresses")
   318  							return
   319  						}
   320  					}
   321  				}()
   322  			}
   323  		}
   324  
   325  		// Destroy the agency.
   326  		t.Log("destroying agency")
   327  		if err := agency.Destroy(ctx); err != nil {
   328  			t.Fatal(err)
   329  		}
   330  
   331  		if listAgencies() != 0 {
   332  			t.Fatal("no agencies expected")
   333  		}
   334  	})
   335  }
   336  
   337  func TestNotAuthenticated(t *testing.T) {
   338  	vcsim.Test(func(ctx context.Context, vimClient *vim25.Client) {
   339  
   340  		t.Run("TerminateSession", func(t *testing.T) {
   341  			// Terminate the session.
   342  			sessionManager := session.NewManager(vimClient)
   343  			if err := sessionManager.Logout(ctx); err != nil {
   344  				t.Fatalf("logout failed: %v", err)
   345  			}
   346  		})
   347  
   348  		t.Run("ValidateFaults", func(t *testing.T) {
   349  
   350  			t.Run("vim.NotAuthenticated", func(t *testing.T) {
   351  				t.Parallel()
   352  
   353  				// Create a finder to get the default datacenter.
   354  				finder := find.NewFinder(vimClient, true)
   355  
   356  				// Try to get the default datacenter, but receive a NotAuthenticated
   357  				// error.
   358  				_, err := finder.DefaultDatacenter(ctx)
   359  
   360  				if !fault.Is(err, &vim.NotAuthenticated{}) {
   361  					t.Fatal(err)
   362  				}
   363  			})
   364  
   365  			t.Run("eam.EamInvalidLogin", func(t *testing.T) {
   366  				t.Parallel()
   367  
   368  				// Get an EAM client.
   369  				eamClient := eam.NewClient(vimClient)
   370  
   371  				// Get the EAM root object.
   372  				mgr := object.NewEsxAgentManager(eamClient, eam.EsxAgentManager)
   373  
   374  				// Try to list the agencies, but receive an EamInvalidLogin error.
   375  				_, err := mgr.Agencies(ctx)
   376  
   377  				if !fault.Is(err, &types.EamInvalidLogin{}) {
   378  					t.Fatalf("err=%[1]T %+[1]v", err)
   379  				}
   380  			})
   381  		})
   382  
   383  	})
   384  }