api

package
v3.5.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 6, 2023 License: Apache-2.0 Imports: 10 Imported by: 24

Documentation

Index

Constants

This section is empty.

Variables

View Source
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")
)
View Source
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

Functions

func ErrInvalidMetadataType

func ErrInvalidMetadataType(key string) error

ErrInvalidMetadataType is returned to scheduler by auto-generated descriptor adapter when value metadata does not match expected type.

func ErrInvalidValueType

func ErrInvalidValueType(key string, value proto.Message) error

ErrInvalidValueType is returned to scheduler by auto-generated descriptor adapter when value does not match expected type.

func IsNonBlockingTxn

func IsNonBlockingTxn(ctx context.Context) bool

IsNonBlockingTxn returns true if transaction context is configured for non-blocking Commit.

func IsWithDescription

func IsWithDescription(ctx context.Context) (description string, withDescription bool)

IsWithDescription returns true if the transaction context is configured to include transaction description.

func IsWithRevert

func IsWithRevert(ctx context.Context) bool

IsWithRevert returns true if the transaction context is configured to revert transaction if any of its operations fails.

func IsWithSimulation

func IsWithSimulation(ctx context.Context) bool

IsWithSimulation returns true if transaction context is configured to enable pre-execution simulation.

func ResyncTypeToString added in v3.2.0

func ResyncTypeToString(t ResyncType) string

func TxnTypeToString added in v3.2.0

func TxnTypeToString(t TxnType) string

func WithDescription

func WithDescription(ctx context.Context, description string) context.Context

WithDescription prepares context for transaction that will have description provided. By default, transactions are without description.

func WithResync

func WithResync(ctx context.Context, resyncType ResyncType, verboseSBRefresh bool) context.Context

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

func WithRetryDefault(ctx context.Context) context.Context

WithRetryDefault is a specialization of WithRetry, where retry parameters are set to default values.

func WithRetryMaxCount

func WithRetryMaxCount(ctx context.Context, maxCount int) context.Context

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

func WithRevert(ctx context.Context) context.Context

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

func WithSimulation(ctx context.Context) context.Context

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.

func WithoutBlocking

func WithoutBlocking(ctx context.Context) context.Context

WithoutBlocking prepares context for transaction that should be scheduled for execution without blocking the caller of the Commit() method. By default, commit is blocking.

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 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 InvalidMessageError added in v3.3.0

type InvalidMessageError struct {
	// contains filtered or unexported fields
}

InvalidMessageError is message validation error that links proto message with its corresponding InvalidValueError returned from running KVDescriptor.Validate on the given proto message

func NewInvalidMessageError added in v3.3.0

func NewInvalidMessageError(message proto.Message, invalidError *InvalidValueError,
	parentMessage proto.Message) *InvalidMessageError

NewInvalidMessageError is constructor for InvalidMessageError

func (*InvalidMessageError) Error added in v3.3.0

func (e *InvalidMessageError) Error() string

Error returns string representation of the pair (proto message, its InvalidValueError)

func (*InvalidMessageError) InvalidFields added in v3.3.0

func (e *InvalidMessageError) InvalidFields() []string

InvalidFields return fields to which the InvalidValueError is referring

func (*InvalidMessageError) Message added in v3.3.0

func (e *InvalidMessageError) Message() proto.Message

Message returns proto message to which the InvalidValueError is linked

func (*InvalidMessageError) ParentMessage added in v3.3.0

func (e *InvalidMessageError) ParentMessage() proto.Message

ParentMessage returns parent proto message to message which the InvalidValueError is linked to. The parent proto message is non-nill only when the KVDescriptor.DerivedValues was used to create message (InvalidMessageError.Message()), otherwise it is nil

func (*InvalidMessageError) ValidationError added in v3.3.0

func (e *InvalidMessageError) ValidationError() error

ValidationError return error message of linked InvalidValueError

type InvalidMessagesError added in v3.3.0

type InvalidMessagesError struct {
	// contains filtered or unexported fields
}

InvalidMessagesError is container for multiple InvalidMessageError instances

func NewInvalidMessagesError added in v3.3.0

func NewInvalidMessagesError(messageErrors []*InvalidMessageError) *InvalidMessagesError

NewInvalidMessagesError is constructor for new InvalidMessagesError instances

func (*InvalidMessagesError) Error added in v3.3.0

func (e *InvalidMessagesError) Error() string

Error returns string representation of all contained InvalidMessageError instances

func (*InvalidMessagesError) MessageErrors added in v3.3.0

