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