go.ligato.io/vpp-agent/v3@v3.5.0/plugins/kvscheduler/api/kv_scheduler_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 "context" 19 "time" 20 21 "go.ligato.io/cn-infra/v2/idxmap" 22 "google.golang.org/protobuf/proto" 23 24 "go.ligato.io/vpp-agent/v3/proto/ligato/kvscheduler" 25 ) 26 27 // KeySelector is used to filter keys. 28 type KeySelector func(key string) bool 29 30 // KeyValuePair groups key with value. 31 type KeyValuePair struct { 32 // Key identifies value. 33 Key string 34 35 // Value may represent some object, action or property. 36 // 37 // Value can be created either via northbound transaction (NB-value, 38 // ValueOrigin = FromNB) or pushed (as already created) through SB notification 39 // (SB-value, ValueOrigin = FromSB). Values from NB take priority as they 40 // overwrite existing SB values (via Modify operation), whereas notifications 41 // for existing NB values are ignored. For values retrieved with unknown 42 // origin the scheduler reviews the value's history to determine where it came 43 // from. 44 // 45 // For descriptors the values are mutable objects - Create, Update and Delete 46 // methods should reflect the value content without changing it. 47 // To add and maintain extra (runtime) attributes alongside the value, descriptor 48 // can use the value metadata. 49 Value proto.Message 50 } 51 52 // Metadata are extra information carried alongside non-derived (base) value 53 // that descriptor may use for runtime attributes, secondary lookups, etc. This 54 // data are opaque for the scheduler and fully owned by the descriptor. 55 // Descriptor is supposed to create/edit (and use) metadata inside the Create, 56 // Update, Delete methods and return the latest state with Retrieve. 57 // Metadata, however, should not be used to determine the list of derived values 58 // and dependencies for a value - this needs to be fixed for a given value 59 // (Update is effectively replace) and known even before the value is created. 60 // 61 // The only way how scheduler can learn anything from metadata, is if MetadataMap 62 // is enabled by descriptor (using WithMetadata method) and a custom NamedMapping 63 // implementation is provided that defines secondary indexes (over metadata). 64 // The scheduler exposes the current snapshot of secondary indexes, but otherwise 65 // is not familiar with their semantics. 66 type Metadata interface{} 67 68 // KeyWithError stores error for a key whose value failed to get updated. 69 type KeyWithError struct { 70 Key string 71 TxnOperation kvscheduler.TxnOperation 72 Error error 73 } 74 75 // KVWithMetadata encapsulates key-value pair with metadata and the origin mark. 76 type KVWithMetadata struct { 77 Key string 78 Value proto.Message 79 Metadata Metadata 80 Origin ValueOrigin 81 } 82 83 // View chooses from which point of view to look at the key-value space when 84 // retrieving values. 85 type View int 86 87 const ( 88 // SBView means to look directly into SB via Retrieve methods of descriptors 89 // to learn the real and up-to-date state of the system. 90 SBView View = iota 91 92 // NBView means to look at the key-value space from NB point of view, i.e. 93 // what key-values were requested and are assumed by NB to be applied. 94 NBView 95 96 // CachedView means to obtain the kvscheduler's current view of SB. 97 CachedView 98 ) 99 100 // String converts View to string. 101 func (v View) String() string { 102 switch v { 103 case SBView: 104 return "SB" 105 case NBView: 106 return "NB" 107 default: 108 return "cached" 109 } 110 } 111 112 // KVScheduler synchronizes the *desired* system state described by northbound 113 // (NB) components via transactions with the *actual* state of the southbound (SB). 114 // The system state is represented as a set of inter-dependent key-value pairs 115 // that can be created, updated, deleted from within NB transactions or be notified 116 // about via notifications from the SB plane. 117 // The scheduling basically implements "state reconciliation" - periodically and 118 // on any change the scheduler attempts to update every value which has satisfied 119 // dependencies but is out-of-sync with the desired state given by NB. 120 // 121 // For the scheduler, the key-value pairs are just abstract items that need 122 // to be managed in a synchronized fashion according to the described relations. 123 // It is up to the SB components to assign actual meaning to the individual 124 // values via provided implementations for CRUD operations. 125 // 126 // The idea behind scheduler is based on the Mediator pattern - SB components 127 // do not communicate directly, but instead interact through the mediator. 128 // This reduces the dependencies between communicating objects, thereby reducing 129 // coupling. 130 // 131 // The values are described for scheduler by registered KVDescriptor-s. 132 // The scheduler learns two kinds of relations between values that have to be 133 // respected by the scheduling algorithm: 134 // -> A depends on B: 135 // - A cannot exist without B 136 // - request to create A without B existing must be postponed by storing 137 // A into the cache of values with unmet dependencies (a.k.a. pending) 138 // - if B is to be removed and A exists, A must be removed first 139 // and cached in case B is restored in the future 140 // - Note: values pushed from SB are not checked for dependencies 141 // -> B is derived from A: 142 // - value B is not created directly (by NB or SB) but gets derived 143 // from base value A (using the DerivedValues() method of the base 144 // value's descriptor) 145 // - derived value exists only as long as its base does and gets removed 146 // (without caching) once the base value goes away 147 // - derived value may be described by a different descriptor than 148 // the base and usually represents property of the base value (that 149 // other values may depend on) or an extra action to be taken 150 // when additional dependencies are met. 151 // 152 // Every key-value pair must have at most one descriptor associated with it. 153 // Base NB value without descriptor is considered unimplemented and will never 154 // be created. 155 // On the other hand, derived value is allowed to have no descriptor associated 156 // with it. Typically, properties of base values are implemented as derived 157 // (often empty) values without attached SB operations, used as targets for 158 // dependencies. 159 // 160 // For descriptors the values are mutable objects - Create, Update and Delete 161 // methods should reflect the value content without changing it. 162 // To add and maintain extra (runtime) attributes alongside the value, scheduler 163 // allows descriptors to append metadata - of any type - to each created 164 // non-derived Object value. Descriptor can also use the metadata to define 165 // secondary lookups, exposed via MetadataMap. 166 // 167 // Advantages of the centralized scheduling are: 168 // - easy to add new descriptors and dependencies 169 // - decreases the likelihood of race conditions and deadlocks in systems with 170 // complex dependencies 171 // - allows to write loosely-coupled SB components (mediator pattern) 172 // - descriptor API will force new SB components to follow the same 173 // code structure which will make them easier to familiarize with 174 // - NB components should never worry about dependencies between requests - 175 // it is taken care of by the scheduler 176 // - single cache for all (not only pending) values (exposed via REST, 177 // easier to debug) 178 // 179 // Apart from scheduling and execution, KVScheduler also offers the following 180 // features: 181 // - collecting and counting present and past errors individually for every 182 // key 183 // - retry for previously failed actions 184 // - transaction reverting 185 // - exposing history of actions, errors and past value revisions over the REST 186 // interface 187 // - clearly describing the sequence of actions to be executed and postponed 188 // in the log file 189 // - allows to print verbose log messages describing graph traversal during 190 // transactions for debugging purposes 191 // - exposing graph snapshot, in the present state or after a given transaction, 192 // as a plotted graph (returned via REST) with values as nodes (colored to 193 // distinguish various value states) and dependencies/derivations as edges. 194 type KVScheduler interface { 195 ValueProvider 196 197 // RegisterKVDescriptor registers descriptor(s) for a set of selected 198 // keys. It should be called in the Init phase of agent plugins. 199 // Every key-value pair must have at most one descriptor associated with it 200 // (none for derived values expressing properties). 201 RegisterKVDescriptor(descriptor ...*KVDescriptor) error 202 203 // GetRegisteredNBKeyPrefixes returns a list of key prefixes from NB with values 204 // described by registered descriptors and therefore managed by the scheduler. 205 GetRegisteredNBKeyPrefixes() []string 206 207 // StartNBTransaction starts a new transaction from NB to SB plane. 208 // The enqueued actions are scheduled for execution by Txn.Commit(). 209 StartNBTransaction() Txn 210 211 // TransactionBarrier ensures that all notifications received prior to the call 212 // are associated with transactions that have already finalized. 213 TransactionBarrier() 214 215 // PushSBNotification notifies about a spontaneous value change in the SB 216 // plane (i.e. not triggered by NB transaction). 217 // 218 // Pass <value> as nil if the value was removed, non-nil otherwise. 219 // 220 // Values pushed from SB do not trigger Create/Update/Delete operations 221 // on the descriptors - the change has already happened in SB - only 222 // dependencies and derived values are updated. 223 // 224 // Values pushed from SB are overwritten by those created via NB transactions, 225 // however. For example, notifications for values already created by NB 226 // are ignored. But otherwise, SB values (not managed by NB) are untouched 227 // by reconciliation or any other operation of the scheduler/descriptor. 228 // Note: Origin in KVWithMetadata is ignored and can be left unset 229 // (automatically assumed to be FromSB). 230 PushSBNotification(notif ...KVWithMetadata) error 231 232 // GetMetadataMap returns (read-only) map associating value label with value 233 // metadata of a given descriptor. 234 // Returns nil if the descriptor does not expose metadata. 235 GetMetadataMap(descriptor string) idxmap.NamedMapping 236 237 // GetValueStatus returns the status of a non-derived value with the given 238 // key. 239 GetValueStatus(key string) *kvscheduler.BaseValueStatus 240 241 // WatchValueStatus allows to watch for changes in the status of non-derived 242 // values with keys selected by the selector (all if keySelector==nil). 243 WatchValueStatus(channel chan<- *kvscheduler.BaseValueStatus, keySelector KeySelector) 244 245 // GetTransactionHistory returns history of transactions started within 246 // the specified time window, or the full recorded history if the timestamps 247 // are zero values. 248 GetTransactionHistory(since, until time.Time) (history RecordedTxns) 249 250 // GetRecordedTransaction returns record of a transaction referenced 251 // by the sequence number. 252 GetRecordedTransaction(SeqNum uint64) (txn *RecordedTxn) 253 254 // ValidateSemantically validates given proto messages according to semantic validation(KVDescriptor.Validate) 255 // from registered KVDescriptors. If all locally known messages are valid, nil is returned. If some locally known 256 // messages are invalid, kvscheduler.MessageValidationErrors is returned. In any other case, error is returned. 257 // 258 // Usage of dynamic proto messages (dynamicpb.Message) described by remotely known models is not supported. 259 // The reason for this is that the KVDescriptors can validate only statically generated proto messages and 260 // remotely retrieved dynamic proto messages can't be converted to such proto messages (there are 261 // no locally available statically generated proto models). 262 ValidateSemantically([]proto.Message) error 263 } 264 265 // ValueProvider provides key/value data from different sources in system (NB, SB, KVProvider cache of SB) 266 type ValueProvider interface { 267 // DumpValuesByDescriptor dumps values associated with the given 268 // descriptor as viewed from either NB (what was requested to be applied), 269 // SB (what is actually applied) or from the inside (what kvscheduler's 270 // cached view of SB is). 271 DumpValuesByDescriptor(descriptor string, view View) (kvs []KVWithMetadata, err error) 272 273 // DumpValuesByKeyPrefix like DumpValuesByDescriptor returns a dump of values, 274 // but the descriptor is selected based on the key prefix. 275 DumpValuesByKeyPrefix(keyPrefix string, view View) (kvs []KVWithMetadata, err error) 276 } 277 278 // Txn represent a single transaction. 279 // Scheduler starts to plan and execute actions only after Commit is called. 280 type Txn interface { 281 // SetValue changes (non-derived) value. 282 // If <value> is nil, the value will get deleted. 283 SetValue(key string, value proto.Message) Txn 284 285 // Commit orders scheduler to execute enqueued operations. 286 // Operations with unmet dependencies will get postponed and possibly 287 // executed later. 288 // <ctx> allows to pass transaction options (see With* functions from 289 // txn_options.go) or to cancel waiting for the end of a blocking transaction. 290 // 291 // For blocking transactions, the method returns the sequence number 292 // of the (finalized) transaction or ^uint64(0) (max uint64) if the transaction 293 // failed to even get initialized. In case of failures during the initialization 294 // or transaction processing, the method will return non-nil error, which is 295 // always an instance of TransactionError (see errors.go), wrapping all errors 296 // encountered during the transaction processing. 297 // 298 // Non-blocking transactions return immediately and always without errors. 299 // Subscribe with KVScheduler.WatchValueStatus() to get notified about all 300 // changes/errors, including those related to actions triggered later 301 // or asynchronously by a SB notification. 302 Commit(ctx context.Context) (txnSeqNum uint64, err error) 303 }