Remove BPA from Makefile
[icn.git] / cmd / bpa-operator / vendor / k8s.io / client-go / restmapper / shortcut.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 restmapper
18
19 import (
20         "strings"
21
22         "k8s.io/klog"
23
24         "k8s.io/apimachinery/pkg/api/meta"
25         metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
26         "k8s.io/apimachinery/pkg/runtime/schema"
27         "k8s.io/client-go/discovery"
28 )
29
30 // shortcutExpander is a RESTMapper that can be used for Kubernetes resources.   It expands the resource first, then invokes the wrapped
31 type shortcutExpander struct {
32         RESTMapper meta.RESTMapper
33
34         discoveryClient discovery.DiscoveryInterface
35 }
36
37 var _ meta.RESTMapper = &shortcutExpander{}
38
39 // NewShortcutExpander wraps a restmapper in a layer that expands shortcuts found via discovery
40 func NewShortcutExpander(delegate meta.RESTMapper, client discovery.DiscoveryInterface) meta.RESTMapper {
41         return shortcutExpander{RESTMapper: delegate, discoveryClient: client}
42 }
43
44 // KindFor fulfills meta.RESTMapper
45 func (e shortcutExpander) KindFor(resource schema.GroupVersionResource) (schema.GroupVersionKind, error) {
46         return e.RESTMapper.KindFor(e.expandResourceShortcut(resource))
47 }
48
49 // KindsFor fulfills meta.RESTMapper
50 func (e shortcutExpander) KindsFor(resource schema.GroupVersionResource) ([]schema.GroupVersionKind, error) {
51         return e.RESTMapper.KindsFor(e.expandResourceShortcut(resource))
52 }
53
54 // ResourcesFor fulfills meta.RESTMapper
55 func (e shortcutExpander) ResourcesFor(resource schema.GroupVersionResource) ([]schema.GroupVersionResource, error) {
56         return e.RESTMapper.ResourcesFor(e.expandResourceShortcut(resource))
57 }
58
59 // ResourceFor fulfills meta.RESTMapper
60 func (e shortcutExpander) ResourceFor(resource schema.GroupVersionResource) (schema.GroupVersionResource, error) {
61         return e.RESTMapper.ResourceFor(e.expandResourceShortcut(resource))
62 }
63
64 // ResourceSingularizer fulfills meta.RESTMapper
65 func (e shortcutExpander) ResourceSingularizer(resource string) (string, error) {
66         return e.RESTMapper.ResourceSingularizer(e.expandResourceShortcut(schema.GroupVersionResource{Resource: resource}).Resource)
67 }
68
69 // RESTMapping fulfills meta.RESTMapper
70 func (e shortcutExpander) RESTMapping(gk schema.GroupKind, versions ...string) (*meta.RESTMapping, error) {
71         return e.RESTMapper.RESTMapping(gk, versions...)
72 }
73
74 // RESTMappings fulfills meta.RESTMapper
75 func (e shortcutExpander) RESTMappings(gk schema.GroupKind, versions ...string) ([]*meta.RESTMapping, error) {
76         return e.RESTMapper.RESTMappings(gk, versions...)
77 }
78
79 // getShortcutMappings returns a set of tuples which holds short names for resources.
80 // First the list of potential resources will be taken from the API server.
81 // Next we will append the hardcoded list of resources - to be backward compatible with old servers.
82 // NOTE that the list is ordered by group priority.
83 func (e shortcutExpander) getShortcutMappings() ([]*metav1.APIResourceList, []resourceShortcuts, error) {
84         res := []resourceShortcuts{}
85         // get server resources
86         // This can return an error *and* the results it was able to find.  We don't need to fail on the error.
87         apiResList, err := e.discoveryClient.ServerResources()
88         if err != nil {
89                 klog.V(1).Infof("Error loading discovery information: %v", err)
90         }
91         for _, apiResources := range apiResList {
92                 gv, err := schema.ParseGroupVersion(apiResources.GroupVersion)
93                 if err != nil {
94                         klog.V(1).Infof("Unable to parse groupversion = %s due to = %s", apiResources.GroupVersion, err.Error())
95                         continue
96                 }
97                 for _, apiRes := range apiResources.APIResources {
98                         for _, shortName := range apiRes.ShortNames {
99                                 rs := resourceShortcuts{
100                                         ShortForm: schema.GroupResource{Group: gv.Group, Resource: shortName},
101                                         LongForm:  schema.GroupResource{Group: gv.Group, Resource: apiRes.Name},
102                                 }
103                                 res = append(res, rs)
104                         }
105                 }
106         }
107
108         return apiResList, res, nil
109 }
110
111 // expandResourceShortcut will return the expanded version of resource
112 // (something that a pkg/api/meta.RESTMapper can understand), if it is
113 // indeed a shortcut. If no match has been found, we will match on group prefixing.
114 // Lastly we will return resource unmodified.
115 func (e shortcutExpander) expandResourceShortcut(resource schema.GroupVersionResource) schema.GroupVersionResource {
116         // get the shortcut mappings and return on first match.
117         if allResources, shortcutResources, err := e.getShortcutMappings(); err == nil {
118                 // avoid expanding if there's an exact match to a full resource name
119                 for _, apiResources := range allResources {
120                         gv, err := schema.ParseGroupVersion(apiResources.GroupVersion)
121                         if err != nil {
122                                 continue
123                         }
124                         if len(resource.Group) != 0 && resource.Group != gv.Group {
125                                 continue
126                         }
127                         for _, apiRes := range apiResources.APIResources {
128                                 if resource.Resource == apiRes.Name {
129                                         return resource
130                                 }
131                                 if resource.Resource == apiRes.SingularName {
132                                         return resource
133                                 }
134                         }
135                 }
136
137                 for _, item := range shortcutResources {
138                         if len(resource.Group) != 0 && resource.Group != item.ShortForm.Group {
139                                 continue
140                         }
141                         if resource.Resource == item.ShortForm.Resource {
142                                 resource.Resource = item.LongForm.Resource
143                                 resource.Group = item.LongForm.Group
144                                 return resource
145                         }
146                 }
147
148                 // we didn't find exact match so match on group prefixing. This allows autoscal to match autoscaling
149                 if len(resource.Group) == 0 {
150                         return resource
151                 }
152                 for _, item := range shortcutResources {
153                         if !strings.HasPrefix(item.ShortForm.Group, resource.Group) {
154                                 continue
155                         }
156                         if resource.Resource == item.ShortForm.Resource {
157                                 resource.Resource = item.LongForm.Resource
158                                 resource.Group = item.LongForm.Group
159                                 return resource
160                         }
161                 }
162         }
163
164         return resource
165 }
166
167 // ResourceShortcuts represents a structure that holds the information how to
168 // transition from resource's shortcut to its full name.
169 type resourceShortcuts struct {
170         ShortForm schema.GroupResource
171         LongForm  schema.GroupResource
172 }