github.com/vmware/govmomi@v0.51.0/eam/object/agency_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 object_test
     6  
     7  import (
     8  	"errors"
     9  	"fmt"
    10  	"testing"
    11  	"time"
    12  
    13  	"github.com/vmware/govmomi/eam/object"
    14  	"github.com/vmware/govmomi/eam/types"
    15  	"github.com/vmware/govmomi/find"
    16  	"github.com/vmware/govmomi/vim25/soap"
    17  	vim "github.com/vmware/govmomi/vim25/types"
    18  )
    19  
    20  func TestAgency(t *testing.T) {
    21  
    22  	// Create a finder that sets the default datacenter.
    23  	finder := find.NewFinder(client.vim, true)
    24  
    25  	// Get the datacenter to use when creating the agency.
    26  	datacenter, err := finder.DefaultDatacenter(client.ctx)
    27  	if err != nil {
    28  		t.Fatal(err)
    29  	}
    30  	finder.SetDatacenter(datacenter)
    31  
    32  	// Get the "vm" folder.
    33  	folder, err := finder.DefaultFolder(client.ctx)
    34  	if err != nil {
    35  		t.Fatal(err)
    36  	}
    37  
    38  	// Get the cluster to use when creating the agency.
    39  	computeResource, err := finder.ClusterComputeResourceOrDefault(client.ctx, "")
    40  	if err != nil {
    41  		t.Fatal(err)
    42  	}
    43  
    44  	// Get the resource pool to use when creating the agency.
    45  	pool, err := computeResource.ResourcePool(client.ctx)
    46  	if err != nil {
    47  		t.Fatal(err)
    48  	}
    49  
    50  	// Get the datastore to use when creating the agency.
    51  	datastore, err := finder.DatastoreOrDefault(client.ctx, "")
    52  	if err != nil {
    53  		t.Fatal(err)
    54  	}
    55  
    56  	// Get the network to use when creating the agency.
    57  	network, err := finder.NetworkOrDefault(client.ctx, "DVS0")
    58  	if err != nil {
    59  		t.Fatal(err)
    60  	}
    61  
    62  	const (
    63  		initialGoalState = string(types.EamObjectRuntimeInfoGoalStateEnabled)
    64  	)
    65  	var (
    66  		agency       object.Agency
    67  		agencyConfig = &types.AgencyConfigInfo{
    68  			AgencyName: t.Name(),
    69  			AgentName:  t.Name(),
    70  			AgentConfig: []types.AgentConfigInfo{
    71  				{
    72  					HostVersion: "1",
    73  				},
    74  			},
    75  			AgentVmDatastore: []vim.ManagedObjectReference{
    76  				datastore.Reference(),
    77  			},
    78  			Folders: []types.AgencyVMFolder{
    79  				{
    80  					FolderId:     folder.Reference(),
    81  					DatacenterId: datacenter.Reference(),
    82  				},
    83  			},
    84  			ResourcePools: []types.AgencyVMResourcePool{
    85  				{
    86  					ResourcePoolId:    pool.Reference(),
    87  					ComputeResourceId: computeResource.Reference(),
    88  				},
    89  			},
    90  			AgentVmNetwork: []vim.ManagedObjectReference{
    91  				network.Reference(),
    92  			},
    93  		}
    94  	)
    95  
    96  	agencyExists := func(agency object.Agency) (bool, error) {
    97  		agencies, err := client.eam.Agencies(client.ctx)
    98  		if err != nil {
    99  			return false, err
   100  		}
   101  		for _, a := range agencies {
   102  			if a.Reference() == agency.Reference() {
   103  				return true, nil
   104  			}
   105  		}
   106  		return false, nil
   107  	}
   108  
   109  	testCreate := func(t *testing.T) {
   110  		var err error
   111  		if agency, err = client.eam.CreateAgency(
   112  			client.ctx, agencyConfig, initialGoalState); err != nil {
   113  			t.Fatal(err)
   114  		}
   115  		if ok, err := agencyExists(agency); !ok {
   116  			if err != nil {
   117  				t.Fatal(err)
   118  			}
   119  			t.Fatal("agency not returned by Agencies")
   120  		}
   121  	}
   122  
   123  	testConfig := func(t *testing.T) {
   124  		t.Parallel()
   125  
   126  		baseConfig, err := agency.Config(client.ctx)
   127  		if err != nil {
   128  			t.Fatal(err)
   129  		}
   130  		config := baseConfig.GetAgencyConfigInfo()
   131  		if config.AgencyName != agencyConfig.AgencyName {
   132  			t.Fatalf(
   133  				"unexpected agency name: exp=%v, act=%v",
   134  				agencyConfig.AgencyName,
   135  				config.AgencyName)
   136  		}
   137  		if config.AgentName != agencyConfig.AgentName {
   138  			t.Fatalf(
   139  				"unexpected agency agent name: exp=%v, act=%v",
   140  				agencyConfig.AgentName,
   141  				config.AgentName)
   142  		}
   143  	}
   144  
   145  	// This test waits up to 10 seconds for the agency.runtime.issue
   146  	// list to be non-empty. Because this test is run in parallel with
   147  	// the TestAgency.Created.Runtime.Issues.Add test, there should be an
   148  	// issue returned by the tested call before 10 seconds has elapsed.
   149  	testRuntimeIssues := func(t *testing.T) {
   150  		t.Parallel()
   151  		const (
   152  			waitTotalSecs    = 10
   153  			waitIntervalSecs = time.Duration(1) * time.Second
   154  		)
   155  		hasIssues := false
   156  		for i := 0; i < waitTotalSecs; i++ {
   157  			runtime, err := agency.Runtime(client.ctx)
   158  			if err != nil {
   159  				t.Fatal(err)
   160  			}
   161  			if len(runtime.Issue) > 0 {
   162  				hasIssues = true
   163  				break
   164  			}
   165  			time.Sleep(waitIntervalSecs)
   166  		}
   167  		if !hasIssues {
   168  			t.Fatalf(
   169  				"agency.runtime had no issues after %d seconds",
   170  				waitTotalSecs)
   171  		}
   172  	}
   173  
   174  	testRuntimeGoalState := func(t *testing.T) {
   175  		validateExpectedGoalState := func(expGoalState any) error {
   176  			runtime, err := agency.Runtime(client.ctx)
   177  			if err != nil {
   178  				return err
   179  			}
   180  			if runtime.GoalState != fmt.Sprintf("%s", expGoalState) {
   181  				return fmt.Errorf(
   182  					"unexpected agency goal state: exp=%v, act=%v",
   183  					expGoalState,
   184  					runtime.GoalState)
   185  			}
   186  			return nil
   187  		}
   188  
   189  		t.Run("Initial", func(t *testing.T) {
   190  			if err := validateExpectedGoalState(
   191  				initialGoalState); err != nil {
   192  				t.Fatal(err)
   193  			}
   194  		})
   195  		t.Run("Disabled", func(t *testing.T) {
   196  			if err := agency.Disable(client.ctx); err != nil {
   197  				t.Fatal(err)
   198  			}
   199  			if err := validateExpectedGoalState(
   200  				types.EamObjectRuntimeInfoGoalStateDisabled); err != nil {
   201  				t.Fatal(err)
   202  			}
   203  		})
   204  		t.Run("Uninstalled", func(t *testing.T) {
   205  			if err := agency.Uninstall(client.ctx); err != nil {
   206  				t.Fatal(err)
   207  			}
   208  			if err := validateExpectedGoalState(
   209  				types.EamObjectRuntimeInfoGoalStateUninstalled); err != nil {
   210  				t.Fatal(err)
   211  			}
   212  		})
   213  		t.Run("Enabled", func(t *testing.T) {
   214  			if err := agency.Enable(client.ctx); err != nil {
   215  				t.Fatal(err)
   216  			}
   217  			if err := validateExpectedGoalState(
   218  				types.EamObjectRuntimeInfoGoalStateEnabled); err != nil {
   219  				t.Fatal(err)
   220  			}
   221  		})
   222  	}
   223  
   224  	testRuntime := func(t *testing.T) {
   225  		t.Parallel()
   226  
   227  		runtime, err := agency.Runtime(client.ctx)
   228  		if err != nil {
   229  			t.Fatal(err)
   230  		}
   231  		if runtime.GoalState != initialGoalState {
   232  			t.Fatalf(
   233  				"unexpected agency goal state: exp=%v, act=%v",
   234  				initialGoalState,
   235  				runtime.GoalState)
   236  		}
   237  
   238  		t.Run("Issues", testRuntimeIssues)
   239  		t.Run("GoalState", testRuntimeGoalState)
   240  	}
   241  
   242  	testIssues := func(t *testing.T) {
   243  		t.Parallel()
   244  
   245  		var issueKey int32
   246  
   247  		t.Run("Add", func(t *testing.T) {
   248  			baseIssue, err := agency.AddIssue(client.ctx, &types.OrphanedAgency{
   249  				AgencyIssue: types.AgencyIssue{
   250  					Agency:     agency.Reference(),
   251  					AgencyName: agencyConfig.AgencyName,
   252  				},
   253  			})
   254  			if err != nil {
   255  				t.Fatal(err)
   256  			}
   257  			baseAgencyIssue, ok := baseIssue.(types.BaseAgencyIssue)
   258  			if !ok {
   259  				t.Fatalf(
   260  					"unexpected issue type: exp=%v, act=%T",
   261  					"types.BaseAgencyIssue",
   262  					baseIssue)
   263  			}
   264  			issue := baseAgencyIssue.GetAgencyIssue()
   265  			if issue == nil {
   266  				t.Fatal("returned issue is nil")
   267  			}
   268  			if issue.Key == 0 {
   269  				t.Fatal("issue.Key == 0")
   270  			}
   271  			if issue.Time.IsZero() {
   272  				t.Fatal("issue.Time is not set")
   273  			}
   274  			if issue.Agency != agency.Reference() {
   275  				t.Fatalf(
   276  					"unexpected agency moRef: exp=%v, act=%v",
   277  					agency.Reference(),
   278  					issue.Agency)
   279  			}
   280  			if issue.AgencyName != agencyConfig.AgencyName {
   281  				t.Fatalf(
   282  					"unexpected agency name: exp=%v, act=%v",
   283  					agencyConfig.AgencyName,
   284  					issue.AgencyName)
   285  			}
   286  			issueKey = issue.Key
   287  			t.Logf("added new issue to agency: agency=%v, issueKey=%d",
   288  				agency.Reference(), issueKey)
   289  		})
   290  
   291  		t.Run("Query", func(t *testing.T) {
   292  			validateIssueIsInList := func(
   293  				issues []types.BaseIssue,
   294  				inErr error) error {
   295  
   296  				if inErr != nil {
   297  					return inErr
   298  				}
   299  				if len(issues) == 0 {
   300  					return errors.New("no issues returned")
   301  				}
   302  				foundIssueKey := false
   303  				for _, baseIssue := range issues {
   304  					issue := baseIssue.GetIssue()
   305  					if issue == nil {
   306  						return errors.New("returned issue is nil")
   307  					}
   308  					if issue.Key == issueKey {
   309  						foundIssueKey = true
   310  						break
   311  					}
   312  				}
   313  				if !foundIssueKey {
   314  					return fmt.Errorf(
   315  						"did not find expected issue: key=%d", issueKey)
   316  				}
   317  				return nil
   318  			}
   319  
   320  			t.Run("All", func(t *testing.T) {
   321  				t.Parallel()
   322  				if err := validateIssueIsInList(
   323  					agency.Issues(client.ctx)); err != nil {
   324  					t.Fatal(err)
   325  				}
   326  			})
   327  			t.Run("ByKey", func(t *testing.T) {
   328  				t.Parallel()
   329  				if err := validateIssueIsInList(
   330  					agency.Issues(client.ctx, issueKey)); err != nil {
   331  					t.Fatal(err)
   332  				}
   333  			})
   334  		})
   335  	}
   336  
   337  	testAgents := func(t *testing.T) {
   338  		t.Parallel()
   339  
   340  		var agent *object.Agent
   341  
   342  		t.Run("Query", func(t *testing.T) {
   343  			agents, err := agency.Agents(client.ctx)
   344  			if err != nil {
   345  				t.Fatal(err)
   346  			}
   347  			if len(agents) != 1 {
   348  				t.Fatal("expected one agent")
   349  			}
   350  			agent = &agents[0]
   351  		})
   352  
   353  		t.Run("Queried", func(t *testing.T) {
   354  			t.Run("Config", func(t *testing.T) {
   355  				t.Parallel()
   356  				config, err := agent.Config(client.ctx)
   357  				if err != nil {
   358  					t.Fatal(err)
   359  				}
   360  				if config.HostVersion != "1" {
   361  					t.Fatalf(
   362  						"unexpected agent config host version: exp=%v, act=%v",
   363  						"1",
   364  						config.HostVersion)
   365  				}
   366  			})
   367  			t.Run("Runtime", func(t *testing.T) {
   368  				t.Parallel()
   369  				var runtime *types.AgentRuntimeInfo
   370  
   371  				t.Run("Query", func(t *testing.T) {
   372  					var err error
   373  					if runtime, err = agent.Runtime(client.ctx); err != nil {
   374  						t.Fatal(err)
   375  					} else if runtime.Agency == nil {
   376  						t.Fatal("agent runtime.Agency is nil")
   377  					}
   378  				})
   379  				t.Run("Properties", func(t *testing.T) {
   380  					t.Run("Agency", func(t *testing.T) {
   381  						t.Parallel()
   382  						if *runtime.Agency != agency.Reference() {
   383  							t.Fatalf(
   384  								"unexpected agent runtime.Agency: exp=%v, act=%v",
   385  								agency.Reference(),
   386  								*runtime.Agency)
   387  						}
   388  					})
   389  					t.Run("VirtualMachine", func(t *testing.T) {
   390  						t.Parallel()
   391  						if runtime.Vm == nil {
   392  							t.Fatal("runtime.Vm is nil")
   393  						}
   394  					})
   395  				})
   396  			})
   397  		})
   398  	}
   399  
   400  	testDestroy := func(t *testing.T) {
   401  		t.Run("HappyPath", func(t *testing.T) {
   402  			if err := agency.Destroy(client.ctx); err != nil {
   403  				t.Fatal(err)
   404  			}
   405  		})
   406  
   407  		// Attempt to destroy the agency a second time, asserting that a
   408  		// ManagedObjectNotFound error will occur.
   409  		t.Run("NotFound", func(t *testing.T) {
   410  			if err := agency.Destroy(client.ctx); err == nil {
   411  				t.Fatal("error did not occur")
   412  			} else if fault := soap.ToSoapFault(err); fault == nil {
   413  				t.Fatalf("soap fault did not occur: %+v", err)
   414  			} else if fault, ok := fault.VimFault().(vim.ManagedObjectNotFound); !ok {
   415  				t.Fatalf("expected soap fault did not occur: %+v", fault)
   416  			} else if fault.Obj != agency.Reference() {
   417  				t.Fatalf("unexpected error details: exp=%v, act=%v",
   418  					agency.Reference(), fault.Obj)
   419  			}
   420  		})
   421  
   422  		t.Run("Verify", func(t *testing.T) {
   423  			if ok, err := agencyExists(agency); err != nil {
   424  				t.Fatal(err)
   425  			} else if ok {
   426  				t.Fatal("agency still returned after being destroyed")
   427  			}
   428  		})
   429  	}
   430  
   431  	t.Run("Create", testCreate)
   432  
   433  	t.Run("Created", func(t *testing.T) {
   434  		t.Run("Config", testConfig)
   435  		t.Run("Issues", testIssues)
   436  		t.Run("Runtime", testRuntime)
   437  		t.Run("Agents", testAgents)
   438  	})
   439  
   440  	t.Run("Destroy", testDestroy)
   441  }