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