match.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. /*
  2. Copyright (c) 2017-2024 VMware, Inc. All Rights Reserved.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package property
  14. import (
  15. "fmt"
  16. "path"
  17. "reflect"
  18. "strconv"
  19. "strings"
  20. "github.com/vmware/govmomi/vim25/types"
  21. )
  22. // Match provides methods for matching against types.DynamicProperty
  23. type Match map[string]types.AnyType
  24. // Keys returns the Match map keys as a []string
  25. func (m Match) Keys() []string {
  26. keys := make([]string, 0, len(m))
  27. for key := range m {
  28. keys = append(keys, key)
  29. }
  30. return keys
  31. }
  32. // Property returns true if an entry matches the given prop.
  33. func (m Match) Property(prop types.DynamicProperty) bool {
  34. if prop.Val == nil {
  35. return false
  36. }
  37. match, ok := m[prop.Name]
  38. if !ok {
  39. return false
  40. }
  41. if match == prop.Val {
  42. return true
  43. }
  44. ptype := reflect.TypeOf(prop.Val)
  45. if strings.HasPrefix(ptype.Name(), "ArrayOf") {
  46. pval := reflect.ValueOf(prop.Val).Field(0)
  47. for i := 0; i < pval.Len(); i++ {
  48. prop.Val = pval.Index(i).Interface()
  49. if m.Property(prop) {
  50. return true
  51. }
  52. }
  53. return false
  54. }
  55. if reflect.TypeOf(match) != ptype {
  56. s, ok := match.(string)
  57. if !ok {
  58. return false
  59. }
  60. // convert if we can
  61. switch val := prop.Val.(type) {
  62. case bool:
  63. match, _ = strconv.ParseBool(s)
  64. case int16:
  65. x, _ := strconv.ParseInt(s, 10, 16)
  66. match = int16(x)
  67. case int32:
  68. x, _ := strconv.ParseInt(s, 10, 32)
  69. match = int32(x)
  70. case int64:
  71. match, _ = strconv.ParseInt(s, 10, 64)
  72. case float32:
  73. x, _ := strconv.ParseFloat(s, 32)
  74. match = float32(x)
  75. case float64:
  76. match, _ = strconv.ParseFloat(s, 64)
  77. case fmt.Stringer:
  78. prop.Val = val.String()
  79. case *types.CustomFieldStringValue:
  80. prop.Val = fmt.Sprintf("%d:%s", val.Key, val.Value)
  81. default:
  82. if ptype.Kind() != reflect.String {
  83. return false
  84. }
  85. // An enum type we can convert to a string type
  86. prop.Val = reflect.ValueOf(prop.Val).String()
  87. }
  88. }
  89. switch pval := prop.Val.(type) {
  90. case string:
  91. s := match.(string)
  92. if s == "*" {
  93. return true // TODO: path.Match fails if s contains a '/'
  94. }
  95. m, _ := path.Match(s, pval)
  96. return m
  97. default:
  98. return reflect.DeepEqual(match, pval)
  99. }
  100. }
  101. // List returns true if all given props match.
  102. func (m Match) List(props []types.DynamicProperty) bool {
  103. for _, p := range props {
  104. if !m.Property(p) {
  105. return false
  106. }
  107. }
  108. return len(m) == len(props) // false if a property such as VM "guest" is unset
  109. }
  110. // ObjectContent returns a list of ObjectContent.Obj where the
  111. // ObjectContent.PropSet matches all properties the Filter.
  112. func (m Match) ObjectContent(objects []types.ObjectContent) []types.ManagedObjectReference {
  113. var refs []types.ManagedObjectReference
  114. for _, o := range objects {
  115. if m.List(o.PropSet) {
  116. refs = append(refs, o.Obj)
  117. }
  118. }
  119. return refs
  120. }
  121. // AnyList returns true if any given props match.
  122. func (m Match) AnyList(props []types.DynamicProperty) bool {
  123. for _, p := range props {
  124. if m.Property(p) {
  125. return true
  126. }
  127. }
  128. return false
  129. }
  130. // AnyObjectContent returns a list of ObjectContent.Obj where the
  131. // ObjectContent.PropSet matches any property.
  132. func (m Match) AnyObjectContent(objects []types.ObjectContent) []types.ManagedObjectReference {
  133. var refs []types.ManagedObjectReference
  134. for _, o := range objects {
  135. if m.AnyList(o.PropSet) {
  136. refs = append(refs, o.Obj)
  137. }
  138. }
  139. return refs
  140. }