k8s.io/client-go@v0.22.2/dynamic/simple.go (about) 1 /* 2 Copyright 2018 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 dynamic 18 19 import ( 20 "context" 21 "fmt" 22 23 "k8s.io/apimachinery/pkg/api/meta" 24 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 25 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 26 "k8s.io/apimachinery/pkg/runtime" 27 "k8s.io/apimachinery/pkg/runtime/schema" 28 "k8s.io/apimachinery/pkg/types" 29 "k8s.io/apimachinery/pkg/watch" 30 "k8s.io/client-go/rest" 31 ) 32 33 type dynamicClient struct { 34 client *rest.RESTClient 35 } 36 37 var _ Interface = &dynamicClient{} 38 39 // ConfigFor returns a copy of the provided config with the 40 // appropriate dynamic client defaults set. 41 func ConfigFor(inConfig *rest.Config) *rest.Config { 42 config := rest.CopyConfig(inConfig) 43 config.AcceptContentTypes = "application/json" 44 config.ContentType = "application/json" 45 config.NegotiatedSerializer = basicNegotiatedSerializer{} // this gets used for discovery and error handling types 46 if config.UserAgent == "" { 47 config.UserAgent = rest.DefaultKubernetesUserAgent() 48 } 49 return config 50 } 51 52 // NewForConfigOrDie creates a new Interface for the given config and 53 // panics if there is an error in the config. 54 func NewForConfigOrDie(c *rest.Config) Interface { 55 ret, err := NewForConfig(c) 56 if err != nil { 57 panic(err) 58 } 59 return ret 60 } 61 62 // NewForConfig creates a new dynamic client or returns an error. 63 func NewForConfig(inConfig *rest.Config) (Interface, error) { 64 config := ConfigFor(inConfig) 65 // for serializing the options 66 config.GroupVersion = &schema.GroupVersion{} 67 config.APIPath = "/if-you-see-this-search-for-the-break" 68 69 restClient, err := rest.RESTClientFor(config) 70 if err != nil { 71 return nil, err 72 } 73 74 return &dynamicClient{client: restClient}, nil 75 } 76 77 type dynamicResourceClient struct { 78 client *dynamicClient 79 namespace string 80 resource schema.GroupVersionResource 81 } 82 83 func (c *dynamicClient) Resource(resource schema.GroupVersionResource) NamespaceableResourceInterface { 84 return &dynamicResourceClient{client: c, resource: resource} 85 } 86 87 func (c *dynamicResourceClient) Namespace(ns string) ResourceInterface { 88 ret := *c 89 ret.namespace = ns 90 return &ret 91 } 92 93 func (c *dynamicResourceClient) Create(ctx context.Context, obj *unstructured.Unstructured, opts metav1.CreateOptions, subresources ...string) (*unstructured.Unstructured, error) { 94 outBytes, err := runtime.Encode(unstructured.UnstructuredJSONScheme, obj) 95 if err != nil { 96 return nil, err 97 } 98 name := "" 99 if len(subresources) > 0 { 100 accessor, err := meta.Accessor(obj) 101 if err != nil { 102 return nil, err 103 } 104 name = accessor.GetName() 105 if len(name) == 0 { 106 return nil, fmt.Errorf("name is required") 107 } 108 } 109 110 result := c.client.client. 111 Post(). 112 AbsPath(append(c.makeURLSegments(name), subresources...)...). 113 Body(outBytes). 114 SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1). 115 Do(ctx) 116 if err := result.Error(); err != nil { 117 return nil, err 118 } 119 120 retBytes, err := result.Raw() 121 if err != nil { 122 return nil, err 123 } 124 uncastObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, retBytes) 125 if err != nil { 126 return nil, err 127 } 128 return uncastObj.(*unstructured.Unstructured), nil 129 } 130 131 func (c *dynamicResourceClient) Update(ctx context.Context, obj *unstructured.Unstructured, opts metav1.UpdateOptions, subresources ...string) (*unstructured.Unstructured, error) { 132 accessor, err := meta.Accessor(obj) 133 if err != nil { 134 return nil, err 135 } 136 name := accessor.GetName() 137 if len(name) == 0 { 138 return nil, fmt.Errorf("name is required") 139 } 140 outBytes, err := runtime.Encode(unstructured.UnstructuredJSONScheme, obj) 141 if err != nil { 142 return nil, err 143 } 144 145 result := c.client.client. 146 Put(). 147 AbsPath(append(c.makeURLSegments(name), subresources...)...). 148 Body(outBytes). 149 SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1). 150 Do(ctx) 151 if err := result.Error(); err != nil { 152 return nil, err 153 } 154 155 retBytes, err := result.Raw() 156 if err != nil { 157 return nil, err 158 } 159 uncastObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, retBytes) 160 if err != nil { 161 return nil, err 162 } 163 return uncastObj.(*unstructured.Unstructured), nil 164 } 165 166 func (c *dynamicResourceClient) UpdateStatus(ctx context.Context, obj *unstructured.Unstructured, opts metav1.UpdateOptions) (*unstructured.Unstructured, error) { 167 accessor, err := meta.Accessor(obj) 168 if err != nil { 169 return nil, err 170 } 171 name := accessor.GetName() 172 if len(name) == 0 { 173 return nil, fmt.Errorf("name is required") 174 } 175 176 outBytes, err := runtime.Encode(unstructured.UnstructuredJSONScheme, obj) 177 if err != nil { 178 return nil, err 179 } 180 181 result := c.client.client. 182 Put(). 183 AbsPath(append(c.makeURLSegments(name), "status")...). 184 Body(outBytes). 185 SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1). 186 Do(ctx) 187 if err := result.Error(); err != nil { 188 return nil, err 189 } 190 191 retBytes, err := result.Raw() 192 if err != nil { 193 return nil, err 194 } 195 uncastObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, retBytes) 196 if err != nil { 197 return nil, err 198 } 199 return uncastObj.(*unstructured.Unstructured), nil 200 } 201 202 func (c *dynamicResourceClient) Delete(ctx context.Context, name string, opts metav1.DeleteOptions, subresources ...string) error { 203 if len(name) == 0 { 204 return fmt.Errorf("name is required") 205 } 206 deleteOptionsByte, err := runtime.Encode(deleteOptionsCodec.LegacyCodec(schema.GroupVersion{Version: "v1"}), &opts) 207 if err != nil { 208 return err 209 } 210 211 result := c.client.client. 212 Delete(). 213 AbsPath(append(c.makeURLSegments(name), subresources...)...). 214 Body(deleteOptionsByte). 215 Do(ctx) 216 return result.Error() 217 } 218 219 func (c *dynamicResourceClient) DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOptions metav1.ListOptions) error { 220 deleteOptionsByte, err := runtime.Encode(deleteOptionsCodec.LegacyCodec(schema.GroupVersion{Version: "v1"}), &opts) 221 if err != nil { 222 return err 223 } 224 225 result := c.client.client. 226 Delete(). 227 AbsPath(c.makeURLSegments("")...). 228 Body(deleteOptionsByte). 229 SpecificallyVersionedParams(&listOptions, dynamicParameterCodec, versionV1). 230 Do(ctx) 231 return result.Error() 232 } 233 234 func (c *dynamicResourceClient) Get(ctx context.Context, name string, opts metav1.GetOptions, subresources ...string) (*unstructured.Unstructured, error) { 235 if len(name) == 0 { 236 return nil, fmt.Errorf("name is required") 237 } 238 result := c.client.client.Get().AbsPath(append(c.makeURLSegments(name), subresources...)...).SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1).Do(ctx) 239 if err := result.Error(); err != nil { 240 return nil, err 241 } 242 retBytes, err := result.Raw() 243 if err != nil { 244 return nil, err 245 } 246 uncastObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, retBytes) 247 if err != nil { 248 return nil, err 249 } 250 return uncastObj.(*unstructured.Unstructured), nil 251 } 252 253 func (c *dynamicResourceClient) List(ctx context.Context, opts metav1.ListOptions) (*unstructured.UnstructuredList, error) { 254 result := c.client.client.Get().AbsPath(c.makeURLSegments("")...).SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1).Do(ctx) 255 if err := result.Error(); err != nil { 256 return nil, err 257 } 258 retBytes, err := result.Raw() 259 if err != nil { 260 return nil, err 261 } 262 uncastObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, retBytes) 263 if err != nil { 264 return nil, err 265 } 266 if list, ok := uncastObj.(*unstructured.UnstructuredList); ok { 267 return list, nil 268 } 269 270 list, err := uncastObj.(*unstructured.Unstructured).ToList() 271 if err != nil { 272 return nil, err 273 } 274 return list, nil 275 } 276 277 func (c *dynamicResourceClient) Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { 278 opts.Watch = true 279 return c.client.client.Get().AbsPath(c.makeURLSegments("")...). 280 SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1). 281 Watch(ctx) 282 } 283 284 func (c *dynamicResourceClient) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (*unstructured.Unstructured, error) { 285 if len(name) == 0 { 286 return nil, fmt.Errorf("name is required") 287 } 288 result := c.client.client. 289 Patch(pt). 290 AbsPath(append(c.makeURLSegments(name), subresources...)...). 291 Body(data). 292 SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1). 293 Do(ctx) 294 if err := result.Error(); err != nil { 295 return nil, err 296 } 297 retBytes, err := result.Raw() 298 if err != nil { 299 return nil, err 300 } 301 uncastObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, retBytes) 302 if err != nil { 303 return nil, err 304 } 305 return uncastObj.(*unstructured.Unstructured), nil 306 } 307 308 func (c *dynamicResourceClient) makeURLSegments(name string) []string { 309 url := []string{} 310 if len(c.resource.Group) == 0 { 311 url = append(url, "api") 312 } else { 313 url = append(url, "apis", c.resource.Group) 314 } 315 url = append(url, c.resource.Version) 316 317 if len(c.namespace) > 0 { 318 url = append(url, "namespaces", c.namespace) 319 } 320 url = append(url, c.resource.Resource) 321 322 if len(name) > 0 { 323 url = append(url, name) 324 } 325 326 return url 327 }