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