Documentation ¶
Index ¶
- Variables
- func ErrInvalidMetadataType(key string) error
- func ErrInvalidValueType(key string, value proto.Message) error
- func IsNonBlockingTxn(ctx context.Context) bool
- func IsWithDescription(ctx context.Context) (description string, withDescription bool)
- func IsWithRevert(ctx context.Context) bool
- func IsWithSimulation(ctx context.Context) bool
- func WithDescription(ctx context.Context, description string) context.Context
- func WithResync(ctx context.Context, resyncType ResyncType, verboseSBRefresh bool) context.Context
- func WithRetry(ctx context.Context, period time.Duration, maxCount int, expBackoff bool) context.Context
- func WithRetryDefault(ctx context.Context) context.Context
- func WithRetryMaxCount(ctx context.Context, maxCount int) context.Context
- func WithRevert(ctx context.Context) context.Context
- func WithSimulation(ctx context.Context) context.Context
- func WithoutBlocking(ctx context.Context) context.Context
- type AnyOfDependency
- type BaseValueStatus
- func (*BaseValueStatus) Descriptor() ([]byte, []int)
- func (m *BaseValueStatus) GetDerivedValues() []*ValueStatus
- func (m *BaseValueStatus) GetValue() *ValueStatus
- func (*BaseValueStatus) ProtoMessage()
- func (m *BaseValueStatus) Reset()
- func (m *BaseValueStatus) String() string
- func (m *BaseValueStatus) XXX_DiscardUnknown()
- func (m *BaseValueStatus) XXX_Marshal(b []byte, deterministic bool) ([]byte, error)
- func (dst *BaseValueStatus) XXX_Merge(src proto.Message)
- func (m *BaseValueStatus) XXX_Size() int
- func (m *BaseValueStatus) XXX_Unmarshal(b []byte) error
- type Dependency
- type InvalidValueError
- type KVDescriptor
- type KVScheduler
- type KVWithMetadata
- type KeySelector
- type KeyValuePair
- type KeyWithError
- type Metadata
- type MetadataMapFactory
- type RecordedKVPair
- type RecordedTxn
- type RecordedTxnOp
- type RecordedTxnOps
- type RecordedTxns
- type ResyncType
- type RetryOpt
- type TransactionError
- type Txn
- type TxnOperation
- type TxnType
- type ValueOrigin
- type ValueProvider
- type ValueState
- type ValueStatus
- func (*ValueStatus) Descriptor() ([]byte, []int)
- func (m *ValueStatus) GetDetails() []string
- func (m *ValueStatus) GetError() string
- func (m *ValueStatus) GetKey() string
- func (m *ValueStatus) GetLastOperation() TxnOperation
- func (m *ValueStatus) GetState() ValueState
- func (m *ValueStatus) MarshalJSON() ([]byte, error)
- func (*ValueStatus) ProtoMessage()
- func (m *ValueStatus) Reset()
- func (m *ValueStatus) String() string
- func (m *ValueStatus) UnmarshalJSON(data []byte) error
- func (m *ValueStatus) XXX_DiscardUnknown()
- func (m *ValueStatus) XXX_Marshal(b []byte, deterministic bool) ([]byte, error)
- func (dst *ValueStatus) XXX_Merge(src proto.Message)
- func (m *ValueStatus) XXX_Size() int
- func (m *ValueStatus) XXX_Unmarshal(b []byte) error
- type VerificationError
- type VerificationErrorType
- type View
Constants ¶
This section is empty.
Variables ¶
var ( // ErrCombinedDownstreamResyncWithChange is returned when transaction combines downstream-resync with data changes. ErrCombinedDownstreamResyncWithChange = errors.New("downstream resync combined with data changes in one transaction") // ErrRevertNotSupportedWithResync is returned when transaction combines resync with revert. ErrRevertNotSupportedWithResync = errors.New("it is not supported to combine resync with revert") // ErrClosedScheduler is returned when scheduler is closed during transaction execution. ErrClosedScheduler = errors.New("scheduler was closed") // ErrTxnWaitCanceled is returned when waiting for result of blocking transaction is canceled. ErrTxnWaitCanceled = errors.New("waiting for result of blocking transaction was canceled") // ErrTxnQueueFull is returned when the queue of pending transactions is full. ErrTxnQueueFull = errors.New("transaction queue is full") // ErrUnimplementedCreate is returned when NB transaction attempts to Create value // for which there is a descriptor, but Create operation is not implemented. ErrUnimplementedCreate = errors.New("operation Create is not implemented") // ErrUnimplementedDelete is returned when NB transaction attempts to Delete value // for which there is a descriptor, but Delete operation is not implemented. ErrUnimplementedDelete = errors.New("operation Delete is not implemented") // ErrDescriptorExists is returned when the same descriptor is registered // more than once. ErrDescriptorExists = errors.New("descriptor already exist") // ErrEscapedNetNs is returned when a descriptor changes the Linux network // namespace but forgets to revert the change back before returning from the // operation back to the scheduler. ErrEscapedNetNs = errors.New("operation didn't preserve the original network namespace") )
var ( // DefaultRetryPeriod delays first retry by one second. DefaultRetryPeriod = time.Second // DefaultRetryMaxCount limits the number of retries to 3 attempts at maximum. DefaultRetryMaxCount = 3 // DefaultRetryBackoff enables exponential back-off for retry delay. DefaultRetryBackoff = true )
modifiable default parameters for the *retry* txn option
var TxnOperation_name = map[int32]string{
0: "UNDEFINED",
1: "VALIDATE",
2: "CREATE",
3: "UPDATE",
4: "DELETE",
}
var TxnOperation_value = map[string]int32{
"UNDEFINED": 0,
"VALIDATE": 1,
"CREATE": 2,
"UPDATE": 3,
"DELETE": 4,
}
var ValueState_name = map[int32]string{
0: "NONEXISTENT",
1: "MISSING",
2: "UNIMPLEMENTED",
3: "REMOVED",
4: "CONFIGURED",
5: "OBTAINED",
6: "DISCOVERED",
7: "PENDING",
8: "INVALID",
9: "FAILED",
10: "RETRYING",
}
var ValueState_value = map[string]int32{
"NONEXISTENT": 0,
"MISSING": 1,
"UNIMPLEMENTED": 2,
"REMOVED": 3,
"CONFIGURED": 4,
"OBTAINED": 5,
"DISCOVERED": 6,
"PENDING": 7,
"INVALID": 8,
"FAILED": 9,
"RETRYING": 10,
}
Functions ¶
func ErrInvalidMetadataType ¶
ErrInvalidMetadataType is returned to scheduler by auto-generated descriptor adapter when value metadata does not match expected type.
func ErrInvalidValueType ¶
ErrInvalidValueType is returned to scheduler by auto-generated descriptor adapter when value does not match expected type.
func IsNonBlockingTxn ¶
IsNonBlockingTxn returns true if transaction context is configured for non-blocking Commit.
func IsWithDescription ¶
IsWithDescription returns true if the transaction context is configured to include transaction description.
func IsWithRevert ¶
IsWithRevert returns true if the transaction context is configured to revert transaction if any of its operations fails.
func IsWithSimulation ¶
IsWithSimulation returns true if transaction context is configured to enable pre-execution simulation.
func WithDescription ¶
WithDescription prepares context for transaction that will have description provided. By default, transactions are without description.
func WithResync ¶
WithResync prepares context for transaction that, based on the resync type, will trigger resync between the configuration states of NB, the agent and SB. For DownstreamResync the transaction should be empty, otherwise it should carry non-NIL values - existing NB values not included in the transaction are automatically removed. When <verboseSBRefresh> is enabled, the refreshed state of SB will be printed into stdout. The argument is irrelevant for UpstreamResync, where SB state is not refreshed.
func WithRetry ¶
func WithRetry(ctx context.Context, period time.Duration, maxCount int, expBackoff bool) context.Context
WithRetry prepares context for transaction for which the scheduler will retry any (retriable) failed operations after given <period>. If <expBackoff> is enabled, every failed retry will double the next delay. Non-zero <maxCount> limits the maximum number of retries the scheduler will execute. Can be combined with revert - even failed revert operations will be re-tried. By default, the scheduler will not automatically retry failed operations.
func WithRetryDefault ¶
WithRetryDefault is a specialization of WithRetry, where retry parameters are set to default values.
func WithRetryMaxCount ¶
WithRetryMaxCount is a specialization of WithRetry, where <period> and <expBackoff> are set to default values and the maximum number of retries can be customized.
func WithRevert ¶
WithRevert prepares context for transaction that will be reverted if any of its operations fails. By default, the scheduler executes transactions in a best-effort mode - even in the case of an error it will keep the effects of successful operations.
func WithSimulation ¶
WithSimulation enables simulation of txn operations, which is triggered before execution to obtain the sequence of intended operations without actually calling any CRUD operations and assuming no failures. By default, simulation is disabled.
Types ¶
type AnyOfDependency ¶
type AnyOfDependency struct { // KeyPrefixes is a list of all (longest common) key prefixes found in the // keys satisfying the dependency. If defined (not empty), the scheduler will // know that for a given key to match the dependency, it must begin with at // least one of the specified prefixes. // Keys matched by these prefixes can be further filtered with the KeySelector // below. KeyPrefixes []string // KeySelector, if defined (non-nil), must return true for at least one of // the already created keys for the dependency to be considered satisfied. // It is recommended to narrow down the set of candidates as much as possible // using KeyPrefixes, so that the KeySelector will not have to be called too // many times, limiting its impact on the performance. KeySelector KeySelector }
AnyOfDependency defines a set of keys from which at least one must reference a created object for the dependency to be considered satisfied.
KeyPrefixes jointly select a set of keys that begin with at least one of the defined key prefixes, potentially further filtered by KeySelector, which is typically parsing and evaluating key suffix to check if it satisfies the dependency (i.e. the selections of KeyPrefixes and KeySelector are **intersected**).
KeyPrefixes and KeySelector can be combined, but also used as standalone. However, using only KeySelector without limiting the set of candidates using prefixes is very costly - for the scheduling algorithm the key selector is a black box that can potentially match any key and must be therefore checked with every key entering the key space (i.e. linear complexity as opposed to logarithmic complexity when the key space is suitably reduced with prefixes).
type BaseValueStatus ¶
type BaseValueStatus struct { Value *ValueStatus `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"` DerivedValues []*ValueStatus `protobuf:"bytes,2,rep,name=derived_values,json=derivedValues,proto3" json:"derived_values,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` }
func (*BaseValueStatus) Descriptor ¶
func (*BaseValueStatus) Descriptor() ([]byte, []int)
func (*BaseValueStatus) GetDerivedValues ¶
func (m *BaseValueStatus) GetDerivedValues() []*ValueStatus
func (*BaseValueStatus) GetValue ¶
func (m *BaseValueStatus) GetValue() *ValueStatus
func (*BaseValueStatus) ProtoMessage ¶
func (*BaseValueStatus) ProtoMessage()
func (*BaseValueStatus) Reset ¶
func (m *BaseValueStatus) Reset()
func (*BaseValueStatus) String ¶
func (m *BaseValueStatus) String() string
func (*BaseValueStatus) XXX_DiscardUnknown ¶
func (m *BaseValueStatus) XXX_DiscardUnknown()
func (*BaseValueStatus) XXX_Marshal ¶
func (m *BaseValueStatus) XXX_Marshal(b []byte, deterministic bool) ([]byte, error)
func (*BaseValueStatus) XXX_Merge ¶
func (dst *BaseValueStatus) XXX_Merge(src proto.Message)
func (*BaseValueStatus) XXX_Size ¶
func (m *BaseValueStatus) XXX_Size() int
func (*BaseValueStatus) XXX_Unmarshal ¶
func (m *BaseValueStatus) XXX_Unmarshal(b []byte) error
type Dependency ¶
type Dependency struct { // Label should be a short human-readable string labeling the dependency. // Must be unique in the list of dependencies for a value. Label string // Key of another kv pair that the associated value depends on. // If empty, AnyOf must be defined instead. Key string // AnyOf defines a set of keys from which at least one must reference // a created object for the dependency to be considered satisfied - i.e. // **any of** the matched keys is good enough to satisfy the dependency. // Either Key or AnyOf should be defined, but not both at the same time. // BEWARE: AnyOf comes with more overhead than a static key dependency // (especially when KeySelector is used without KeyPrefixes), so prefer to // use Key whenever possible. AnyOf AnyOfDependency }
Dependency references another kv pair that must exist before the associated value can be created.
type InvalidValueError ¶
type InvalidValueError struct {
// contains filtered or unexported fields
}
InvalidValueError can be used by descriptor for the Validate method to return validation error together with a list of invalid fields for further clarification.
func NewInvalidValueError ¶
func NewInvalidValueError(err error, invalidFields ...string) *InvalidValueError
NewInvalidValueError is a constructor for invalid-value error.
func (*InvalidValueError) Error ¶
func (e *InvalidValueError) Error() string
Error returns a string representation of all errors encountered during the transaction processing.
func (*InvalidValueError) GetInvalidFields ¶
func (e *InvalidValueError) GetInvalidFields() []string
GetInvalidFields returns internally stored slice of invalid fields.
func (*InvalidValueError) GetValidationError ¶
func (e *InvalidValueError) GetValidationError() error
GetValidationError returns internally stored validation error.
type KVDescriptor ¶
type KVDescriptor struct { // Name of the descriptor unique across all registered descriptors. Name string // KeySelector selects keys described by this descriptor. KeySelector KeySelector // TODO: obsolete, remove once Orchestrator is completed // ValueTypeName defines name of the proto.Message type used to represent // described values. This attribute is mandatory, otherwise LazyValue-s // received from NB (e.g. datasync package) cannot be un-marshalled. // Note: proto Messages are registered against this type name in the generated // code using proto.RegisterType(). ValueTypeName string // KeyLabel can be *optionally* defined to provide a *shorter* value // identifier, that, unlike the original key, only needs to be unique in the // key scope of the descriptor and not necessarily in the entire key space. // If defined, key label will be used as value identifier in the metadata map // and in the non-verbose logs. KeyLabel func(key string) string // NBKeyPrefix is a key prefix that the scheduler should watch // in NB to receive all NB-values described by this descriptor. // The key space defined by NBKeyPrefix may cover more than KeySelector // selects - the scheduler will filter the received values and pass // to the descriptor only those that are really chosen by KeySelector. // The opposite may be true as well - KeySelector may select some extra // SB-only values, which the scheduler will not watch for in NB. Furthermore, // the keys may already be requested for watching by another descriptor // within the same plugin and in such case it is not needed to mention the // same prefix again. NBKeyPrefix string // ValueComparator can be *optionally* provided to customize comparision // of values for equality. // Scheduler compares values to determine if Update operation is really // needed. // For NB values, <oldValue> was either previously set by NB or refreshed // from SB, whereas <newValue> is a new value to be applied by NB. ValueComparator func(key string, oldValue, newValue proto.Message) bool // WithMetadata tells scheduler whether to enable metadata - run-time, // descriptor-owned, scheduler-opaque, data carried alongside a created // (non-derived) value. // If enabled, the scheduler will maintain a map between key (-label, if // KeyLabel is defined) and the associated metadata. // If <WithMetadata> is false, metadata returned by Create will be ignored // and other methods will receive nil metadata. WithMetadata bool // MetadataMapFactory can be used to provide a customized map implementation // for value metadata, possibly extended with secondary lookups. // If not defined, the scheduler will use the bare NamedMapping from // the idxmap package. MetadataMapFactory MetadataMapFactory // Validate value handler (optional). // Validate is called for every new value before it is Created or Updated. // If the validations fails (returned <err> is non-nil), the scheduler will // mark the value as invalid and will not attempt to apply it. // The descriptor can further specify which field(s) are not valid // by wrapping the validation error together with a slice of invalid fields // using the error InvalidValueError (see errors.go). Validate func(key string, value proto.Message) error // Create new value handler. // For non-derived values, descriptor may return metadata to associate with // the value. // For derived values, Create+Delete+Update are optional. Typically, properties // of base values are implemented as derived (often empty) values without // attached SB operations, used as targets for dependencies. Create func(key string, value proto.Message) (metadata Metadata, err error) // Delete value handler. // If Create is defined, Delete handler must be provided as well. Delete func(key string, value proto.Message, metadata Metadata) error // Update value handler. // The handler is optional - if not defined, value change will be carried out // via full re-creation (Delete followed by Create with the new value). // <newMetadata> can re-use the <oldMetadata>. Update func(key string, oldValue, newValue proto.Message, oldMetadata Metadata) (newMetadata Metadata, err error) // UpdateWithRecreate can be defined to tell the scheduler if going from // <oldValue> to <newValue> requires the value to be completely re-created // with Delete+Create handlers. // If not defined, KVScheduler will decide based on the (un)availability // of the Update operation - if provided, it is assumed that any change // can be applied incrementally, otherwise a full re-creation is the only way // to go. UpdateWithRecreate func(key string, oldValue, newValue proto.Message, metadata Metadata) bool // Retrieve should return all non-derived values described by this descriptor // that *really* exist in the southbound plane (and not what the current // scheduler's view of SB is). Derived value will get automatically created // using the method DerivedValues(). If some non-derived value doesn't // actually exist, it shouldn't be returned by DerivedValues() for the // retrieved base value! // <correlate> represents the non-derived values currently created // as viewed from the northbound/scheduler point of view: // -> startup resync: <correlate> = values received from NB to be applied // -> run-time/downstream resync: <correlate> = values applied according // to the in-memory kv-store (scheduler's view of SB) // // The callback is optional - if not defined, it is assumed that descriptor // is not able to read the current SB state and thus refresh cannot be // performed for its kv-pairs. Retrieve func(correlate []KVWithMetadata) ([]KVWithMetadata, error) // IsRetriableFailure tells scheduler if the given error, returned by one // of Create/Delete/Update handlers, will always be returned for the // the same value (non-retriable) or if the value can be theoretically // fixed merely by repeating the operation. // If the callback is not defined, every error will be considered retriable. IsRetriableFailure func(err error) bool // DerivedValues returns ("derived") values solely inferred from the current // state of this ("base") value. Derived values cannot be changed by NB // transaction. // While their state and existence is bound to the state of their base value, // they are allowed to have their own descriptors. // // Typically, derived value represents the base value's properties (that // other kv pairs may depend on), or extra actions taken when additional // dependencies are met, but otherwise not blocking the base // value from being created. // // The callback is optional - if not defined, there will be no values derived // from kv-pairs of the descriptor. DerivedValues func(key string, value proto.Message) []KeyValuePair // Dependencies are keys that must already exist for the value to be created. // Conversely, if a dependency is to be removed, all values that depend on it // are deleted first and cached for a potential future re-creation. // Dependencies returned in the list are AND-ed. // The callback is optional - if not defined, the kv-pairs of the descriptor // are assumed to have no dependencies. Dependencies func(key string, value proto.Message) []Dependency // RetrieveDependencies is a list of descriptors whose values are needed // and should be already retrieved prior to calling Retrieve for this // descriptor. // Metadata for values already retrieved are available via GetMetadataMap(). // TODO: define dependencies as a slice of models, not descriptors. RetrieveDependencies []string /* descriptor name */ }
KVDescriptor teaches KVScheduler how to CRUD values under keys matched by KeySelector().
Every SB component should define one or more descriptors to cover all (non-property) keys under its management. The descriptor is what in essence gives meaning to individual key-value pairs. The list of available keys and their purpose should be properly documented so that clients from the NB plane can use them correctly. The scheduler does not care what CRUD methods do, it only needs to call the right callbacks at the right time.
Every key-value pair must have at most one descriptor associated with it. NB base value without descriptor is considered unimplemented and will never be created. On the other hand, derived value is allowed to have no descriptor associated with it. Typically, properties of base values are implemented as derived (often empty) values without attached SB operations, used as targets for dependencies.
type KVScheduler ¶
type KVScheduler interface { ValueProvider // RegisterKVDescriptor registers descriptor(s) for a set of selected // keys. It should be called in the Init phase of agent plugins. // Every key-value pair must have at most one descriptor associated with it // (none for derived values expressing properties). RegisterKVDescriptor(descriptor ...*KVDescriptor) error // GetRegisteredNBKeyPrefixes returns a list of key prefixes from NB with values // described by registered descriptors and therefore managed by the scheduler. GetRegisteredNBKeyPrefixes() []string // StartNBTransaction starts a new transaction from NB to SB plane. // The enqueued actions are scheduled for execution by Txn.Commit(). StartNBTransaction() Txn // TransactionBarrier ensures that all notifications received prior to the call // are associated with transactions that have already finalized. TransactionBarrier() // PushSBNotification notifies about a spontaneous value change in the SB // plane (i.e. not triggered by NB transaction). // // Pass <value> as nil if the value was removed, non-nil otherwise. // // Values pushed from SB do not trigger Create/Update/Delete operations // on the descriptors - the change has already happened in SB - only // dependencies and derived values are updated. // // Values pushed from SB are overwritten by those created via NB transactions, // however. For example, notifications for values already created by NB // are ignored. But otherwise, SB values (not managed by NB) are untouched // by reconciliation or any other operation of the scheduler/descriptor. // Note: Origin in KVWithMetadata is ignored and can be left unset // (automatically assumed to be FromSB). PushSBNotification(notif ...KVWithMetadata) error // GetMetadataMap returns (read-only) map associating value label with value // metadata of a given descriptor. // Returns nil if the descriptor does not expose metadata. GetMetadataMap(descriptor string) idxmap.NamedMapping // GetValueStatus returns the status of a non-derived value with the given // key. GetValueStatus(key string) *BaseValueStatus // WatchValueStatus allows to watch for changes in the status of non-derived // values with keys selected by the selector (all if keySelector==nil). WatchValueStatus(channel chan<- *BaseValueStatus, keySelector KeySelector) // GetTransactionHistory returns history of transactions started within // the specified time window, or the full recorded history if the timestamps // are zero values. GetTransactionHistory(since, until time.Time) (history RecordedTxns) // GetRecordedTransaction returns record of a transaction referenced // by the sequence number. GetRecordedTransaction(SeqNum uint64) (txn *RecordedTxn) }
KVScheduler synchronizes the *desired* system state described by northbound (NB) components via transactions with the *actual* state of the southbound (SB). The system state is represented as a set of inter-dependent key-value pairs that can be created, updated, deleted from within NB transactions or be notified about via notifications from the SB plane. The scheduling basically implements "state reconciliation" - periodically and on any change the scheduler attempts to update every value which has satisfied dependencies but is out-of-sync with the desired state given by NB.
For the scheduler, the key-value pairs are just abstract items that need to be managed in a synchronized fashion according to the described relations. It is up to the SB components to assign actual meaning to the individual values via provided implementations for CRUD operations.
The idea behind scheduler is based on the Mediator pattern - SB components do not communicate directly, but instead interact through the mediator. This reduces the dependencies between communicating objects, thereby reducing coupling.
The values are described for scheduler by registered KVDescriptor-s. The scheduler learns two kinds of relations between values that have to be respected by the scheduling algorithm:
-> A depends on B: - A cannot exist without B - request to create A without B existing must be postponed by storing A into the cache of values with unmet dependencies (a.k.a. pending) - if B is to be removed and A exists, A must be removed first and cached in case B is restored in the future - Note: values pushed from SB are not checked for dependencies -> B is derived from A: - value B is not created directly (by NB or SB) but gets derived from base value A (using the DerivedValues() method of the base value's descriptor) - derived value exists only as long as its base does and gets removed (without caching) once the base value goes away - derived value may be described by a different descriptor than the base and usually represents property of the base value (that other values may depend on) or an extra action to be taken when additional dependencies are met.
Every key-value pair must have at most one descriptor associated with it. Base NB value without descriptor is considered unimplemented and will never be created. On the other hand, derived value is allowed to have no descriptor associated with it. Typically, properties of base values are implemented as derived (often empty) values without attached SB operations, used as targets for dependencies.
For descriptors the values are mutable objects - Create, Update and Delete methods should reflect the value content without changing it. To add and maintain extra (runtime) attributes alongside the value, scheduler allows descriptors to append metadata - of any type - to each created non-derived Object value. Descriptor can also use the metadata to define secondary lookups, exposed via MetadataMap.
Advantages of the centralized scheduling are:
- easy to add new descriptors and dependencies
- decreases the likelihood of race conditions and deadlocks in systems with complex dependencies
- allows to write loosely-coupled SB components (mediator pattern)
- descriptor API will force new SB components to follow the same code structure which will make them easier to familiarize with
- NB components should never worry about dependencies between requests - it is taken care of by the scheduler
- single cache for all (not only pending) values (exposed via REST, easier to debug)
Apart from scheduling and execution, KVScheduler also offers the following features:
- collecting and counting present and past errors individually for every key
- retry for previously failed actions
- transaction reverting
- exposing history of actions, errors and past value revisions over the REST interface
- clearly describing the sequence of actions to be executed and postponed in the log file
- allows to print verbose log messages describing graph traversal during transactions for debugging purposes
- exposing graph snapshot, in the present state or after a given transaction, as a plotted graph (returned via REST) with values as nodes (colored to distinguish various value states) and dependencies/derivations as edges.
type KVWithMetadata ¶
type KVWithMetadata struct { Key string Value proto.Message Metadata Metadata Origin ValueOrigin }
KVWithMetadata encapsulates key-value pair with metadata and the origin mark.
type KeyValuePair ¶
type KeyValuePair struct { // Key identifies value. Key string // Value may represent some object, action or property. // // Value can be created either via northbound transaction (NB-value, // ValueOrigin = FromNB) or pushed (as already created) through SB notification // (SB-value, ValueOrigin = FromSB). Values from NB take priority as they // overwrite existing SB values (via Modify operation), whereas notifications // for existing NB values are ignored. For values retrieved with unknown // origin the scheduler reviews the value's history to determine where it came // from. // // For descriptors the values are mutable objects - Create, Update and Delete // methods should reflect the value content without changing it. // To add and maintain extra (runtime) attributes alongside the value, descriptor // can use the value metadata. Value proto.Message }
KeyValuePair groups key with value.
type KeyWithError ¶
type KeyWithError struct { Key string TxnOperation TxnOperation Error error }
KeyWithError stores error for a key whose value failed to get updated.
type Metadata ¶
type Metadata interface{}
Metadata are extra information carried alongside non-derived (base) value that descriptor may use for runtime attributes, secondary lookups, etc. This data are opaque for the scheduler and fully owned by the descriptor. Descriptor is supposed to create/edit (and use) metadata inside the Create, Update, Delete methods and return the latest state with Retrieve. Metadata, however, should not be used to determine the list of derived values and dependencies for a value - this needs to be fixed for a given value (Update is effectively replace) and known even before the value is created.
The only way how scheduler can learn anything from metadata, is if MetadataMap is enabled by descriptor (using WithMetadata method) and a custom NamedMapping implementation is provided that defines secondary indexes (over metadata). The scheduler exposes the current snapshot of secondary indexes, but otherwise is not familiar with their semantics.
type MetadataMapFactory ¶
type MetadataMapFactory func() idxmap.NamedMappingRW
MetadataMapFactory can be used by descriptor to define a custom map associating value labels with value metadata, potentially extending the basic in-memory implementation (memNamedMapping) with secondary indexes, type-safe watch, etc. If metadata are enabled (by WithMetadata method), the scheduler will create an instance of the map using the provided factory during the descriptor registration (RegisterKVDescriptor). Immediately afterwards, the mapping is available read-only via scheduler's method GetMetadataMap. The returned map can be then casted to the customized implementation, but it should remain read-only (i.e. define read-only interface for the customized implementation).
type RecordedKVPair ¶
type RecordedKVPair struct { Key string Value proto.Message Origin ValueOrigin }
RecordedKVPair is used to record key-value pair.
type RecordedTxn ¶
type RecordedTxn struct { PreRecord bool // not yet fully recorded, only args + plan + pre-processing errors WithSimulation bool // timestamps Start time.Time Stop time.Time // arguments SeqNum uint64 TxnType TxnType ResyncType ResyncType Description string RetryForTxn uint64 RetryAttempt int Values []RecordedKVPair // operations Planned RecordedTxnOps Executed RecordedTxnOps }
RecordedTxn is used to record executed transaction.
func (*RecordedTxn) String ¶
func (txn *RecordedTxn) String() string
String returns a *multi-line* human-readable string representation of recorded transaction.
func (*RecordedTxn) StringWithOpts ¶
func (txn *RecordedTxn) StringWithOpts(resultOnly, verbose bool, indent int) string
StringWithOpts allows to format string representation of recorded transaction.
type RecordedTxnOp ¶
type RecordedTxnOp struct { // identification Operation TxnOperation Key string // changes PrevValue proto.Message NewValue proto.Message PrevState ValueState NewState ValueState PrevErr error NewErr error NOOP bool // flags IsDerived bool IsProperty bool IsRevert bool IsRetry bool IsRecreate bool }
RecordedTxnOp is used to record executed/planned transaction operation.
func (*RecordedTxnOp) String ¶
func (op *RecordedTxnOp) String() string
String returns a *multi-line* human-readable string representation of a recorded transaction operation.
func (*RecordedTxnOp) StringWithOpts ¶
func (op *RecordedTxnOp) StringWithOpts(index int, verbose bool, indent int) string
StringWithOpts allows to format string representation of a transaction operation.
type RecordedTxnOps ¶
type RecordedTxnOps []*RecordedTxnOp
RecordedTxnOps is a list of recorded executed/planned transaction operations.
func (RecordedTxnOps) String ¶
func (ops RecordedTxnOps) String() string
String returns a *multi-line* human-readable string representation of transaction operations.
func (RecordedTxnOps) StringWithOpts ¶
func (ops RecordedTxnOps) StringWithOpts(verbose bool, indent int) string
StringWithOpts allows to format string representation of transaction operations.
type RecordedTxns ¶
type RecordedTxns []*RecordedTxn
RecordedTxns is a list of recorded transactions.
func (RecordedTxns) String ¶
func (txns RecordedTxns) String() string
String returns a *multi-line* human-readable string representation of a transaction list.
func (RecordedTxns) StringWithOpts ¶
func (txns RecordedTxns) StringWithOpts(resultOnly, verbose bool, indent int) string
StringWithOpts allows to format string representation of a transaction list.
type ResyncType ¶
type ResyncType int
ResyncType is one of: Upstream, Downstream, Full.
const ( // NotResync is the default value for ResyncType, used when resync is actually // not enabled. NotResync ResyncType = iota // FullResync resynchronizes the agent with both SB and NB. FullResync // UpstreamResync resynchronizes the agent with NB. // It can be used by NB in situations when fully re-calculating the desired // state is far easier or more efficient that to determine the minimal difference // that needs to be applied to reach that state. // The agent's view of SB is not refreshed, instead it is expected to be up-to-date. UpstreamResync // DownstreamResync resynchronizes the agent with SB. // In this case it is assumed that the state required by NB is up-to-date // (transaction should be empty) and only the agent's view of SB is refreshed // and any discrepancies are acted upon. DownstreamResync )
func IsResync ¶
func IsResync(ctx context.Context) (resyncType ResyncType, verboseSBRefresh bool)
IsResync returns true if the transaction context is configured to trigger resync.
func (ResyncType) String ¶
func (t ResyncType) String() string
type TransactionError ¶
type TransactionError struct {
// contains filtered or unexported fields
}
TransactionError implements Error interface, wrapping all errors encountered during the processing of a single transaction.
func NewTransactionError ¶
func NewTransactionError(txnInitError error, kvErrors []KeyWithError) *TransactionError
NewTransactionError is a constructor for transaction error.
func (*TransactionError) Error ¶
func (e *TransactionError) Error() string
Error returns a string representation of all errors encountered during the transaction processing.
func (*TransactionError) GetKVErrors ¶
func (e *TransactionError) GetKVErrors() (kvErrors []KeyWithError)
GetKVErrors returns errors for key-value pairs that failed to get applied.
func (*TransactionError) GetTxnInitError ¶
func (e *TransactionError) GetTxnInitError() error
GetTxnInitError returns error thrown during the transaction initialization. If the transaction initialization fails, the other stages of the transaction processing are not even started, therefore either GetTxnInitError or GetKVErrors may return some errors, but not both.
type Txn ¶
type Txn interface { // SetValue changes (non-derived) value. // If <value> is nil, the value will get deleted. SetValue(key string, value proto.Message) Txn // Commit orders scheduler to execute enqueued operations. // Operations with unmet dependencies will get postponed and possibly // executed later. // <ctx> allows to pass transaction options (see With* functions from // txn_options.go) or to cancel waiting for the end of a blocking transaction. // // For blocking transactions, the method returns the sequence number // of the (finalized) transaction or ^uint64(0) (max uint64) if the transaction // failed to even get initialized. In case of failures during the initialization // or transaction processing, the method will return non-nil error, which is // always an instance of TransactionError (see errors.go), wrapping all errors // encountered during the transaction processing. // // Non-blocking transactions return immediately and always without errors. // Subscribe with KVScheduler.WatchValueStatus() to get notified about all // changes/errors, including those related to actions triggered later // or asynchronously by a SB notification. Commit(ctx context.Context) (txnSeqNum uint64, err error) }
Txn represent a single transaction. Scheduler starts to plan and execute actions only after Commit is called.
type TxnOperation ¶
type TxnOperation int32
const ( TxnOperation_UNDEFINED TxnOperation = 0 TxnOperation_VALIDATE TxnOperation = 1 TxnOperation_CREATE TxnOperation = 2 TxnOperation_UPDATE TxnOperation = 3 TxnOperation_DELETE TxnOperation = 4 )
func (TxnOperation) EnumDescriptor ¶
func (TxnOperation) EnumDescriptor() ([]byte, []int)
func (TxnOperation) String ¶
func (x TxnOperation) String() string
type TxnType ¶
type TxnType int
TxnType differentiates between NB transaction, retry of failed operations and SB notification. Once queued, all three different operations are classified as transactions, only with different parameters.
type ValueOrigin ¶
type ValueOrigin int
ValueOrigin is one of: FromNB, FromSB, UnknownOrigin.
const ( // UnknownOrigin is given to a retrieved value when it cannot be determined // if the value was previously created by NB or not. // Scheduler will then look into its history to find out if the value was // ever managed by NB to determine the origin heuristically. UnknownOrigin ValueOrigin = iota // FromNB marks value created via NB transaction. FromNB // FromSB marks value not managed by NB - i.e. created automatically or // externally in SB. FromSB )
func (ValueOrigin) String ¶
func (vo ValueOrigin) String() string
String converts ValueOrigin to string.
type ValueProvider ¶
type ValueProvider interface { // DumpValuesByDescriptor dumps values associated with the given // descriptor as viewed from either NB (what was requested to be applied), // SB (what is actually applied) or from the inside (what kvscheduler's // cached view of SB is). DumpValuesByDescriptor(descriptor string, view View) (kvs []KVWithMetadata, err error) // DumpValuesByKeyPrefix like DumpValuesByDescriptor returns a dump of values, // but the descriptor is selected based on the key prefix. DumpValuesByKeyPrefix(keyPrefix string, view View) (kvs []KVWithMetadata, err error) }
ValueProvider provides key/value data from different sources in system (NB, SB, KVProvider cache of SB)
type ValueState ¶
type ValueState int32
const ( // ValueState_NONEXISTENT is assigned to value that was deleted or has never // existed. ValueState_NONEXISTENT ValueState = 0 // ValueState_MISSING is assigned to NB value that was configured but refresh // found it to be missing. ValueState_MISSING ValueState = 1 // ValueState_UNIMPLEMENTED marks value received from NB that cannot // be configured because there is no registered descriptor associated // with it. ValueState_UNIMPLEMENTED ValueState = 2 // ValueState_REMOVED is assigned to NB value after it was removed or when // it is being re-created. The state is only temporary: for re-create, the // value transits to whatever state the following Create operation produces, // and delete values are removed from the graph (go to the NONEXISTENT state) // immediately after the notification about the state change is sent. ValueState_REMOVED ValueState = 3 // ValueState_CONFIGURED marks value defined by NB and successfully configured. ValueState_CONFIGURED ValueState = 4 // ValueState_OBTAINED marks value not managed by NB, instead created // automatically or externally in SB. The KVScheduler learns about the value // either using Retrieve() or through a SB notification. ValueState_OBTAINED ValueState = 5 // ValueState_DISCOVERED marks NB value that was found (=retrieved) by refresh // but not actually configured by the agent in this run. ValueState_DISCOVERED ValueState = 6 // ValueState_PENDING represents (NB) value that cannot be configured yet // due to missing dependencies. ValueState_PENDING ValueState = 7 // ValueState_INVALID represents (NB) value that will not be configured // because it has a logically invalid content as declared by the Validate // method of the associated descriptor. // The corresponding error and the list of affected fields are stored // in the <InvalidValueDetails> structure available via <details> for invalid // value. ValueState_INVALID ValueState = 8 // ValueState_FAILED marks (NB) value for which the last executed operation // returned an error. // The error and the type of the operation which caused the error are stored // in the <FailedValueDetails> structure available via <details> for failed // value. ValueState_FAILED ValueState = 9 // ValueState_RETRYING marks unsucessfully applied (NB) value, for which, // however, one or more attempts to fix the error by repeating the last // operation are planned, and only if all the retries fail, the value will // then transit to the FAILED state. ValueState_RETRYING ValueState = 10 )
func (ValueState) EnumDescriptor ¶
func (ValueState) EnumDescriptor() ([]byte, []int)
func (ValueState) String ¶
func (x ValueState) String() string
type ValueStatus ¶
type ValueStatus struct { Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` State ValueState `protobuf:"varint,2,opt,name=state,proto3,enum=api.ValueState" json:"state,omitempty"` Error string `protobuf:"bytes,3,opt,name=error,proto3" json:"error,omitempty"` LastOperation TxnOperation `protobuf:"varint,4,opt,name=last_operation,json=lastOperation,proto3,enum=api.TxnOperation" json:"last_operation,omitempty"` // - for invalid value, details is a list of invalid fields // - for pending value, details is a list of missing dependencies (labels) Details []string `protobuf:"bytes,5,rep,name=details,proto3" json:"details,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` }
func (*ValueStatus) Descriptor ¶
func (*ValueStatus) Descriptor() ([]byte, []int)
func (*ValueStatus) GetDetails ¶
func (m *ValueStatus) GetDetails() []string
func (*ValueStatus) GetError ¶
func (m *ValueStatus) GetError() string
func (*ValueStatus) GetKey ¶
func (m *ValueStatus) GetKey() string
func (*ValueStatus) GetLastOperation ¶
func (m *ValueStatus) GetLastOperation() TxnOperation
func (*ValueStatus) GetState ¶
func (m *ValueStatus) GetState() ValueState
func (*ValueStatus) MarshalJSON ¶
func (m *ValueStatus) MarshalJSON() ([]byte, error)
MarshalJSON ensures data is correctly marshaled
func (*ValueStatus) ProtoMessage ¶
func (*ValueStatus) ProtoMessage()
func (*ValueStatus) Reset ¶
func (m *ValueStatus) Reset()
func (*ValueStatus) String ¶
func (m *ValueStatus) String() string
func (*ValueStatus) UnmarshalJSON ¶
func (m *ValueStatus) UnmarshalJSON(data []byte) error
UnmarshalJSON ensures that data is correctly unmarshaled
func (*ValueStatus) XXX_DiscardUnknown ¶
func (m *ValueStatus) XXX_DiscardUnknown()
func (*ValueStatus) XXX_Marshal ¶
func (m *ValueStatus) XXX_Marshal(b []byte, deterministic bool) ([]byte, error)
func (*ValueStatus) XXX_Merge ¶
func (dst *ValueStatus) XXX_Merge(src proto.Message)
func (*ValueStatus) XXX_Size ¶
func (m *ValueStatus) XXX_Size() int
func (*ValueStatus) XXX_Unmarshal ¶
func (m *ValueStatus) XXX_Unmarshal(b []byte) error
type VerificationError ¶
type VerificationError struct {
// contains filtered or unexported fields
}
VerificationError is returned by the scheduler for a transaction when an applied value does not match with the refreshed value.
func NewVerificationError ¶
func NewVerificationError(key string, errType VerificationErrorType) *VerificationError
NewVerificationError is constructor for a verification error.
func (*VerificationError) Error ¶
func (e *VerificationError) Error() string
Error returns a string representation of the error.
func (*VerificationError) Key ¶
func (e *VerificationError) Key() string
Key returns the key of the value for which the verification failed.
func (*VerificationError) Type ¶
func (e *VerificationError) Type() VerificationErrorType
Type returns the verification error type.
type VerificationErrorType ¶
type VerificationErrorType int
const ( // ExpectedToExist marks verification error returned when configured (non-nil) // value is not found by the refresh. ExpectedToExist VerificationErrorType = iota // ExpectedToNotExist marks verification error returned when removed (nil) // value is found by the refresh to still exist. ExpectedToNotExist // NotEquivalent marks verification error returned when applied value is not // equivalent with the refreshed value. NotEquivalent )
type View ¶
type View int
View chooses from which point of view to look at the key-value space when retrieving values.
const ( // SBView means to look directly into SB via Retrieve methods of descriptors // to learn the real and up-to-date state of the system. SBView View = iota // NBView means to look at the key-value space from NB point of view, i.e. // what key-values were requested and are assumed by NB to be applied. NBView // CachedView means to obtain the kvscheduler's current view of SB. CachedView )