github.com/vmware/govmomi@v0.51.0/pbm/pbm_util.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 pbm 6 7 import ( 8 "context" 9 "fmt" 10 "strconv" 11 "strings" 12 13 "github.com/vmware/govmomi/pbm/types" 14 "github.com/vmware/govmomi/property" 15 "github.com/vmware/govmomi/view" 16 "github.com/vmware/govmomi/vim25" 17 "github.com/vmware/govmomi/vim25/mo" 18 vim "github.com/vmware/govmomi/vim25/types" 19 ) 20 21 // A struct to capture pbm create spec details. 22 type CapabilityProfileCreateSpec struct { 23 Name string 24 SubProfileName string 25 Description string 26 Category string 27 CapabilityList []Capability 28 } 29 30 // A struct to capture pbm capability instance details. 31 type Capability struct { 32 ID string 33 Namespace string 34 PropertyList []Property 35 } 36 37 // A struct to capture pbm property instance details. 38 type Property struct { 39 ID string 40 Operator string 41 Value string 42 DataType string 43 } 44 45 func CreateCapabilityProfileSpec(pbmCreateSpec CapabilityProfileCreateSpec) (*types.PbmCapabilityProfileCreateSpec, error) { 46 capabilities, err := createCapabilityInstances(pbmCreateSpec.CapabilityList) 47 if err != nil { 48 return nil, err 49 } 50 51 pbmCapabilityProfileSpec := types.PbmCapabilityProfileCreateSpec{ 52 Name: pbmCreateSpec.Name, 53 Description: pbmCreateSpec.Description, 54 Category: pbmCreateSpec.Category, 55 ResourceType: types.PbmProfileResourceType{ 56 ResourceType: string(types.PbmProfileResourceTypeEnumSTORAGE), 57 }, 58 Constraints: &types.PbmCapabilitySubProfileConstraints{ 59 SubProfiles: []types.PbmCapabilitySubProfile{ 60 types.PbmCapabilitySubProfile{ 61 Capability: capabilities, 62 Name: pbmCreateSpec.SubProfileName, 63 }, 64 }, 65 }, 66 } 67 return &pbmCapabilityProfileSpec, nil 68 } 69 70 func createCapabilityInstances(rules []Capability) ([]types.PbmCapabilityInstance, error) { 71 var capabilityInstances []types.PbmCapabilityInstance 72 for _, capabilityRule := range rules { 73 capability := types.PbmCapabilityInstance{ 74 Id: types.PbmCapabilityMetadataUniqueId{ 75 Namespace: capabilityRule.Namespace, 76 Id: capabilityRule.ID, 77 }, 78 } 79 80 var propertyInstances []types.PbmCapabilityPropertyInstance 81 for _, propertyRule := range capabilityRule.PropertyList { 82 property := types.PbmCapabilityPropertyInstance{ 83 Id: propertyRule.ID, 84 } 85 if propertyRule.Operator != "" { 86 property.Operator = propertyRule.Operator 87 } 88 var err error 89 switch strings.ToLower(propertyRule.DataType) { 90 case "int": 91 // Go int32 is marshalled to xsi:int whereas Go int is marshalled to xsi:long when sending down the wire. 92 var val int32 93 val, err = verifyPropertyValueIsInt(propertyRule.Value, propertyRule.DataType) 94 property.Value = val 95 case "bool": 96 var val bool 97 val, err = verifyPropertyValueIsBoolean(propertyRule.Value, propertyRule.DataType) 98 property.Value = val 99 case "string": 100 property.Value = propertyRule.Value 101 case "set": 102 set := types.PbmCapabilityDiscreteSet{} 103 for _, val := range strings.Split(propertyRule.Value, ",") { 104 set.Values = append(set.Values, val) 105 } 106 property.Value = set 107 default: 108 return nil, fmt.Errorf("invalid value: %q with datatype: %q", propertyRule.Value, propertyRule.Value) 109 } 110 if err != nil { 111 return nil, fmt.Errorf("invalid value: %q with datatype: %q", propertyRule.Value, propertyRule.Value) 112 } 113 propertyInstances = append(propertyInstances, property) 114 } 115 constraintInstances := []types.PbmCapabilityConstraintInstance{ 116 types.PbmCapabilityConstraintInstance{ 117 PropertyInstance: propertyInstances, 118 }, 119 } 120 capability.Constraint = constraintInstances 121 capabilityInstances = append(capabilityInstances, capability) 122 } 123 return capabilityInstances, nil 124 } 125 126 // Verify if the capability value is of type integer. 127 func verifyPropertyValueIsInt(propertyValue string, dataType string) (int32, error) { 128 val, err := strconv.ParseInt(propertyValue, 10, 32) 129 if err != nil { 130 return -1, err 131 } 132 return int32(val), nil 133 } 134 135 // Verify if the capability value is of type integer. 136 func verifyPropertyValueIsBoolean(propertyValue string, dataType string) (bool, error) { 137 val, err := strconv.ParseBool(propertyValue) 138 if err != nil { 139 return false, err 140 } 141 return val, nil 142 } 143 144 // ProfileMap contains a map of storage profiles by name. 145 type ProfileMap struct { 146 Name map[string]types.BasePbmProfile 147 Profile []types.BasePbmProfile 148 } 149 150 // ProfileMap builds a map of storage profiles by name. 151 func (c *Client) ProfileMap(ctx context.Context, uid ...string) (*ProfileMap, error) { 152 m := &ProfileMap{Name: make(map[string]types.BasePbmProfile)} 153 154 rtype := types.PbmProfileResourceType{ 155 ResourceType: string(types.PbmProfileResourceTypeEnumSTORAGE), 156 } 157 158 category := types.PbmProfileCategoryEnumREQUIREMENT 159 160 var ids []types.PbmProfileId 161 if len(uid) == 0 { 162 var err error 163 ids, err = c.QueryProfile(ctx, rtype, string(category)) 164 if err != nil { 165 return nil, err 166 } 167 } else { 168 ids = make([]types.PbmProfileId, len(uid)) 169 for i, id := range uid { 170 ids[i].UniqueId = id 171 } 172 } 173 174 profiles, err := c.RetrieveContent(ctx, ids) 175 if err != nil { 176 return nil, err 177 } 178 m.Profile = profiles 179 180 for _, p := range profiles { 181 base := p.GetPbmProfile() 182 m.Name[base.Name] = p 183 m.Name[base.ProfileId.UniqueId] = p 184 } 185 186 return m, nil 187 } 188 189 // DatastoreMap contains a map of Datastore by name. 190 type DatastoreMap struct { 191 Name map[string]string 192 PlacementHub []types.PbmPlacementHub 193 } 194 195 // DatastoreMap returns a map of Datastore by name. 196 // The root reference can be a ClusterComputeResource or Folder. 197 func (c *Client) DatastoreMap(ctx context.Context, vc *vim25.Client, root vim.ManagedObjectReference) (*DatastoreMap, error) { 198 m := &DatastoreMap{Name: make(map[string]string)} 199 200 prop := []string{"name"} 201 var content []vim.ObjectContent 202 203 if root.Type == "ClusterComputeResource" { 204 pc := property.DefaultCollector(vc) 205 var cluster mo.ClusterComputeResource 206 207 if err := pc.RetrieveOne(ctx, root, []string{"datastore"}, &cluster); err != nil { 208 return nil, err 209 } 210 211 if err := pc.Retrieve(ctx, cluster.Datastore, prop, &content); err != nil { 212 return nil, err 213 } 214 } else { 215 kind := []string{"Datastore"} 216 m := view.NewManager(vc) 217 218 v, err := m.CreateContainerView(ctx, root, kind, true) 219 if err != nil { 220 return nil, err 221 } 222 223 err = v.Retrieve(ctx, kind, prop, &content) 224 _ = v.Destroy(ctx) 225 if err != nil { 226 return nil, err 227 } 228 } 229 230 for _, item := range content { 231 m.PlacementHub = append(m.PlacementHub, types.PbmPlacementHub{ 232 HubType: item.Obj.Type, 233 HubId: item.Obj.Value, 234 }) 235 m.Name[item.Obj.Value] = item.PropSet[0].Val.(string) 236 } 237 238 return m, nil 239 }