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  }