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 }