github.com/vmware/govmomi@v0.51.0/property/match.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 property
     6  
     7  import (
     8  	"fmt"
     9  	"path"
    10  	"reflect"
    11  	"strconv"
    12  	"strings"
    13  
    14  	"github.com/vmware/govmomi/vim25/types"
    15  )
    16  
    17  // Match provides methods for matching against types.DynamicProperty
    18  type Match map[string]types.AnyType
    19  
    20  // Keys returns the Match map keys as a []string
    21  func (m Match) Keys() []string {
    22  	keys := make([]string, 0, len(m))
    23  
    24  	for key := range m {
    25  		keys = append(keys, key)
    26  	}
    27  
    28  	return keys
    29  }
    30  
    31  // Property returns true if an entry matches the given prop.
    32  func (m Match) Property(prop types.DynamicProperty) bool {
    33  	if prop.Val == nil {
    34  		return false
    35  	}
    36  	match, ok := m[prop.Name]
    37  	if !ok {
    38  		return false
    39  	}
    40  
    41  	if match == prop.Val {
    42  		return true
    43  	}
    44  
    45  	if matchFunc, ok := match.(func(any) bool); ok {
    46  		if matchFunc(prop.Val) {
    47  			return true
    48  		}
    49  	}
    50  
    51  	ptype := reflect.TypeOf(prop.Val)
    52  
    53  	if strings.HasPrefix(ptype.Name(), "ArrayOf") {
    54  		pval := reflect.ValueOf(prop.Val).Field(0)
    55  
    56  		for i := 0; i < pval.Len(); i++ {
    57  			prop.Val = pval.Index(i).Interface()
    58  
    59  			if m.Property(prop) {
    60  				return true
    61  			}
    62  		}
    63  
    64  		return false
    65  	}
    66  
    67  	if reflect.TypeOf(match) != ptype {
    68  		s, ok := match.(string)
    69  		if !ok {
    70  			return false
    71  		}
    72  
    73  		// convert if we can
    74  		switch val := prop.Val.(type) {
    75  		case bool:
    76  			match, _ = strconv.ParseBool(s)
    77  		case int16:
    78  			x, _ := strconv.ParseInt(s, 10, 16)
    79  			match = int16(x)
    80  		case int32:
    81  			x, _ := strconv.ParseInt(s, 10, 32)
    82  			match = int32(x)
    83  		case int64:
    84  			match, _ = strconv.ParseInt(s, 10, 64)
    85  		case float32:
    86  			x, _ := strconv.ParseFloat(s, 32)
    87  			match = float32(x)
    88  		case float64:
    89  			match, _ = strconv.ParseFloat(s, 64)
    90  		case fmt.Stringer:
    91  			prop.Val = val.String()
    92  		case *types.CustomFieldStringValue:
    93  			prop.Val = fmt.Sprintf("%d:%s", val.Key, val.Value)
    94  		default:
    95  			if ptype.Kind() != reflect.String {
    96  				return false
    97  			}
    98  			// An enum type we can convert to a string type
    99  			prop.Val = reflect.ValueOf(prop.Val).String()
   100  		}
   101  	}
   102  
   103  	switch pval := prop.Val.(type) {
   104  	case string:
   105  		s := match.(string)
   106  		if s == "*" {
   107  			return true // TODO: path.Match fails if s contains a '/'
   108  		}
   109  		m, _ := path.Match(s, pval)
   110  		return m
   111  	default:
   112  		return reflect.DeepEqual(match, pval)
   113  	}
   114  }
   115  
   116  // List returns true if all given props match.
   117  func (m Match) List(props []types.DynamicProperty) bool {
   118  	for _, p := range props {
   119  		if !m.Property(p) {
   120  			return false
   121  		}
   122  	}
   123  
   124  	return len(m) == len(props) // false if a property such as VM "guest" is unset
   125  }
   126  
   127  // ObjectContent returns a list of ObjectContent.Obj where the
   128  // ObjectContent.PropSet matches all properties the Filter.
   129  func (m Match) ObjectContent(objects []types.ObjectContent) []types.ManagedObjectReference {
   130  	var refs []types.ManagedObjectReference
   131  
   132  	for _, o := range objects {
   133  		if m.List(o.PropSet) {
   134  			refs = append(refs, o.Obj)
   135  		}
   136  	}
   137  
   138  	return refs
   139  }
   140  
   141  // AnyList returns true if any given props match.
   142  func (m Match) AnyList(props []types.DynamicProperty) bool {
   143  	for _, p := range props {
   144  		if m.Property(p) {
   145  			return true
   146  		}
   147  	}
   148  
   149  	return false
   150  }
   151  
   152  // AnyObjectContent returns a list of ObjectContent.Obj where the
   153  // ObjectContent.PropSet matches any property.
   154  func (m Match) AnyObjectContent(objects []types.ObjectContent) []types.ManagedObjectReference {
   155  	var refs []types.ManagedObjectReference
   156  
   157  	for _, o := range objects {
   158  		if m.AnyList(o.PropSet) {
   159  			refs = append(refs, o.Obj)
   160  		}
   161  	}
   162  
   163  	return refs
   164  }