github.com/spotmaxtech/k8s-apimachinery-v0260@v0.0.1/pkg/api/meta/priority.go (about) 1 /* 2 Copyright 2016 The Kubernetes Authors. 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 meta 18 19 import ( 20 "fmt" 21 22 "github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/runtime/schema" 23 ) 24 25 const ( 26 AnyGroup = "*" 27 AnyVersion = "*" 28 AnyResource = "*" 29 AnyKind = "*" 30 ) 31 32 var ( 33 _ ResettableRESTMapper = PriorityRESTMapper{} 34 ) 35 36 // PriorityRESTMapper is a wrapper for automatically choosing a particular Resource or Kind 37 // when multiple matches are possible 38 type PriorityRESTMapper struct { 39 // Delegate is the RESTMapper to use to locate all the Kind and Resource matches 40 Delegate RESTMapper 41 42 // ResourcePriority is a list of priority patterns to apply to matching resources. 43 // The list of all matching resources is narrowed based on the patterns until only one remains. 44 // A pattern with no matches is skipped. A pattern with more than one match uses its 45 // matches as the list to continue matching against. 46 ResourcePriority []schema.GroupVersionResource 47 48 // KindPriority is a list of priority patterns to apply to matching kinds. 49 // The list of all matching kinds is narrowed based on the patterns until only one remains. 50 // A pattern with no matches is skipped. A pattern with more than one match uses its 51 // matches as the list to continue matching against. 52 KindPriority []schema.GroupVersionKind 53 } 54 55 func (m PriorityRESTMapper) String() string { 56 return fmt.Sprintf("PriorityRESTMapper{\n\t%v\n\t%v\n\t%v\n}", m.ResourcePriority, m.KindPriority, m.Delegate) 57 } 58 59 // ResourceFor finds all resources, then passes them through the ResourcePriority patterns to find a single matching hit. 60 func (m PriorityRESTMapper) ResourceFor(partiallySpecifiedResource schema.GroupVersionResource) (schema.GroupVersionResource, error) { 61 originalGVRs, originalErr := m.Delegate.ResourcesFor(partiallySpecifiedResource) 62 if originalErr != nil && len(originalGVRs) == 0 { 63 return schema.GroupVersionResource{}, originalErr 64 } 65 if len(originalGVRs) == 1 { 66 return originalGVRs[0], originalErr 67 } 68 69 remainingGVRs := append([]schema.GroupVersionResource{}, originalGVRs...) 70 for _, pattern := range m.ResourcePriority { 71 matchedGVRs := []schema.GroupVersionResource{} 72 for _, gvr := range remainingGVRs { 73 if resourceMatches(pattern, gvr) { 74 matchedGVRs = append(matchedGVRs, gvr) 75 } 76 } 77 78 switch len(matchedGVRs) { 79 case 0: 80 // if you have no matches, then nothing matched this pattern just move to the next 81 continue 82 case 1: 83 // one match, return 84 return matchedGVRs[0], originalErr 85 default: 86 // more than one match, use the matched hits as the list moving to the next pattern. 87 // this way you can have a series of selection criteria 88 remainingGVRs = matchedGVRs 89 } 90 } 91 92 return schema.GroupVersionResource{}, &AmbiguousResourceError{PartialResource: partiallySpecifiedResource, MatchingResources: originalGVRs} 93 } 94 95 // KindFor finds all kinds, then passes them through the KindPriority patterns to find a single matching hit. 96 func (m PriorityRESTMapper) KindFor(partiallySpecifiedResource schema.GroupVersionResource) (schema.GroupVersionKind, error) { 97 originalGVKs, originalErr := m.Delegate.KindsFor(partiallySpecifiedResource) 98 if originalErr != nil && len(originalGVKs) == 0 { 99 return schema.GroupVersionKind{}, originalErr 100 } 101 if len(originalGVKs) == 1 { 102 return originalGVKs[0], originalErr 103 } 104 105 remainingGVKs := append([]schema.GroupVersionKind{}, originalGVKs...) 106 for _, pattern := range m.KindPriority { 107 matchedGVKs := []schema.GroupVersionKind{} 108 for _, gvr := range remainingGVKs { 109 if kindMatches(pattern, gvr) { 110 matchedGVKs = append(matchedGVKs, gvr) 111 } 112 } 113 114 switch len(matchedGVKs) { 115 case 0: 116 // if you have no matches, then nothing matched this pattern just move to the next 117 continue 118 case 1: 119 // one match, return 120 return matchedGVKs[0], originalErr 121 default: 122 // more than one match, use the matched hits as the list moving to the next pattern. 123 // this way you can have a series of selection criteria 124 remainingGVKs = matchedGVKs 125 } 126 } 127 128 return schema.GroupVersionKind{}, &AmbiguousResourceError{PartialResource: partiallySpecifiedResource, MatchingKinds: originalGVKs} 129 } 130 131 func resourceMatches(pattern schema.GroupVersionResource, resource schema.GroupVersionResource) bool { 132 if pattern.Group != AnyGroup && pattern.Group != resource.Group { 133 return false 134 } 135 if pattern.Version != AnyVersion && pattern.Version != resource.Version { 136 return false 137 } 138 if pattern.Resource != AnyResource && pattern.Resource != resource.Resource { 139 return false 140 } 141 142 return true 143 } 144 145 func kindMatches(pattern schema.GroupVersionKind, kind schema.GroupVersionKind) bool { 146 if pattern.Group != AnyGroup && pattern.Group != kind.Group { 147 return false 148 } 149 if pattern.Version != AnyVersion && pattern.Version != kind.Version { 150 return false 151 } 152 if pattern.Kind != AnyKind && pattern.Kind != kind.Kind { 153 return false 154 } 155 156 return true 157 } 158 159 func (m PriorityRESTMapper) RESTMapping(gk schema.GroupKind, versions ...string) (mapping *RESTMapping, err error) { 160 mappings, originalErr := m.Delegate.RESTMappings(gk, versions...) 161 if originalErr != nil && len(mappings) == 0 { 162 return nil, originalErr 163 } 164 165 // any versions the user provides take priority 166 priorities := m.KindPriority 167 if len(versions) > 0 { 168 priorities = make([]schema.GroupVersionKind, 0, len(m.KindPriority)+len(versions)) 169 for _, version := range versions { 170 gv := schema.GroupVersion{ 171 Version: version, 172 Group: gk.Group, 173 } 174 priorities = append(priorities, gv.WithKind(AnyKind)) 175 } 176 priorities = append(priorities, m.KindPriority...) 177 } 178 179 remaining := append([]*RESTMapping{}, mappings...) 180 for _, pattern := range priorities { 181 var matching []*RESTMapping 182 for _, m := range remaining { 183 if kindMatches(pattern, m.GroupVersionKind) { 184 matching = append(matching, m) 185 } 186 } 187 188 switch len(matching) { 189 case 0: 190 // if you have no matches, then nothing matched this pattern just move to the next 191 continue 192 case 1: 193 // one match, return 194 return matching[0], originalErr 195 default: 196 // more than one match, use the matched hits as the list moving to the next pattern. 197 // this way you can have a series of selection criteria 198 remaining = matching 199 } 200 } 201 if len(remaining) == 1 { 202 return remaining[0], originalErr 203 } 204 205 var kinds []schema.GroupVersionKind 206 for _, m := range mappings { 207 kinds = append(kinds, m.GroupVersionKind) 208 } 209 return nil, &AmbiguousKindError{PartialKind: gk.WithVersion(""), MatchingKinds: kinds} 210 } 211 212 func (m PriorityRESTMapper) RESTMappings(gk schema.GroupKind, versions ...string) ([]*RESTMapping, error) { 213 return m.Delegate.RESTMappings(gk, versions...) 214 } 215 216 func (m PriorityRESTMapper) ResourceSingularizer(resource string) (singular string, err error) { 217 return m.Delegate.ResourceSingularizer(resource) 218 } 219 220 func (m PriorityRESTMapper) ResourcesFor(partiallySpecifiedResource schema.GroupVersionResource) ([]schema.GroupVersionResource, error) { 221 return m.Delegate.ResourcesFor(partiallySpecifiedResource) 222 } 223 224 func (m PriorityRESTMapper) KindsFor(partiallySpecifiedResource schema.GroupVersionResource) (gvk []schema.GroupVersionKind, err error) { 225 return m.Delegate.KindsFor(partiallySpecifiedResource) 226 } 227 228 func (m PriorityRESTMapper) Reset() { 229 MaybeResetRESTMapper(m.Delegate) 230 }