func (e *InvalidMessagesError) MessageErrors() []*InvalidMessageError

MessageErrors returns all InvalidMessageError instances

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) *kvscheduler.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<- *kvscheduler.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)

	// ValidateSemantically validates given proto messages according to semantic validation(KVDescriptor.Validate)
	// from registered KVDescriptors. If all locally known messages are valid, nil is returned. If some locally known
	// messages are invalid, kvscheduler.MessageValidationErrors is returned. In any other case, error is returned.
	//
	// Usage of dynamic proto messages (dynamicpb.Message) described by remotely known models is not supported.
	// The reason for this is that the KVDescriptors can validate only statically generated proto messages and
	// remotely retrieved dynamic proto messages can't be converted to such proto messages (there are
	// no locally available statically generated proto models).
	ValidateSemantically([]proto.Message) error
}

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 KeySelector

type KeySelector func(key string) bool

KeySelector is used to filter keys.

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 kvscheduler.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  *utils.RecordedProtoMessage
	Origin ValueOrigin
}

RecordedKVPair is used to record key-value pair.

type RecordedKVWithMetadata added in v3.5.0

type RecordedKVWithMetadata struct {
	RecordedKVPair
	Metadata Metadata
}

RecordedKVWithMetadata is the same as KVWithMetadata but with the field Value of type utils.RecordedProtoMessage instead of proto.Message. This allows for proper JSON marshalling and unmarshalling. Values of this type are used in KVScheduler's REST API.

type RecordedTxn

type RecordedTxn struct {
	PreRecord      bool `json:",omitempty"` // not yet fully recorded, only args + plan + pre-processing errors
	WithSimulation bool `json:",omitempty"`

	// timestamps
	Start time.Time
	Stop  time.Time

	// arguments
	SeqNum       uint64
	TxnType      TxnType
	ResyncType   ResyncType       `json:",omitempty"`
	Description  string           `json:",omitempty"`
	RetryForTxn  uint64           `json:",omitempty"`
	RetryAttempt int              `json:",omitempty"`
	Values       []RecordedKVPair `json:",omitempty"`

	// operations
	Planned  RecordedTxnOps `json:",omitempty"`
	Executed RecordedTxnOps `json:",omitempty"`
}

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 kvscheduler.TxnOperation
	Key       string

	// changes
	NewState   kvscheduler.ValueState      `json:",omitempty"`
	NewValue   *utils.RecordedProtoMessage `json:",omitempty"`
	NewErr     error                       `json:"-"`
	NewErrMsg  string                      `json:",omitempty"`
	PrevState  kvscheduler.ValueState      `json:",omitempty"`
	PrevValue  *utils.RecordedProtoMessage `json:",omitempty"`
	PrevErr    error                       `json:"-"`
	PrevErrMsg string                      `json:",omitempty"`
	NOOP       bool                        `json:",omitempty"`

	// flags
	IsDerived  bool `json:",omitempty"`
	IsProperty bool `json:",omitempty"`
	IsRevert   bool `json:",omitempty"`
	IsRetry    bool `json:",omitempty"`
	IsRecreate bool `json:",omitempty"`
}

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) MarshalJSON added in v3.2.0

func (t ResyncType) MarshalJSON() ([]byte, error)

func (ResyncType) String

func (t ResyncType) String() string

func (*ResyncType) UnmarshalJSON added in v3.2.0

func (t *ResyncType) UnmarshalJSON(b []byte) error

type RetryOpt

type RetryOpt struct {
	Period     time.Duration
	MaxCount   int
	ExpBackoff bool
}

RetryOpt represents the *retry* transaction option.

func IsWithRetry

func IsWithRetry(ctx context.Context) (retryArgs *RetryOpt, withRetry bool)

IsWithRetry returns true if transaction context is configured to allow retry, including the option parameters, or nil if retry is not enabled.

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 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.

const (
	// SBNotification is notification from southbound.
	SBNotification TxnType = iota

	// NBTransaction is transaction from northbound.
	NBTransaction

	// RetryFailedOps is a transaction re-trying failed operations from previous
	// northbound transaction.
	RetryFailedOps
)

func (TxnType) MarshalJSON added in v3.2.0

func (t TxnType) MarshalJSON() ([]byte, error)

func (TxnType) String

func (t TxnType) String() string

String returns human-readable string representation of the transaction type.

func (*TxnType) UnmarshalJSON added in v3.2.0

func (t *TxnType) UnmarshalJSON(b []byte) error

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 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

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
)

func (View) String

func (v View) String() string

String converts View to string.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL