github.xiaoq7.com/operator-framework/operator-sdk@v0.8.2/pkg/restmapper/dynamicrestmapper.go (about) 1 // Copyright 2019 The Operator-SDK Authors 2 // 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 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package restmapper 16 17 import ( 18 "k8s.io/apimachinery/pkg/api/meta" 19 "k8s.io/apimachinery/pkg/runtime/schema" 20 utilruntime "k8s.io/apimachinery/pkg/util/runtime" 21 "k8s.io/client-go/discovery" 22 "k8s.io/client-go/rest" 23 "k8s.io/client-go/restmapper" 24 ) 25 26 type DynamicRESTMapper struct { 27 client discovery.DiscoveryInterface 28 delegate meta.RESTMapper 29 } 30 31 // NewDynamicRESTMapper returns a RESTMapper that dynamically discovers resource 32 // types at runtime. This is in contrast to controller-manager's default RESTMapper, which 33 // only checks resource types at startup, and so can't handle the case of first creating a 34 // CRD and then creating an instance of that CRD. 35 func NewDynamicRESTMapper(cfg *rest.Config) (meta.RESTMapper, error) { 36 client, err := discovery.NewDiscoveryClientForConfig(cfg) 37 if err != nil { 38 return nil, err 39 } 40 41 drm := &DynamicRESTMapper{client: client} 42 if err := drm.reload(); err != nil { 43 return nil, err 44 } 45 return drm, nil 46 } 47 48 func (drm *DynamicRESTMapper) reload() error { 49 gr, err := restmapper.GetAPIGroupResources(drm.client) 50 if err != nil { 51 return err 52 } 53 drm.delegate = restmapper.NewDiscoveryRESTMapper(gr) 54 return nil 55 } 56 57 // reloadOnError checks if an error indicates that the delegated RESTMapper needs to be 58 // reloaded, and if so, reloads it and returns true. 59 func (drm *DynamicRESTMapper) reloadOnError(err error) bool { 60 if _, matches := err.(*meta.NoKindMatchError); !matches { 61 return false 62 } 63 err = drm.reload() 64 if err != nil { 65 utilruntime.HandleError(err) 66 } 67 return err == nil 68 } 69 70 func (drm *DynamicRESTMapper) KindFor(resource schema.GroupVersionResource) (schema.GroupVersionKind, error) { 71 gvk, err := drm.delegate.KindFor(resource) 72 if drm.reloadOnError(err) { 73 gvk, err = drm.delegate.KindFor(resource) 74 } 75 return gvk, err 76 } 77 78 func (drm *DynamicRESTMapper) KindsFor(resource schema.GroupVersionResource) ([]schema.GroupVersionKind, error) { 79 gvks, err := drm.delegate.KindsFor(resource) 80 if drm.reloadOnError(err) { 81 gvks, err = drm.delegate.KindsFor(resource) 82 } 83 return gvks, err 84 } 85 86 func (drm *DynamicRESTMapper) ResourceFor(input schema.GroupVersionResource) (schema.GroupVersionResource, error) { 87 gvr, err := drm.delegate.ResourceFor(input) 88 if drm.reloadOnError(err) { 89 gvr, err = drm.delegate.ResourceFor(input) 90 } 91 return gvr, err 92 } 93 94 func (drm *DynamicRESTMapper) ResourcesFor(input schema.GroupVersionResource) ([]schema.GroupVersionResource, error) { 95 gvrs, err := drm.delegate.ResourcesFor(input) 96 if drm.reloadOnError(err) { 97 gvrs, err = drm.delegate.ResourcesFor(input) 98 } 99 return gvrs, err 100 } 101 102 func (drm *DynamicRESTMapper) RESTMapping(gk schema.GroupKind, versions ...string) (*meta.RESTMapping, error) { 103 m, err := drm.delegate.RESTMapping(gk, versions...) 104 if drm.reloadOnError(err) { 105 m, err = drm.delegate.RESTMapping(gk, versions...) 106 } 107 return m, err 108 } 109 110 func (drm *DynamicRESTMapper) RESTMappings(gk schema.GroupKind, versions ...string) ([]*meta.RESTMapping, error) { 111 ms, err := drm.delegate.RESTMappings(gk, versions...) 112 if drm.reloadOnError(err) { 113 ms, err = drm.delegate.RESTMappings(gk, versions...) 114 } 115 return ms, err 116 } 117 118 func (drm *DynamicRESTMapper) ResourceSingularizer(resource string) (singular string, err error) { 119 s, err := drm.delegate.ResourceSingularizer(resource) 120 if drm.reloadOnError(err) { 121 s, err = drm.delegate.ResourceSingularizer(resource) 122 } 123 return s, err 124 }