...
1
16
17
18
19 package util
20
21 import (
22 "errors"
23 "sync"
24
25 corev1 "k8s.io/api/core/v1"
26 "k8s.io/apimachinery/pkg/api/meta"
27 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
28 "k8s.io/cli-runtime/pkg/genericclioptions"
29 "k8s.io/cli-runtime/pkg/resource"
30 "k8s.io/client-go/discovery"
31 "k8s.io/client-go/dynamic"
32 "k8s.io/client-go/kubernetes"
33 openapiclient "k8s.io/client-go/openapi"
34 "k8s.io/client-go/openapi/cached"
35 restclient "k8s.io/client-go/rest"
36 "k8s.io/client-go/tools/clientcmd"
37 "k8s.io/kubectl/pkg/util/openapi"
38 "k8s.io/kubectl/pkg/validation"
39 )
40
41 type factoryImpl struct {
42 clientGetter genericclioptions.RESTClientGetter
43
44
45 openAPIParser *openapi.CachedOpenAPIParser
46 oapi *openapi.CachedOpenAPIGetter
47 parser sync.Once
48 getter sync.Once
49 }
50
51 func NewFactory(clientGetter genericclioptions.RESTClientGetter) Factory {
52 if clientGetter == nil {
53 panic("attempt to instantiate client_access_factory with nil clientGetter")
54 }
55 f := &factoryImpl{
56 clientGetter: clientGetter,
57 }
58
59 return f
60 }
61
62 func (f *factoryImpl) ToRESTConfig() (*restclient.Config, error) {
63 return f.clientGetter.ToRESTConfig()
64 }
65
66 func (f *factoryImpl) ToRESTMapper() (meta.RESTMapper, error) {
67 return f.clientGetter.ToRESTMapper()
68 }
69
70 func (f *factoryImpl) ToDiscoveryClient() (discovery.CachedDiscoveryInterface, error) {
71 return f.clientGetter.ToDiscoveryClient()
72 }
73
74 func (f *factoryImpl) ToRawKubeConfigLoader() clientcmd.ClientConfig {
75 return f.clientGetter.ToRawKubeConfigLoader()
76 }
77
78 func (f *factoryImpl) KubernetesClientSet() (*kubernetes.Clientset, error) {
79 clientConfig, err := f.ToRESTConfig()
80 if err != nil {
81 return nil, err
82 }
83 return kubernetes.NewForConfig(clientConfig)
84 }
85
86 func (f *factoryImpl) DynamicClient() (dynamic.Interface, error) {
87 clientConfig, err := f.ToRESTConfig()
88 if err != nil {
89 return nil, err
90 }
91 return dynamic.NewForConfig(clientConfig)
92 }
93
94
95 func (f *factoryImpl) NewBuilder() *resource.Builder {
96 return resource.NewBuilder(f.clientGetter)
97 }
98
99 func (f *factoryImpl) RESTClient() (*restclient.RESTClient, error) {
100 clientConfig, err := f.ToRESTConfig()
101 if err != nil {
102 return nil, err
103 }
104 setKubernetesDefaults(clientConfig)
105 return restclient.RESTClientFor(clientConfig)
106 }
107
108 func (f *factoryImpl) ClientForMapping(mapping *meta.RESTMapping) (resource.RESTClient, error) {
109 cfg, err := f.clientGetter.ToRESTConfig()
110 if err != nil {
111 return nil, err
112 }
113 if err := setKubernetesDefaults(cfg); err != nil {
114 return nil, err
115 }
116 gvk := mapping.GroupVersionKind
117 switch gvk.Group {
118 case corev1.GroupName:
119 cfg.APIPath = "/api"
120 default:
121 cfg.APIPath = "/apis"
122 }
123 gv := gvk.GroupVersion()
124 cfg.GroupVersion = &gv
125 return restclient.RESTClientFor(cfg)
126 }
127
128 func (f *factoryImpl) UnstructuredClientForMapping(mapping *meta.RESTMapping) (resource.RESTClient, error) {
129 cfg, err := f.clientGetter.ToRESTConfig()
130 if err != nil {
131 return nil, err
132 }
133 if err := restclient.SetKubernetesDefaults(cfg); err != nil {
134 return nil, err
135 }
136 cfg.APIPath = "/apis"
137 if mapping.GroupVersionKind.Group == corev1.GroupName {
138 cfg.APIPath = "/api"
139 }
140 gv := mapping.GroupVersionKind.GroupVersion()
141 cfg.ContentConfig = resource.UnstructuredPlusDefaultContentConfig()
142 cfg.GroupVersion = &gv
143 return restclient.RESTClientFor(cfg)
144 }
145
146 func (f *factoryImpl) Validator(validationDirective string) (validation.Schema, error) {
147
148
149
150
151
152
153 if validationDirective == metav1.FieldValidationIgnore {
154 return validation.NullSchema{}, nil
155 }
156
157 schema := validation.ConjunctiveSchema{
158 validation.NewSchemaValidation(f),
159 validation.NoDoubleKeySchema{},
160 }
161
162 dynamicClient, err := f.DynamicClient()
163 if err != nil {
164 return nil, err
165 }
166
167 discoveryClient, err := f.ToDiscoveryClient()
168 if err != nil {
169 return nil, err
170 }
171
172
173 oapiV3Client := cached.NewClient(discoveryClient.OpenAPIV3())
174 queryParam := resource.QueryParamFieldValidation
175 primary := resource.NewQueryParamVerifierV3(dynamicClient, oapiV3Client, queryParam)
176 secondary := resource.NewQueryParamVerifier(dynamicClient, f.openAPIGetter(), queryParam)
177 fallback := resource.NewFallbackQueryParamVerifier(primary, secondary)
178 return validation.NewParamVerifyingSchema(schema, fallback, string(validationDirective)), nil
179 }
180
181
182
183 func (f *factoryImpl) OpenAPISchema() (openapi.Resources, error) {
184 openAPIGetter := f.openAPIGetter()
185 if openAPIGetter == nil {
186 return nil, errors.New("no openapi getter")
187 }
188
189
190 f.parser.Do(func() {
191
192 f.openAPIParser = openapi.NewOpenAPIParser(f.openAPIGetter())
193 })
194
195
196 return f.openAPIParser.Parse()
197 }
198
199 func (f *factoryImpl) openAPIGetter() discovery.OpenAPISchemaInterface {
200 discovery, err := f.clientGetter.ToDiscoveryClient()
201 if err != nil {
202 return nil
203 }
204 f.getter.Do(func() {
205 f.oapi = openapi.NewOpenAPIGetter(discovery)
206 })
207
208 return f.oapi
209 }
210
211 func (f *factoryImpl) OpenAPIV3Client() (openapiclient.Client, error) {
212 discovery, err := f.clientGetter.ToDiscoveryClient()
213 if err != nil {
214 return nil, err
215 }
216
217 return cached.NewClient(discovery.OpenAPIV3()), nil
218 }
219
View as plain text