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