go.ligato.io/vpp-agent/v3@v3.5.0/plugins/kvscheduler/api/kv_descriptor_api.go (about) 1 // Copyright (c) 2018 Cisco and/or its affiliates. 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 package api 16 17 import ( 18 "go.ligato.io/cn-infra/v2/idxmap" 19 "google.golang.org/protobuf/proto" 20 ) 21 22 // Dependency references another kv pair that must exist before the associated 23 // value can be created. 24 type Dependency struct { 25 // Label should be a short human-readable string labeling the dependency. 26 // Must be unique in the list of dependencies for a value. 27 Label string 28 29 // Key of another kv pair that the associated value depends on. 30 // If empty, AnyOf must be defined instead. 31 Key string 32 33 // AnyOf defines a set of keys from which at least one must reference 34 // a created object for the dependency to be considered satisfied - i.e. 35 // **any of** the matched keys is good enough to satisfy the dependency. 36 // Either Key or AnyOf should be defined, but not both at the same time. 37 // BEWARE: AnyOf comes with more overhead than a static key dependency 38 // (especially when KeySelector is used without KeyPrefixes), so prefer to 39 // use Key whenever possible. 40 AnyOf AnyOfDependency 41 } 42 43 // AnyOfDependency defines a set of keys from which at least one must reference 44 // a created object for the dependency to be considered satisfied. 45 // 46 // KeyPrefixes jointly select a set of keys that begin with at least one of the 47 // defined key prefixes, potentially further filtered by KeySelector, which is 48 // typically parsing and evaluating key suffix to check if it satisfies the 49 // dependency (i.e. the selections of KeyPrefixes and KeySelector are 50 // **intersected**). 51 // 52 // KeyPrefixes and KeySelector can be combined, but also used as standalone. 53 // However, using only KeySelector without limiting the set of candidates using 54 // prefixes is very costly - for the scheduling algorithm the key selector is 55 // a black box that can potentially match any key and must be therefore checked 56 // with every key entering the key space (i.e. linear complexity as opposed to 57 // logarithmic complexity when the key space is suitably reduced with prefixes). 58 type AnyOfDependency struct { 59 // KeyPrefixes is a list of all (longest common) key prefixes found in the 60 // keys satisfying the dependency. If defined (not empty), the scheduler will 61 // know that for a given key to match the dependency, it must begin with at 62 // least one of the specified prefixes. 63 // Keys matched by these prefixes can be further filtered with the KeySelector 64 // below. 65 KeyPrefixes []string 66 67 // KeySelector, if defined (non-nil), must return true for at least one of 68 // the already created keys for the dependency to be considered satisfied. 69 // It is recommended to narrow down the set of candidates as much as possible 70 // using KeyPrefixes, so that the KeySelector will not have to be called too 71 // many times, limiting its impact on the performance. 72 KeySelector KeySelector 73 } 74 75 // MetadataMapFactory can be used by descriptor to define a custom map associating 76 // value labels with value metadata, potentially extending the basic in-memory 77 // implementation (memNamedMapping) with secondary indexes, type-safe watch, etc. 78 // If metadata are enabled (by WithMetadata method), the scheduler will create 79 // an instance of the map using the provided factory during the descriptor 80 // registration (RegisterKVDescriptor). Immediately afterwards, the mapping 81 // is available read-only via scheduler's method GetMetadataMap. The returned 82 // map can be then casted to the customized implementation, but it should remain 83 // read-only (i.e. define read-only interface for the customized implementation). 84 type MetadataMapFactory func() idxmap.NamedMappingRW 85 86 // ValueOrigin is one of: FromNB, FromSB, UnknownOrigin. 87 type ValueOrigin int 88 89 const ( 90 // UnknownOrigin is given to a retrieved value when it cannot be determined 91 // if the value was previously created by NB or not. 92 // Scheduler will then look into its history to find out if the value was 93 // ever managed by NB to determine the origin heuristically. 94 UnknownOrigin ValueOrigin = iota 95 96 // FromNB marks value created via NB transaction. 97 FromNB 98 99 // FromSB marks value not managed by NB - i.e. created automatically or 100 // externally in SB. 101 FromSB 102 ) 103 104 // String converts ValueOrigin to string. 105 func (vo ValueOrigin) String() string { 106 switch vo { 107 case FromNB: 108 return "from-NB" 109 case FromSB: 110 return "from-SB" 111 default: 112 return "unknown" 113 } 114 } 115 116 // KVDescriptor teaches KVScheduler how to CRUD values under keys matched 117 // by KeySelector(). 118 // 119 // Every SB component should define one or more descriptors to cover all 120 // (non-property) keys under its management. The descriptor is what in essence 121 // gives meaning to individual key-value pairs. The list of available keys and 122 // their purpose should be properly documented so that clients from the NB plane 123 // can use them correctly. The scheduler does not care what CRUD methods do, 124 // it only needs to call the right callbacks at the right time. 125 // 126 // Every key-value pair must have at most one descriptor associated with it. 127 // NB base value without descriptor is considered unimplemented and will never 128 // be created. 129 // On the other hand, derived value is allowed to have no descriptor associated 130 // with it. Typically, properties of base values are implemented as derived 131 // (often empty) values without attached SB operations, used as targets for 132 // dependencies. 133 type KVDescriptor struct { 134 // Name of the descriptor unique across all registered descriptors. 135 Name string 136 137 // TODO: replace KeySelector, KeyLabel & NBKeyPrefix with methods from 138 // models.Spec. 139 140 // KeySelector selects keys described by this descriptor. 141 KeySelector KeySelector 142 143 // TODO: obsolete, remove once Orchestrator is completed 144 // ValueTypeName defines name of the proto.Message type used to represent 145 // described values. This attribute is mandatory, otherwise LazyValue-s 146 // received from NB (e.g. datasync package) cannot be un-marshalled. 147 // Note: proto Messages are registered against this type name in the generated 148 // code using proto.RegisterType(). 149 ValueTypeName string 150 151 // KeyLabel can be *optionally* defined to provide a *shorter* value 152 // identifier, that, unlike the original key, only needs to be unique in the 153 // key scope of the descriptor and not necessarily in the entire key space. 154 // If defined, key label will be used as value identifier in the metadata map 155 // and in the non-verbose logs. 156 KeyLabel func(key string) string 157 158 // NBKeyPrefix is a key prefix that the scheduler should watch 159 // in NB to receive all NB-values described by this descriptor. 160 // The key space defined by NBKeyPrefix may cover more than KeySelector 161 // selects - the scheduler will filter the received values and pass 162 // to the descriptor only those that are really chosen by KeySelector. 163 // The opposite may be true as well - KeySelector may select some extra 164 // SB-only values, which the scheduler will not watch for in NB. Furthermore, 165 // the keys may already be requested for watching by another descriptor 166 // within the same plugin and in such case it is not needed to mention the 167 // same prefix again. 168 NBKeyPrefix string 169 170 // ValueComparator can be *optionally* provided to customize comparision 171 // of values for equality. 172 // Scheduler compares values to determine if Update operation is really 173 // needed. 174 // For NB values, <oldValue> was either previously set by NB or refreshed 175 // from SB, whereas <newValue> is a new value to be applied by NB. 176 ValueComparator func(key string, oldValue, newValue proto.Message) bool 177 178 // WithMetadata tells scheduler whether to enable metadata - run-time, 179 // descriptor-owned, scheduler-opaque, data carried alongside a created 180 // (non-derived) value. 181 // If enabled, the scheduler will maintain a map between key (-label, if 182 // KeyLabel is defined) and the associated metadata. 183 // If <WithMetadata> is false, metadata returned by Create will be ignored 184 // and other methods will receive nil metadata. 185 WithMetadata bool 186 187 // MetadataMapFactory can be used to provide a customized map implementation 188 // for value metadata, possibly extended with secondary lookups. 189 // If not defined, the scheduler will use the bare NamedMapping from 190 // the idxmap package. 191 MetadataMapFactory MetadataMapFactory 192 193 // Validate value handler (optional). 194 // Validate is called for every new value before it is Created or Updated. 195 // If the validations fails (returned <err> is non-nil), the scheduler will 196 // mark the value as invalid and will not attempt to apply it. 197 // The descriptor can further specify which field(s) are not valid 198 // by wrapping the validation error together with a slice of invalid fields 199 // using the error InvalidValueError (see errors.go). 200 Validate func(key string, value proto.Message) error 201 202 // Create new value handler. 203 // For non-derived values, descriptor may return metadata to associate with 204 // the value. 205 // For derived values, Create+Delete+Update are optional. Typically, properties 206 // of base values are implemented as derived (often empty) values without 207 // attached SB operations, used as targets for dependencies. 208 Create func(key string, value proto.Message) (metadata Metadata, err error) 209 210 // Delete value handler. 211 // If Create is defined, Delete handler must be provided as well. 212 Delete func(key string, value proto.Message, metadata Metadata) error 213 214 // Update value handler. 215 // The handler is optional - if not defined, value change will be carried out 216 // via full re-creation (Delete followed by Create with the new value). 217 // <newMetadata> can re-use the <oldMetadata>. 218 Update func(key string, oldValue, newValue proto.Message, oldMetadata Metadata) (newMetadata Metadata, err error) 219 220 // UpdateWithRecreate can be defined to tell the scheduler if going from 221 // <oldValue> to <newValue> requires the value to be completely re-created 222 // with Delete+Create handlers. 223 // If not defined, KVScheduler will decide based on the (un)availability 224 // of the Update operation - if provided, it is assumed that any change 225 // can be applied incrementally, otherwise a full re-creation is the only way 226 // to go. 227 UpdateWithRecreate func(key string, oldValue, newValue proto.Message, metadata Metadata) bool 228 229 // Retrieve should return all non-derived values described by this descriptor 230 // that *really* exist in the southbound plane (and not what the current 231 // scheduler's view of SB is). Derived value will get automatically created 232 // using the method DerivedValues(). If some non-derived value doesn't 233 // actually exist, it shouldn't be returned by DerivedValues() for the 234 // retrieved base value! 235 // <correlate> represents the non-derived values currently created 236 // as viewed from the northbound/scheduler point of view: 237 // -> startup resync: <correlate> = values received from NB to be applied 238 // -> run-time/downstream resync: <correlate> = values applied according 239 // to the in-memory kv-store (scheduler's view of SB) 240 // 241 // The callback is optional - if not defined, it is assumed that descriptor 242 // is not able to read the current SB state and thus refresh cannot be 243 // performed for its kv-pairs. 244 Retrieve func(correlate []KVWithMetadata) ([]KVWithMetadata, error) 245 246 // IsRetriableFailure tells scheduler if the given error, returned by one 247 // of Create/Delete/Update handlers, will always be returned for the 248 // the same value (non-retriable) or if the value can be theoretically 249 // fixed merely by repeating the operation. 250 // If the callback is not defined, every error will be considered retriable. 251 IsRetriableFailure func(err error) bool 252 253 // DerivedValues returns ("derived") values solely inferred from the current 254 // state of this ("base") value. Derived values cannot be changed by NB 255 // transaction. 256 // While their state and existence is bound to the state of their base value, 257 // they are allowed to have their own descriptors. 258 // 259 // Typically, derived value represents the base value's properties (that 260 // other kv pairs may depend on), or extra actions taken when additional 261 // dependencies are met, but otherwise not blocking the base 262 // value from being created. 263 // 264 // The callback is optional - if not defined, there will be no values derived 265 // from kv-pairs of the descriptor. 266 DerivedValues func(key string, value proto.Message) []KeyValuePair 267 268 // Dependencies are keys that must already exist for the value to be created. 269 // Conversely, if a dependency is to be removed, all values that depend on it 270 // are deleted first and cached for a potential future re-creation. 271 // Dependencies returned in the list are AND-ed. 272 // The callback is optional - if not defined, the kv-pairs of the descriptor 273 // are assumed to have no dependencies. 274 Dependencies func(key string, value proto.Message) []Dependency 275 276 // RetrieveDependencies is a list of descriptors whose values are needed 277 // and should be already retrieved prior to calling Retrieve for this 278 // descriptor. 279 // Metadata for values already retrieved are available via GetMetadataMap(). 280 // TODO: define dependencies as a slice of models, not descriptors. 281 RetrieveDependencies []string /* descriptor name */ 282 }