123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287 |
- /*
- Copyright 2018 The Kubernetes Authors.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
- package dynamic
- import (
- "io"
- "k8s.io/apimachinery/pkg/api/meta"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
- "k8s.io/apimachinery/pkg/runtime"
- "k8s.io/apimachinery/pkg/runtime/schema"
- "k8s.io/apimachinery/pkg/runtime/serializer/streaming"
- "k8s.io/apimachinery/pkg/types"
- "k8s.io/apimachinery/pkg/watch"
- "k8s.io/client-go/rest"
- )
- type dynamicClient struct {
- client *rest.RESTClient
- }
- var _ Interface = &dynamicClient{}
- func NewForConfig(inConfig *rest.Config) (Interface, error) {
- config := rest.CopyConfig(inConfig)
- // for serializing the options
- config.GroupVersion = &schema.GroupVersion{}
- config.APIPath = "/if-you-see-this-search-for-the-break"
- config.AcceptContentTypes = "application/json"
- config.ContentType = "application/json"
- config.NegotiatedSerializer = basicNegotiatedSerializer{} // this gets used for discovery and error handling types
- if config.UserAgent == "" {
- config.UserAgent = rest.DefaultKubernetesUserAgent()
- }
- restClient, err := rest.RESTClientFor(config)
- if err != nil {
- return nil, err
- }
- return &dynamicClient{client: restClient}, nil
- }
- type dynamicResourceClient struct {
- client *dynamicClient
- namespace string
- resource schema.GroupVersionResource
- }
- func (c *dynamicClient) Resource(resource schema.GroupVersionResource) NamespaceableResourceInterface {
- return &dynamicResourceClient{client: c, resource: resource}
- }
- func (c *dynamicResourceClient) Namespace(ns string) ResourceInterface {
- ret := *c
- ret.namespace = ns
- return &ret
- }
- func (c *dynamicResourceClient) Create(obj *unstructured.Unstructured, subresources ...string) (*unstructured.Unstructured, error) {
- outBytes, err := runtime.Encode(unstructured.UnstructuredJSONScheme, obj)
- if err != nil {
- return nil, err
- }
- name := ""
- if len(subresources) > 0 {
- accessor, err := meta.Accessor(obj)
- if err != nil {
- return nil, err
- }
- name = accessor.GetName()
- }
- result := c.client.client.Post().AbsPath(append(c.makeURLSegments(name), subresources...)...).Body(outBytes).Do()
- if err := result.Error(); err != nil {
- return nil, err
- }
- retBytes, err := result.Raw()
- if err != nil {
- return nil, err
- }
- uncastObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, retBytes)
- if err != nil {
- return nil, err
- }
- return uncastObj.(*unstructured.Unstructured), nil
- }
- func (c *dynamicResourceClient) Update(obj *unstructured.Unstructured, subresources ...string) (*unstructured.Unstructured, error) {
- accessor, err := meta.Accessor(obj)
- if err != nil {
- return nil, err
- }
- outBytes, err := runtime.Encode(unstructured.UnstructuredJSONScheme, obj)
- if err != nil {
- return nil, err
- }
- result := c.client.client.Put().AbsPath(append(c.makeURLSegments(accessor.GetName()), subresources...)...).Body(outBytes).Do()
- if err := result.Error(); err != nil {
- return nil, err
- }
- retBytes, err := result.Raw()
- if err != nil {
- return nil, err
- }
- uncastObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, retBytes)
- if err != nil {
- return nil, err
- }
- return uncastObj.(*unstructured.Unstructured), nil
- }
- func (c *dynamicResourceClient) UpdateStatus(obj *unstructured.Unstructured) (*unstructured.Unstructured, error) {
- accessor, err := meta.Accessor(obj)
- if err != nil {
- return nil, err
- }
- outBytes, err := runtime.Encode(unstructured.UnstructuredJSONScheme, obj)
- if err != nil {
- return nil, err
- }
- result := c.client.client.Put().AbsPath(append(c.makeURLSegments(accessor.GetName()), "status")...).Body(outBytes).Do()
- if err := result.Error(); err != nil {
- return nil, err
- }
- retBytes, err := result.Raw()
- if err != nil {
- return nil, err
- }
- uncastObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, retBytes)
- if err != nil {
- return nil, err
- }
- return uncastObj.(*unstructured.Unstructured), nil
- }
- func (c *dynamicResourceClient) Delete(name string, opts *metav1.DeleteOptions, subresources ...string) error {
- if opts == nil {
- opts = &metav1.DeleteOptions{}
- }
- deleteOptionsByte, err := runtime.Encode(deleteOptionsCodec.LegacyCodec(schema.GroupVersion{Version: "v1"}), opts)
- if err != nil {
- return err
- }
- result := c.client.client.Delete().AbsPath(append(c.makeURLSegments(name), subresources...)...).Body(deleteOptionsByte).Do()
- return result.Error()
- }
- func (c *dynamicResourceClient) DeleteCollection(opts *metav1.DeleteOptions, listOptions metav1.ListOptions) error {
- if opts == nil {
- opts = &metav1.DeleteOptions{}
- }
- deleteOptionsByte, err := runtime.Encode(deleteOptionsCodec.LegacyCodec(schema.GroupVersion{Version: "v1"}), opts)
- if err != nil {
- return err
- }
- result := c.client.client.Delete().AbsPath(c.makeURLSegments("")...).Body(deleteOptionsByte).SpecificallyVersionedParams(&listOptions, dynamicParameterCodec, versionV1).Do()
- return result.Error()
- }
- func (c *dynamicResourceClient) Get(name string, opts metav1.GetOptions, subresources ...string) (*unstructured.Unstructured, error) {
- result := c.client.client.Get().AbsPath(append(c.makeURLSegments(name), subresources...)...).SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1).Do()
- if err := result.Error(); err != nil {
- return nil, err
- }
- retBytes, err := result.Raw()
- if err != nil {
- return nil, err
- }
- uncastObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, retBytes)
- if err != nil {
- return nil, err
- }
- return uncastObj.(*unstructured.Unstructured), nil
- }
- func (c *dynamicResourceClient) List(opts metav1.ListOptions) (*unstructured.UnstructuredList, error) {
- result := c.client.client.Get().AbsPath(c.makeURLSegments("")...).SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1).Do()
- if err := result.Error(); err != nil {
- return nil, err
- }
- retBytes, err := result.Raw()
- if err != nil {
- return nil, err
- }
- uncastObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, retBytes)
- if err != nil {
- return nil, err
- }
- if list, ok := uncastObj.(*unstructured.UnstructuredList); ok {
- return list, nil
- }
- list, err := uncastObj.(*unstructured.Unstructured).ToList()
- if err != nil {
- return nil, err
- }
- return list, nil
- }
- func (c *dynamicResourceClient) Watch(opts metav1.ListOptions) (watch.Interface, error) {
- internalGV := schema.GroupVersions{
- {Group: c.resource.Group, Version: runtime.APIVersionInternal},
- // always include the legacy group as a decoding target to handle non-error `Status` return types
- {Group: "", Version: runtime.APIVersionInternal},
- }
- s := &rest.Serializers{
- Encoder: watchNegotiatedSerializerInstance.EncoderForVersion(watchJsonSerializerInfo.Serializer, c.resource.GroupVersion()),
- Decoder: watchNegotiatedSerializerInstance.DecoderToVersion(watchJsonSerializerInfo.Serializer, internalGV),
- RenegotiatedDecoder: func(contentType string, params map[string]string) (runtime.Decoder, error) {
- return watchNegotiatedSerializerInstance.DecoderToVersion(watchJsonSerializerInfo.Serializer, internalGV), nil
- },
- StreamingSerializer: watchJsonSerializerInfo.StreamSerializer.Serializer,
- Framer: watchJsonSerializerInfo.StreamSerializer.Framer,
- }
- wrappedDecoderFn := func(body io.ReadCloser) streaming.Decoder {
- framer := s.Framer.NewFrameReader(body)
- return streaming.NewDecoder(framer, s.StreamingSerializer)
- }
- opts.Watch = true
- return c.client.client.Get().AbsPath(c.makeURLSegments("")...).
- SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1).
- WatchWithSpecificDecoders(wrappedDecoderFn, unstructured.UnstructuredJSONScheme)
- }
- func (c *dynamicResourceClient) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (*unstructured.Unstructured, error) {
- result := c.client.client.Patch(pt).AbsPath(append(c.makeURLSegments(name), subresources...)...).Body(data).Do()
- if err := result.Error(); err != nil {
- return nil, err
- }
- retBytes, err := result.Raw()
- if err != nil {
- return nil, err
- }
- uncastObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, retBytes)
- if err != nil {
- return nil, err
- }
- return uncastObj.(*unstructured.Unstructured), nil
- }
- func (c *dynamicResourceClient) makeURLSegments(name string) []string {
- url := []string{}
- if len(c.resource.Group) == 0 {
- url = append(url, "api")
- } else {
- url = append(url, "apis", c.resource.Group)
- }
- url = append(url, c.resource.Version)
- if len(c.namespace) > 0 {
- url = append(url, "namespaces", c.namespace)
- }
- url = append(url, c.resource.Resource)
- if len(name) > 0 {
- url = append(url, name)
- }
- return url
- }
|