...

Source file src/sigs.k8s.io/controller-runtime/pkg/client/namespaced_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  
    23  	"k8s.io/apimachinery/pkg/api/meta"
    24  	"k8s.io/apimachinery/pkg/runtime"
    25  	"k8s.io/apimachinery/pkg/runtime/schema"
    26  )
    27  
    28  // NewNamespacedClient wraps an existing client enforcing the namespace value.
    29  // All functions using this client will have the same namespace declared here.
    30  func NewNamespacedClient(c Client, ns string) Client {
    31  	return &namespacedClient{
    32  		client:    c,
    33  		namespace: ns,
    34  	}
    35  }
    36  
    37  var _ Client = &namespacedClient{}
    38  
    39  // namespacedClient is a Client that wraps another Client in order to enforce the specified namespace value.
    40  type namespacedClient struct {
    41  	namespace string
    42  	client    Client
    43  }
    44  
    45  // Scheme returns the scheme this client is using.
    46  func (n *namespacedClient) Scheme() *runtime.Scheme {
    47  	return n.client.Scheme()
    48  }
    49  
    50  // RESTMapper returns the scheme this client is using.
    51  func (n *namespacedClient) RESTMapper() meta.RESTMapper {
    52  	return n.client.RESTMapper()
    53  }
    54  
    55  // GroupVersionKindFor returns the GroupVersionKind for the given object.
    56  func (n *namespacedClient) GroupVersionKindFor(obj runtime.Object) (schema.GroupVersionKind, error) {
    57  	return n.client.GroupVersionKindFor(obj)
    58  }
    59  
    60  // IsObjectNamespaced returns true if the GroupVersionKind of the object is namespaced.
    61  func (n *namespacedClient) IsObjectNamespaced(obj runtime.Object) (bool, error) {
    62  	return n.client.IsObjectNamespaced(obj)
    63  }
    64  
    65  // Create implements client.Client.
    66  func (n *namespacedClient) Create(ctx context.Context, obj Object, opts ...CreateOption) error {
    67  	isNamespaceScoped, err := n.IsObjectNamespaced(obj)
    68  	if err != nil {
    69  		return fmt.Errorf("error finding the scope of the object: %w", err)
    70  	}
    71  
    72  	objectNamespace := obj.GetNamespace()
    73  	if objectNamespace != n.namespace && objectNamespace != "" {
    74  		return fmt.Errorf("namespace %s of the object %s does not match the namespace %s on the client", objectNamespace, obj.GetName(), n.namespace)
    75  	}
    76  
    77  	if isNamespaceScoped && objectNamespace == "" {
    78  		obj.SetNamespace(n.namespace)
    79  	}
    80  	return n.client.Create(ctx, obj, opts...)
    81  }
    82  
    83  // Update implements client.Client.
    84  func (n *namespacedClient) Update(ctx context.Context, obj Object, opts ...UpdateOption) error {
    85  	isNamespaceScoped, err := n.IsObjectNamespaced(obj)
    86  	if err != nil {
    87  		return fmt.Errorf("error finding the scope of the object: %w", err)
    88  	}
    89  
    90  	objectNamespace := obj.GetNamespace()
    91  	if objectNamespace != n.namespace && objectNamespace != "" {
    92  		return fmt.Errorf("namespace %s of the object %s does not match the namespace %s on the client", objectNamespace, obj.GetName(), n.namespace)
    93  	}
    94  
    95  	if isNamespaceScoped && objectNamespace == "" {
    96  		obj.SetNamespace(n.namespace)
    97  	}
    98  	return n.client.Update(ctx, obj, opts...)
    99  }
   100  
   101  // Delete implements client.Client.
   102  func (n *namespacedClient) Delete(ctx context.Context, obj Object, opts ...DeleteOption) error {
   103  	isNamespaceScoped, err := n.IsObjectNamespaced(obj)
   104  	if err != nil {
   105  		return fmt.Errorf("error finding the scope of the object: %w", err)
   106  	}
   107  
   108  	objectNamespace := obj.GetNamespace()
   109  	if objectNamespace != n.namespace && objectNamespace != "" {
   110  		return fmt.Errorf("namespace %s of the object %s does not match the namespace %s on the client", objectNamespace, obj.GetName(), n.namespace)
   111  	}
   112  
   113  	if isNamespaceScoped && objectNamespace == "" {
   114  		obj.SetNamespace(n.namespace)
   115  	}
   116  	return n.client.Delete(ctx, obj, opts...)
   117  }
   118  
   119  // DeleteAllOf implements client.Client.
   120  func (n *namespacedClient) DeleteAllOf(ctx context.Context, obj Object, opts ...DeleteAllOfOption) error {
   121  	isNamespaceScoped, err := n.IsObjectNamespaced(obj)
   122  	if err != nil {
   123  		return fmt.Errorf("error finding the scope of the object: %w", err)
   124  	}
   125  
   126  	if isNamespaceScoped {
   127  		opts = append(opts, InNamespace(n.namespace))
   128  	}
   129  	return n.client.DeleteAllOf(ctx, obj, opts...)
   130  }
   131  
   132  // Patch implements client.Client.
   133  func (n *namespacedClient) Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error {
   134  	isNamespaceScoped, err := n.IsObjectNamespaced(obj)
   135  	if err != nil {
   136  		return fmt.Errorf("error finding the scope of the object: %w", err)
   137  	}
   138  
   139  	objectNamespace := obj.GetNamespace()
   140  	if objectNamespace != n.namespace && objectNamespace != "" {
   141  		return fmt.Errorf("namespace %s of the object %s does not match the namespace %s on the client", objectNamespace, obj.GetName(), n.namespace)
   142  	}
   143  
   144  	if isNamespaceScoped && objectNamespace == "" {
   145  		obj.SetNamespace(n.namespace)
   146  	}
   147  	return n.client.Patch(ctx, obj, patch, opts...)
   148  }
   149  
   150  // Get implements client.Client.
   151  func (n *namespacedClient) Get(ctx context.Context, key ObjectKey, obj Object, opts ...GetOption) error {
   152  	isNamespaceScoped, err := n.IsObjectNamespaced(obj)
   153  	if err != nil {
   154  		return fmt.Errorf("error finding the scope of the object: %w", err)
   155  	}
   156  	if isNamespaceScoped {
   157  		if key.Namespace != "" && key.Namespace != n.namespace {
   158  			return fmt.Errorf("namespace %s provided for the object %s does not match the namespace %s on the client", key.Namespace, obj.GetName(), n.namespace)
   159  		}
   160  		key.Namespace = n.namespace
   161  	}
   162  	return n.client.Get(ctx, key, obj, opts...)
   163  }
   164  
   165  // List implements client.Client.
   166  func (n *namespacedClient) List(ctx context.Context, obj ObjectList, opts ...ListOption) error {
   167  	if n.namespace != "" {
   168  		opts = append(opts, InNamespace(n.namespace))
   169  	}
   170  	return n.client.List(ctx, obj, opts...)
   171  }
   172  
   173  // Status implements client.StatusClient.
   174  func (n *namespacedClient) Status() SubResourceWriter {
   175  	return n.SubResource("status")
   176  }
   177  
   178  // SubResource implements client.SubResourceClient.
   179  func (n *namespacedClient) SubResource(subResource string) SubResourceClient {
   180  	return &namespacedClientSubResourceClient{client: n.client.SubResource(subResource), namespace: n.namespace, namespacedclient: n}
   181  }
   182  
   183  // ensure namespacedClientSubResourceClient implements client.SubResourceClient.
   184  var _ SubResourceClient = &namespacedClientSubResourceClient{}
   185  
   186  type namespacedClientSubResourceClient struct {
   187  	client           SubResourceClient
   188  	namespace        string
   189  	namespacedclient Client
   190  }
   191  
   192  func (nsw *namespacedClientSubResourceClient) Get(ctx context.Context, obj, subResource Object, opts ...SubResourceGetOption) error {
   193  	isNamespaceScoped, err := nsw.namespacedclient.IsObjectNamespaced(obj)
   194  	if err != nil {
   195  		return fmt.Errorf("error finding the scope of the object: %w", err)
   196  	}
   197  
   198  	objectNamespace := obj.GetNamespace()
   199  	if objectNamespace != nsw.namespace && objectNamespace != "" {
   200  		return fmt.Errorf("namespace %s of the object %s does not match the namespace %s on the client", objectNamespace, obj.GetName(), nsw.namespace)
   201  	}
   202  
   203  	if isNamespaceScoped && objectNamespace == "" {
   204  		obj.SetNamespace(nsw.namespace)
   205  	}
   206  
   207  	return nsw.client.Get(ctx, obj, subResource, opts...)
   208  }
   209  
   210  func (nsw *namespacedClientSubResourceClient) Create(ctx context.Context, obj, subResource Object, opts ...SubResourceCreateOption) error {
   211  	isNamespaceScoped, err := nsw.namespacedclient.IsObjectNamespaced(obj)
   212  	if err != nil {
   213  		return fmt.Errorf("error finding the scope of the object: %w", err)
   214  	}
   215  
   216  	objectNamespace := obj.GetNamespace()
   217  	if objectNamespace != nsw.namespace && objectNamespace != "" {
   218  		return fmt.Errorf("namespace %s of the object %s does not match the namespace %s on the client", objectNamespace, obj.GetName(), nsw.namespace)
   219  	}
   220  
   221  	if isNamespaceScoped && objectNamespace == "" {
   222  		obj.SetNamespace(nsw.namespace)
   223  	}
   224  
   225  	return nsw.client.Create(ctx, obj, subResource, opts...)
   226  }
   227  
   228  // Update implements client.SubResourceWriter.
   229  func (nsw *namespacedClientSubResourceClient) Update(ctx context.Context, obj Object, opts ...SubResourceUpdateOption) error {
   230  	isNamespaceScoped, err := nsw.namespacedclient.IsObjectNamespaced(obj)
   231  	if err != nil {
   232  		return fmt.Errorf("error finding the scope of the object: %w", err)
   233  	}
   234  
   235  	objectNamespace := obj.GetNamespace()
   236  	if objectNamespace != nsw.namespace && objectNamespace != "" {
   237  		return fmt.Errorf("namespace %s of the object %s does not match the namespace %s on the client", objectNamespace, obj.GetName(), nsw.namespace)
   238  	}
   239  
   240  	if isNamespaceScoped && objectNamespace == "" {
   241  		obj.SetNamespace(nsw.namespace)
   242  	}
   243  	return nsw.client.Update(ctx, obj, opts...)
   244  }
   245  
   246  // Patch implements client.SubResourceWriter.
   247  func (nsw *namespacedClientSubResourceClient) Patch(ctx context.Context, obj Object, patch Patch, opts ...SubResourcePatchOption) error {
   248  	isNamespaceScoped, err := nsw.namespacedclient.IsObjectNamespaced(obj)
   249  	if err != nil {
   250  		return fmt.Errorf("error finding the scope of the object: %w", err)
   251  	}
   252  
   253  	objectNamespace := obj.GetNamespace()
   254  	if objectNamespace != nsw.namespace && objectNamespace != "" {
   255  		return fmt.Errorf("namespace %s of the object %s does not match the namespace %s on the client", objectNamespace, obj.GetName(), nsw.namespace)
   256  	}
   257  
   258  	if isNamespaceScoped && objectNamespace == "" {
   259  		obj.SetNamespace(nsw.namespace)
   260  	}
   261  	return nsw.client.Patch(ctx, obj, patch, opts...)
   262  }
   263  

View as plain text