...

Source file src/sigs.k8s.io/controller-runtime/pkg/client/metadata_client.go

Documentation: sigs.k8s.io/controller-runtime/pkg/client

     1  /*
     2  Copyright 2020 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 client
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"strings"
    23  
    24  	"k8s.io/apimachinery/pkg/api/meta"
    25  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    26  	"k8s.io/apimachinery/pkg/runtime/schema"
    27  	"k8s.io/client-go/metadata"
    28  )
    29  
    30  // TODO(directxman12): we could rewrite this on top of the low-level REST
    31  // client to avoid the extra shallow copy at the end, but I'm not sure it's
    32  // worth it -- the metadata client deals with falling back to loading the whole
    33  // object on older API servers, etc, and we'd have to reproduce that.
    34  
    35  // metadataClient is a client that reads & writes metadata-only requests to/from the API server.
    36  type metadataClient struct {
    37  	client     metadata.Interface
    38  	restMapper meta.RESTMapper
    39  }
    40  
    41  func (mc *metadataClient) getResourceInterface(gvk schema.GroupVersionKind, ns string) (metadata.ResourceInterface, error) {
    42  	mapping, err := mc.restMapper.RESTMapping(gvk.GroupKind(), gvk.Version)
    43  	if err != nil {
    44  		return nil, err
    45  	}
    46  	if mapping.Scope.Name() == meta.RESTScopeNameRoot {
    47  		return mc.client.Resource(mapping.Resource), nil
    48  	}
    49  	return mc.client.Resource(mapping.Resource).Namespace(ns), nil
    50  }
    51  
    52  // Delete implements client.Client.
    53  func (mc *metadataClient) Delete(ctx context.Context, obj Object, opts ...DeleteOption) error {
    54  	metadata, ok := obj.(*metav1.PartialObjectMetadata)
    55  	if !ok {
    56  		return fmt.Errorf("metadata client did not understand object: %T", obj)
    57  	}
    58  
    59  	resInt, err := mc.getResourceInterface(metadata.GroupVersionKind(), metadata.Namespace)
    60  	if err != nil {
    61  		return err
    62  	}
    63  
    64  	deleteOpts := DeleteOptions{}
    65  	deleteOpts.ApplyOptions(opts)
    66  
    67  	return resInt.Delete(ctx, metadata.Name, *deleteOpts.AsDeleteOptions())
    68  }
    69  
    70  // DeleteAllOf implements client.Client.
    71  func (mc *metadataClient) DeleteAllOf(ctx context.Context, obj Object, opts ...DeleteAllOfOption) error {
    72  	metadata, ok := obj.(*metav1.PartialObjectMetadata)
    73  	if !ok {
    74  		return fmt.Errorf("metadata client did not understand object: %T", obj)
    75  	}
    76  
    77  	deleteAllOfOpts := DeleteAllOfOptions{}
    78  	deleteAllOfOpts.ApplyOptions(opts)
    79  
    80  	resInt, err := mc.getResourceInterface(metadata.GroupVersionKind(), deleteAllOfOpts.ListOptions.Namespace)
    81  	if err != nil {
    82  		return err
    83  	}
    84  
    85  	return resInt.DeleteCollection(ctx, *deleteAllOfOpts.AsDeleteOptions(), *deleteAllOfOpts.AsListOptions())
    86  }
    87  
    88  // Patch implements client.Client.
    89  func (mc *metadataClient) Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error {
    90  	metadata, ok := obj.(*metav1.PartialObjectMetadata)
    91  	if !ok {
    92  		return fmt.Errorf("metadata client did not understand object: %T", obj)
    93  	}
    94  
    95  	gvk := metadata.GroupVersionKind()
    96  	resInt, err := mc.getResourceInterface(gvk, metadata.Namespace)
    97  	if err != nil {
    98  		return err
    99  	}
   100  
   101  	data, err := patch.Data(obj)
   102  	if err != nil {
   103  		return err
   104  	}
   105  
   106  	patchOpts := &PatchOptions{}
   107  	patchOpts.ApplyOptions(opts)
   108  
   109  	res, err := resInt.Patch(ctx, metadata.Name, patch.Type(), data, *patchOpts.AsPatchOptions())
   110  	if err != nil {
   111  		return err
   112  	}
   113  	*metadata = *res
   114  	metadata.SetGroupVersionKind(gvk) // restore the GVK, which isn't set on metadata
   115  	return nil
   116  }
   117  
   118  // Get implements client.Client.
   119  func (mc *metadataClient) Get(ctx context.Context, key ObjectKey, obj Object, opts ...GetOption) error {
   120  	metadata, ok := obj.(*metav1.PartialObjectMetadata)
   121  	if !ok {
   122  		return fmt.Errorf("metadata client did not understand object: %T", obj)
   123  	}
   124  
   125  	gvk := metadata.GroupVersionKind()
   126  
   127  	getOpts := GetOptions{}
   128  	getOpts.ApplyOptions(opts)
   129  
   130  	resInt, err := mc.getResourceInterface(gvk, key.Namespace)
   131  	if err != nil {
   132  		return err
   133  	}
   134  
   135  	res, err := resInt.Get(ctx, key.Name, *getOpts.AsGetOptions())
   136  	if err != nil {
   137  		return err
   138  	}
   139  	*metadata = *res
   140  	metadata.SetGroupVersionKind(gvk) // restore the GVK, which isn't set on metadata
   141  	return nil
   142  }
   143  
   144  // List implements client.Client.
   145  func (mc *metadataClient) List(ctx context.Context, obj ObjectList, opts ...ListOption) error {
   146  	metadata, ok := obj.(*metav1.PartialObjectMetadataList)
   147  	if !ok {
   148  		return fmt.Errorf("metadata client did not understand object: %T", obj)
   149  	}
   150  
   151  	gvk := metadata.GroupVersionKind()
   152  	gvk.Kind = strings.TrimSuffix(gvk.Kind, "List")
   153  
   154  	listOpts := ListOptions{}
   155  	listOpts.ApplyOptions(opts)
   156  
   157  	resInt, err := mc.getResourceInterface(gvk, listOpts.Namespace)
   158  	if err != nil {
   159  		return err
   160  	}
   161  
   162  	res, err := resInt.List(ctx, *listOpts.AsListOptions())
   163  	if err != nil {
   164  		return err
   165  	}
   166  	*metadata = *res
   167  	metadata.SetGroupVersionKind(gvk) // restore the GVK, which isn't set on metadata
   168  	return nil
   169  }
   170  
   171  func (mc *metadataClient) PatchSubResource(ctx context.Context, obj Object, subResource string, patch Patch, opts ...SubResourcePatchOption) error {
   172  	metadata, ok := obj.(*metav1.PartialObjectMetadata)
   173  	if !ok {
   174  		return fmt.Errorf("metadata client did not understand object: %T", obj)
   175  	}
   176  
   177  	gvk := metadata.GroupVersionKind()
   178  	resInt, err := mc.getResourceInterface(gvk, metadata.Namespace)
   179  	if err != nil {
   180  		return err
   181  	}
   182  
   183  	patchOpts := &SubResourcePatchOptions{}
   184  	patchOpts.ApplyOptions(opts)
   185  
   186  	body := obj
   187  	if patchOpts.SubResourceBody != nil {
   188  		body = patchOpts.SubResourceBody
   189  	}
   190  
   191  	data, err := patch.Data(body)
   192  	if err != nil {
   193  		return err
   194  	}
   195  
   196  	res, err := resInt.Patch(ctx, metadata.Name, patch.Type(), data, *patchOpts.AsPatchOptions(), subResource)
   197  	if err != nil {
   198  		return err
   199  	}
   200  
   201  	*metadata = *res
   202  	metadata.SetGroupVersionKind(gvk) // restore the GVK, which isn't set on metadata
   203  	return nil
   204  }
   205  

View as plain text