...

Source file src/github.com/chaos-mesh/chaos-mesh/cmd/chaos-controller-manager/provider/updated_client.go

Documentation: github.com/chaos-mesh/chaos-mesh/cmd/chaos-controller-manager/provider

     1  // Copyright 2021 Chaos Mesh Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  // http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  //
    15  
    16  package provider
    17  
    18  import (
    19  	"context"
    20  	"reflect"
    21  	"strconv"
    22  
    23  	lru "github.com/hashicorp/golang-lru"
    24  	"k8s.io/apimachinery/pkg/api/meta"
    25  	"k8s.io/apimachinery/pkg/runtime"
    26  	"k8s.io/apimachinery/pkg/types"
    27  	"sigs.k8s.io/controller-runtime/pkg/client"
    28  	"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
    29  )
    30  
    31  var _ client.Client = &UpdatedClient{}
    32  
    33  type UpdatedClient struct {
    34  	client client.Client
    35  	scheme *runtime.Scheme
    36  
    37  	cache *lru.Cache
    38  }
    39  
    40  func (c *UpdatedClient) objectKey(key client.ObjectKey, obj client.Object) (string, error) {
    41  	gvk, err := apiutil.GVKForObject(obj, c.scheme)
    42  	if err != nil {
    43  		return "", err
    44  	}
    45  
    46  	return gvk.String() + "/" + key.String(), nil
    47  }
    48  
    49  func (c *UpdatedClient) Get(ctx context.Context, key client.ObjectKey, obj client.Object) error {
    50  	err := c.client.Get(ctx, key, obj)
    51  	if err != nil {
    52  		return err
    53  	}
    54  
    55  	objectKey, err := c.objectKey(key, obj)
    56  	if err != nil {
    57  		return err
    58  	}
    59  
    60  	cachedObject, ok := c.cache.Get(objectKey)
    61  	if ok {
    62  		cachedMeta, err := meta.Accessor(cachedObject)
    63  		if err != nil {
    64  			return nil
    65  		}
    66  
    67  		objMeta, err := meta.Accessor(obj)
    68  		if err != nil {
    69  			return nil
    70  		}
    71  
    72  		cachedResourceVersion, err := strconv.Atoi(cachedMeta.GetResourceVersion())
    73  		if err != nil {
    74  			return nil
    75  		}
    76  		newResourceVersion, err := strconv.Atoi(objMeta.GetResourceVersion())
    77  		if err != nil {
    78  			return nil
    79  		}
    80  		if cachedResourceVersion >= newResourceVersion {
    81  			cachedObject := cachedObject.(runtime.Object).DeepCopyObject()
    82  
    83  			reflect.ValueOf(obj).Elem().Set(reflect.ValueOf(cachedObject).Elem())
    84  		}
    85  	}
    86  
    87  	return nil
    88  }
    89  
    90  func (c *UpdatedClient) List(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error {
    91  	return c.client.List(ctx, list, opts...)
    92  }
    93  
    94  func (c *UpdatedClient) Create(ctx context.Context, obj client.Object, opts ...client.CreateOption) error {
    95  	return c.client.Create(ctx, obj, opts...)
    96  }
    97  
    98  func (c *UpdatedClient) Delete(ctx context.Context, obj client.Object, opts ...client.DeleteOption) error {
    99  	return c.client.Delete(ctx, obj, opts...)
   100  }
   101  
   102  func (c *UpdatedClient) Update(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
   103  	err := c.client.Update(ctx, obj, opts...)
   104  	if err != nil {
   105  		return err
   106  	}
   107  
   108  	err = c.writeCache(obj)
   109  	if err != nil {
   110  		return err
   111  	}
   112  
   113  	return nil
   114  }
   115  
   116  func (c *UpdatedClient) writeCache(obj client.Object) error {
   117  	objMeta, err := meta.Accessor(obj)
   118  	if err != nil {
   119  		return nil
   120  	}
   121  
   122  	objectKey, err := c.objectKey(types.NamespacedName{
   123  		Namespace: objMeta.GetNamespace(),
   124  		Name:      objMeta.GetName(),
   125  	}, obj)
   126  	if err != nil {
   127  		return err
   128  	}
   129  
   130  	c.cache.Add(objectKey, obj.DeepCopyObject())
   131  
   132  	return nil
   133  }
   134  
   135  func (c *UpdatedClient) Patch(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption) error {
   136  	return c.client.Patch(ctx, obj, patch, opts...)
   137  }
   138  
   139  func (c *UpdatedClient) DeleteAllOf(ctx context.Context, obj client.Object, opts ...client.DeleteAllOfOption) error {
   140  	return c.client.DeleteAllOf(ctx, obj, opts...)
   141  }
   142  
   143  func (c *UpdatedClient) Scheme() *runtime.Scheme {
   144  	return c.client.Scheme()
   145  }
   146  
   147  func (c *UpdatedClient) RESTMapper() meta.RESTMapper {
   148  	return c.client.RESTMapper()
   149  }
   150  
   151  func (c *UpdatedClient) Status() client.StatusWriter {
   152  	return &UpdatedStatusWriter{
   153  		statusWriter: c.client.Status(),
   154  		client:       c,
   155  	}
   156  }
   157  
   158  type UpdatedStatusWriter struct {
   159  	statusWriter client.StatusWriter
   160  	client       *UpdatedClient
   161  }
   162  
   163  func (c *UpdatedStatusWriter) Update(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
   164  	err := c.statusWriter.Update(ctx, obj, opts...)
   165  	if err != nil {
   166  		return err
   167  	}
   168  
   169  	err = c.client.writeCache(obj)
   170  	if err != nil {
   171  		return err
   172  	}
   173  
   174  	return nil
   175  }
   176  
   177  func (c *UpdatedStatusWriter) Patch(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption) error {
   178  	return c.statusWriter.Patch(ctx, obj, patch, opts...)
   179  }
   180