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  }