github.com/vmware/govmomi@v0.51.0/pbm/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
     6  
     7  import (
     8  	"context"
     9  	"log"
    10  	"reflect"
    11  	"sort"
    12  	"testing"
    13  
    14  	"github.com/vmware/govmomi"
    15  	"github.com/vmware/govmomi/pbm"
    16  	"github.com/vmware/govmomi/pbm/types"
    17  	"github.com/vmware/govmomi/property"
    18  	"github.com/vmware/govmomi/simulator"
    19  	"github.com/vmware/govmomi/view"
    20  	"github.com/vmware/govmomi/vim25/mo"
    21  	vim "github.com/vmware/govmomi/vim25/types"
    22  )
    23  
    24  // TestSimulator is a copy of pbm/client_test.go:ClientTest
    25  // The pbm package cannot import the pbm/simulator package due to cyclic dependency.
    26  func TestSimulator(t *testing.T) {
    27  	ctx := context.Background()
    28  
    29  	model := simulator.VPX()
    30  
    31  	defer model.Remove()
    32  	err := model.Create()
    33  	if err != nil {
    34  		log.Fatal(err)
    35  	}
    36  
    37  	s := model.Service.NewServer()
    38  	defer s.Close()
    39  
    40  	model.Service.RegisterSDK(New())
    41  
    42  	c, err := govmomi.NewClient(ctx, s.URL, true)
    43  	if err != nil {
    44  		t.Fatal(err)
    45  	}
    46  
    47  	pc, err := pbm.NewClient(ctx, c.Client)
    48  	if err != nil {
    49  		t.Fatal(err)
    50  	}
    51  
    52  	t.Logf("PBM version=%s", pc.ServiceContent.AboutInfo.Version)
    53  
    54  	rtype := types.PbmProfileResourceType{
    55  		ResourceType: string(types.PbmProfileResourceTypeEnumSTORAGE),
    56  	}
    57  
    58  	category := types.PbmProfileCategoryEnumREQUIREMENT
    59  
    60  	// 1. Query all the profiles on the vCenter.
    61  	ids, err := pc.QueryProfile(ctx, rtype, string(category))
    62  	if err != nil {
    63  		t.Fatal(err)
    64  	}
    65  
    66  	var qids []string
    67  
    68  	for _, id := range ids {
    69  		qids = append(qids, id.UniqueId)
    70  	}
    71  
    72  	var cids []string
    73  
    74  	// 2. Retrieve the content of all profiles.
    75  	policies, err := pc.RetrieveContent(ctx, ids)
    76  	if err != nil {
    77  		t.Fatal(err)
    78  	}
    79  
    80  	for i := range policies {
    81  		profile := policies[i].GetPbmProfile()
    82  		cids = append(cids, profile.ProfileId.UniqueId)
    83  	}
    84  
    85  	sort.Strings(qids)
    86  	sort.Strings(cids)
    87  
    88  	// Check whether ids retrieved from QueryProfile and RetrieveContent are identical.
    89  	if !reflect.DeepEqual(qids, cids) {
    90  		t.Error("ids mismatch")
    91  	}
    92  
    93  	// 3. Get list of datastores in a cluster if cluster name is specified.
    94  	root := c.ServiceContent.RootFolder
    95  	var datastores []vim.ManagedObjectReference
    96  	var kind []string
    97  	clusterName := "DC0_C0"
    98  	if clusterName == "" {
    99  		kind = []string{"Datastore"}
   100  	} else {
   101  		kind = []string{"ClusterComputeResource"}
   102  	}
   103  
   104  	m := view.NewManager(c.Client)
   105  
   106  	v, err := m.CreateContainerView(ctx, root, kind, true)
   107  	if err != nil {
   108  		t.Fatal(err)
   109  	}
   110  
   111  	if clusterName == "" {
   112  		datastores, err = v.Find(ctx, kind, nil)
   113  		if err != nil {
   114  			t.Fatal(err)
   115  		}
   116  	} else {
   117  		var cluster mo.ClusterComputeResource
   118  
   119  		err = v.RetrieveWithFilter(ctx, kind, []string{"datastore"}, &cluster, property.Match{"name": clusterName})
   120  		if err != nil {
   121  			t.Fatal(err)
   122  		}
   123  
   124  		datastores = cluster.Datastore
   125  	}
   126  
   127  	_ = v.Destroy(ctx)
   128  
   129  	t.Logf("checking %d datatores for compatibility results", len(datastores))
   130  
   131  	var hubs []types.PbmPlacementHub
   132  
   133  	for _, ds := range datastores {
   134  		hubs = append(hubs, types.PbmPlacementHub{
   135  			HubType: ds.Type,
   136  			HubId:   ds.Value,
   137  		})
   138  	}
   139  
   140  	var req []types.BasePbmPlacementRequirement
   141  
   142  	for _, id := range ids {
   143  		req = append(req, &types.PbmPlacementCapabilityProfileRequirement{
   144  			ProfileId: id,
   145  		})
   146  	}
   147  
   148  	// 4. Get the compatibility results for all the profiles on the vCenter.
   149  	res, err := pc.CheckRequirements(ctx, hubs, nil, req)
   150  	if err != nil {
   151  		t.Fatal(err)
   152  	}
   153  
   154  	t.Logf("CheckRequirements results: %d", len(res))
   155  
   156  	// user spec for the profile.
   157  	// VSAN profile with 2 capability instances - hostFailuresToTolerate = 2, stripeWidth = 1
   158  	pbmCreateSpecForVSAN := pbm.CapabilityProfileCreateSpec{
   159  		Name:        "Kubernetes-VSAN-TestPolicy",
   160  		Description: "VSAN Test policy create",
   161  		Category:    string(types.PbmProfileCategoryEnumREQUIREMENT),
   162  		CapabilityList: []pbm.Capability{
   163  			{
   164  				ID:        "hostFailuresToTolerate",
   165  				Namespace: "VSAN",
   166  				PropertyList: []pbm.Property{
   167  					{
   168  						ID:       "hostFailuresToTolerate",
   169  						Value:    "2",
   170  						DataType: "int",
   171  					},
   172  				},
   173  			},
   174  			{
   175  				ID:        "stripeWidth",
   176  				Namespace: "VSAN",
   177  				PropertyList: []pbm.Property{
   178  					{
   179  						ID:       "stripeWidth",
   180  						Value:    "1",
   181  						DataType: "int",
   182  					},
   183  				},
   184  			},
   185  		},
   186  	}
   187  
   188  	// Create PBM capability spec for the above defined user spec.
   189  	createSpecVSAN, err := pbm.CreateCapabilityProfileSpec(pbmCreateSpecForVSAN)
   190  	if err != nil {
   191  		t.Fatal(err)
   192  	}
   193  
   194  	// 5. Create SPBM VSAN profile.
   195  	vsanProfileID, err := pc.CreateProfile(ctx, *createSpecVSAN)
   196  	if err != nil {
   197  		t.Fatal(err)
   198  	}
   199  	t.Logf("VSAN Profile: %q successfully created", vsanProfileID.UniqueId)
   200  
   201  	// 6. Verify if profile created exists by issuing a RetrieveContent request.
   202  	profiles, err := pc.RetrieveContent(ctx, []types.PbmProfileId{*vsanProfileID})
   203  	if err != nil {
   204  		t.Fatal(err)
   205  	}
   206  	for _, profile := range profiles {
   207  		if cap, ok := profile.(*types.PbmCapabilityProfile); ok {
   208  			_, ok = cap.Constraints.(*types.PbmCapabilitySubProfileConstraints)
   209  			if !ok {
   210  				t.Errorf("cap=%T", cap.Constraints)
   211  			}
   212  		} else {
   213  			t.Errorf("profile=%T", profile)
   214  		}
   215  	}
   216  	t.Logf("Profile: %q exists on vCenter", vsanProfileID.UniqueId)
   217  
   218  	// 7. Get compatible datastores for the VSAN profile.
   219  	compatibleDatastores := res.CompatibleDatastores()
   220  	t.Logf("Found %d compatible-datastores for profile: %q", len(compatibleDatastores), vsanProfileID.UniqueId)
   221  
   222  	// 8. Get non-compatible datastores for the VSAN profile.
   223  	nonCompatibleDatastores := res.NonCompatibleDatastores()
   224  	t.Logf("Found %d non-compatible datastores for profile: %q", len(nonCompatibleDatastores), vsanProfileID.UniqueId)
   225  
   226  	// Check whether count of compatible and non-compatible datastores match the total number of datastores.
   227  	if (len(nonCompatibleDatastores) + len(compatibleDatastores)) != len(datastores) {
   228  		t.Error("datastore count mismatch")
   229  	}
   230  
   231  	// user spec for the profile.
   232  	// VSAN profile with 2 capability instances - stripeWidth = 1 and an SIOC profile.
   233  	pbmCreateSpecVSANandSIOC := pbm.CapabilityProfileCreateSpec{
   234  		Name:        "Kubernetes-VSAN-SIOC-TestPolicy",
   235  		Description: "VSAN-SIOC-Test policy create",
   236  		Category:    string(types.PbmProfileCategoryEnumREQUIREMENT),
   237  		CapabilityList: []pbm.Capability{
   238  			{
   239  				ID:        "stripeWidth",
   240  				Namespace: "VSAN",
   241  				PropertyList: []pbm.Property{
   242  					{
   243  						ID:       "stripeWidth",
   244  						Value:    "1",
   245  						DataType: "int",
   246  					},
   247  				},
   248  			},
   249  			{
   250  				ID:        "spm@DATASTOREIOCONTROL",
   251  				Namespace: "spm",
   252  				PropertyList: []pbm.Property{
   253  					{
   254  						ID:       "limit",
   255  						Value:    "200",
   256  						DataType: "int",
   257  					},
   258  					{
   259  						ID:       "reservation",
   260  						Value:    "1000",
   261  						DataType: "int",
   262  					},
   263  					{
   264  						ID:       "shares",
   265  						Value:    "2000",
   266  						DataType: "int",
   267  					},
   268  				},
   269  			},
   270  		},
   271  	}
   272  
   273  	// Create PBM capability spec for the above defined user spec.
   274  	createSpecVSANandSIOC, err := pbm.CreateCapabilityProfileSpec(pbmCreateSpecVSANandSIOC)
   275  	if err != nil {
   276  		t.Fatal(err)
   277  	}
   278  
   279  	// 9. Create SPBM VSAN profile.
   280  	vsansiocProfileID, err := pc.CreateProfile(ctx, *createSpecVSANandSIOC)
   281  	if err != nil {
   282  		t.Fatal(err)
   283  	}
   284  	t.Logf("VSAN-SIOC Profile: %q successfully created", vsansiocProfileID.UniqueId)
   285  
   286  	// 9. Get ProfileID by Name
   287  	profileID, err := pc.ProfileIDByName(ctx, "Kubernetes-VSAN-SIOC-TestPolicy")
   288  	if err != nil {
   289  		t.Fatal(err)
   290  	}
   291  
   292  	if vsansiocProfileID.UniqueId != profileID {
   293  		t.Errorf("vsan-sioc profile: %q and retrieved profileID: %q successfully matched", vsansiocProfileID.UniqueId, profileID)
   294  	}
   295  	t.Logf("VSAN-SIOC profile: %q and retrieved profileID: %q successfully matched", vsansiocProfileID.UniqueId, profileID)
   296  
   297  	// 10. Delete VSAN and VSAN-SIOC profile.
   298  	_, err = pc.DeleteProfile(ctx, []types.PbmProfileId{*vsanProfileID, *vsansiocProfileID})
   299  	if err != nil {
   300  		t.Fatal(err)
   301  	}
   302  	t.Logf("Profile: %+v successfully deleted", []types.PbmProfileId{*vsanProfileID, *vsansiocProfileID})
   303  }