...
1
16
17 package client
18
19 import (
20 "net/http"
21 "strings"
22 "sync"
23
24 "k8s.io/apimachinery/pkg/api/meta"
25 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
26 "k8s.io/apimachinery/pkg/runtime"
27 "k8s.io/apimachinery/pkg/runtime/schema"
28 "k8s.io/apimachinery/pkg/runtime/serializer"
29 "k8s.io/client-go/rest"
30 "sigs.k8s.io/controller-runtime/pkg/client/apiutil"
31 )
32
33
34 type clientRestResources struct {
35
36 httpClient *http.Client
37
38
39 config *rest.Config
40
41
42 scheme *runtime.Scheme
43
44
45 mapper meta.RESTMapper
46
47
48 codecs serializer.CodecFactory
49
50
51 structuredResourceByType map[schema.GroupVersionKind]*resourceMeta
52
53 unstructuredResourceByType map[schema.GroupVersionKind]*resourceMeta
54 mu sync.RWMutex
55 }
56
57
58
59 func (c *clientRestResources) newResource(gvk schema.GroupVersionKind, isList, isUnstructured bool) (*resourceMeta, error) {
60 if strings.HasSuffix(gvk.Kind, "List") && isList {
61
62 gvk.Kind = gvk.Kind[:len(gvk.Kind)-4]
63 }
64
65 client, err := apiutil.RESTClientForGVK(gvk, isUnstructured, c.config, c.codecs, c.httpClient)
66 if err != nil {
67 return nil, err
68 }
69 mapping, err := c.mapper.RESTMapping(gvk.GroupKind(), gvk.Version)
70 if err != nil {
71 return nil, err
72 }
73 return &resourceMeta{Interface: client, mapping: mapping, gvk: gvk}, nil
74 }
75
76
77
78 func (c *clientRestResources) getResource(obj runtime.Object) (*resourceMeta, error) {
79 gvk, err := apiutil.GVKForObject(obj, c.scheme)
80 if err != nil {
81 return nil, err
82 }
83
84 _, isUnstructured := obj.(runtime.Unstructured)
85
86
87
88 c.mu.RLock()
89 resourceByType := c.structuredResourceByType
90 if isUnstructured {
91 resourceByType = c.unstructuredResourceByType
92 }
93 r, known := resourceByType[gvk]
94 c.mu.RUnlock()
95
96 if known {
97 return r, nil
98 }
99
100
101 c.mu.Lock()
102 defer c.mu.Unlock()
103 r, err = c.newResource(gvk, meta.IsListType(obj), isUnstructured)
104 if err != nil {
105 return nil, err
106 }
107 resourceByType[gvk] = r
108 return r, err
109 }
110
111
112 func (c *clientRestResources) getObjMeta(obj runtime.Object) (*objMeta, error) {
113 r, err := c.getResource(obj)
114 if err != nil {
115 return nil, err
116 }
117 m, err := meta.Accessor(obj)
118 if err != nil {
119 return nil, err
120 }
121 return &objMeta{resourceMeta: r, Object: m}, err
122 }
123
124
125 type resourceMeta struct {
126
127 rest.Interface
128
129 gvk schema.GroupVersionKind
130
131 mapping *meta.RESTMapping
132 }
133
134
135 func (r *resourceMeta) isNamespaced() bool {
136 return r.mapping.Scope.Name() != meta.RESTScopeNameRoot
137 }
138
139
140 func (r *resourceMeta) resource() string {
141 return r.mapping.Resource.Resource
142 }
143
144
145 type objMeta struct {
146
147 *resourceMeta
148
149
150 metav1.Object
151 }
152
View as plain text