github.com/vmware/govmomi@v0.37.1/pbm/client_test.go (about)

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