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 }