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  }