go.ligato.io/vpp-agent/v3@v3.5.0/plugins/kvscheduler/descriptor_handler.go (about)

     1  package kvscheduler
     2  
     3  import (
     4  	"errors"
     5  	"os"
     6  
     7  	"github.com/vishvananda/netns"
     8  	"google.golang.org/protobuf/proto"
     9  
    10  	kvs "go.ligato.io/vpp-agent/v3/plugins/kvscheduler/api"
    11  )
    12  
    13  // nonRetryableErrors contains global list of non-retryable errors.
    14  var nonRetryableErrors = []error{
    15  	// errors returned by descriptors
    16  	kvs.ErrUnimplementedCreate,
    17  	kvs.ErrUnimplementedDelete,
    18  	kvs.ErrEscapedNetNs,
    19  }
    20  
    21  // AddNonRetryableError adds errs to non-retryable errors.
    22  func AddNonRetryableError(errs ...error) {
    23  	nonRetryableErrors = append(nonRetryableErrors, errs...)
    24  }
    25  
    26  // IsNonRetryableError returns true if err is non-retryable.
    27  func IsNonRetryableError(err error) bool {
    28  	for _, e := range nonRetryableErrors {
    29  		if errors.Is(err, e) {
    30  			return true
    31  		}
    32  	}
    33  	return false
    34  }
    35  
    36  // checking of the original network namespace preservation
    37  var defaultNs netns.NsHandle
    38  var enableNetNsCheck = os.Getenv(checkNetNamespaceEnv) != ""
    39  
    40  func init() {
    41  	defaultNs, _ = netns.Get()
    42  }
    43  
    44  func checkNetNs() error {
    45  	if enableNetNsCheck && defaultNs != -1 {
    46  		ns, nsErr := netns.Get()
    47  		if nsErr == nil {
    48  			defer ns.Close()
    49  		}
    50  		if nsErr == nil && !defaultNs.Equal(ns) {
    51  			return kvs.ErrEscapedNetNs
    52  		}
    53  	}
    54  	return nil
    55  }
    56  
    57  // descriptorHandler handles access to descriptor methods (callbacks).
    58  // For callback not provided, a default return value is returned.
    59  type descriptorHandler struct {
    60  	descriptor *kvs.KVDescriptor
    61  }
    62  
    63  // newDescriptorHandler is a constructor for descriptor handler
    64  func newDescriptorHandler(descr *kvs.KVDescriptor) *descriptorHandler {
    65  	return &descriptorHandler{
    66  		descriptor: descr,
    67  	}
    68  }
    69  
    70  // keyLabel by default returns the key itself.
    71  func (h *descriptorHandler) keyLabel(key string) string {
    72  	if h.descriptor == nil || h.descriptor.KeyLabel == nil {
    73  		return key
    74  	}
    75  	defer trackDescMethod(h.descriptor.Name, "KeyLabel")()
    76  	return h.descriptor.KeyLabel(key)
    77  }
    78  
    79  // equivalentValues by default uses proto.Equal().
    80  func (h *descriptorHandler) equivalentValues(key string, oldValue, newValue proto.Message) bool {
    81  	if h.descriptor == nil || h.descriptor.ValueComparator == nil {
    82  		return proto.Equal(oldValue, newValue)
    83  	}
    84  	defer trackDescMethod(h.descriptor.Name, "ValueComparator")()
    85  	return h.descriptor.ValueComparator(key, oldValue, newValue)
    86  }
    87  
    88  // validate return nil if Validate is not provided (optional method).
    89  func (h *descriptorHandler) validate(key string, value proto.Message) error {
    90  	if h.descriptor == nil || h.descriptor.Validate == nil {
    91  		return nil
    92  	}
    93  	defer trackDescMethod(h.descriptor.Name, "Validate")()
    94  	return h.descriptor.Validate(key, value)
    95  }
    96  
    97  // create returns ErrUnimplementedCreate if Create is not provided.
    98  func (h *descriptorHandler) create(key string, value proto.Message) (metadata kvs.Metadata, err error) {
    99  	if h.descriptor == nil {
   100  		return
   101  	}
   102  	if h.descriptor.Create == nil {
   103  		return nil, kvs.ErrUnimplementedCreate
   104  	}
   105  	defer trackDescMethod(h.descriptor.Name, "Create")()
   106  	metadata, err = h.descriptor.Create(key, value)
   107  	if nsErr := checkNetNs(); nsErr != nil {
   108  		err = nsErr
   109  	}
   110  	return metadata, err
   111  
   112  }
   113  
   114  // update is not called if Update is not provided (updateWithRecreate() returns true).
   115  func (h *descriptorHandler) update(key string, oldValue, newValue proto.Message, oldMetadata kvs.Metadata) (newMetadata kvs.Metadata, err error) {
   116  	if h.descriptor == nil {
   117  		return oldMetadata, nil
   118  	}
   119  	defer trackDescMethod(h.descriptor.Name, "Update")()
   120  	newMetadata, err = h.descriptor.Update(key, oldValue, newValue, oldMetadata)
   121  	if nsErr := checkNetNs(); nsErr != nil {
   122  		err = nsErr
   123  	}
   124  	return newMetadata, err
   125  }
   126  
   127  // updateWithRecreate either forwards the call to UpdateWithRecreate if defined
   128  // by the descriptor, or decides based on the availability of the Update operation.
   129  func (h *descriptorHandler) updateWithRecreate(key string, oldValue, newValue proto.Message, metadata kvs.Metadata) bool {
   130  	if h.descriptor == nil {
   131  		return false
   132  	}
   133  	if h.descriptor.Update == nil {
   134  		// without Update, re-creation is the only way
   135  		return true
   136  	}
   137  	if h.descriptor.UpdateWithRecreate == nil {
   138  		// by default it is assumed that any change can be applied using Update without
   139  		// re-creation
   140  		return false
   141  	}
   142  	defer trackDescMethod(h.descriptor.Name, "UpdateWithRecreate")()
   143  	return h.descriptor.UpdateWithRecreate(key, oldValue, newValue, metadata)
   144  }
   145  
   146  // delete returns ErrUnimplementedDelete if Delete is not provided.
   147  func (h *descriptorHandler) delete(key string, value proto.Message, metadata kvs.Metadata) error {
   148  	if h.descriptor == nil {
   149  		return nil
   150  	}
   151  	if h.descriptor.Delete == nil {
   152  		return kvs.ErrUnimplementedDelete
   153  	}
   154  	defer trackDescMethod(h.descriptor.Name, "Delete")()
   155  	err := h.descriptor.Delete(key, value, metadata)
   156  	if nsErr := checkNetNs(); nsErr != nil {
   157  		err = nsErr
   158  	}
   159  	return err
   160  }
   161  
   162  // isRetriableFailure first checks for errors returned by the handler itself.
   163  // If descriptor does not define IsRetriableFailure, it is assumed any failure
   164  // can be potentially fixed by retry.
   165  func (h *descriptorHandler) isRetriableFailure(err error) bool {
   166  	if IsNonRetryableError(err) {
   167  		return false
   168  	}
   169  	if h.descriptor == nil || h.descriptor.IsRetriableFailure == nil {
   170  		return true
   171  	}
   172  	defer trackDescMethod(h.descriptor.Name, "IsRetriableFailure")()
   173  	return h.descriptor.IsRetriableFailure(err)
   174  }
   175  
   176  // dependencies returns empty list if descriptor does not define any.
   177  func (h *descriptorHandler) dependencies(key string, value proto.Message) (deps []kvs.Dependency) {
   178  	if h.descriptor == nil || h.descriptor.Dependencies == nil {
   179  		return
   180  	}
   181  	// TODO: check that label is unique for each KV pair, throw panic if not (?)
   182  	defer trackDescMethod(h.descriptor.Name, "Dependencies")()
   183  	return h.descriptor.Dependencies(key, value)
   184  }
   185  
   186  // derivedValues returns empty list if descriptor does not define any.
   187  func (h *descriptorHandler) derivedValues(key string, value proto.Message) (derives []kvs.KeyValuePair) {
   188  	if h.descriptor == nil || h.descriptor.DerivedValues == nil {
   189  		return
   190  	}
   191  	defer trackDescMethod(h.descriptor.Name, "DerivedValues")()
   192  	return h.descriptor.DerivedValues(key, value)
   193  }
   194  
   195  // retrieve returns <ableToRetrieve> as false if descriptor does not implement Retrieve.
   196  func (h *descriptorHandler) retrieve(correlate []kvs.KVWithMetadata) (values []kvs.KVWithMetadata, ableToRetrieve bool, err error) {
   197  	if h.descriptor == nil || h.descriptor.Retrieve == nil {
   198  		return values, false, nil
   199  	}
   200  	defer trackDescMethod(h.descriptor.Name, "Retrieve")()
   201  	values, err = h.descriptor.Retrieve(correlate)
   202  	if nsErr := checkNetNs(); nsErr != nil {
   203  		err = nsErr
   204  	}
   205  	return values, true, err
   206  }