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 }