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 }