api

package
v2.0.2+incompatible Latest Latest
Warning

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

Go to latest
Published: Apr 19, 2019 License: Apache-2.0 Imports: 11 Imported by: 0

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

View Source
var TxnOperation_name = map[int32]string{
	0: "UNDEFINED",
	1: "VALIDATE",
	2: "CREATE",
	3: "UPDATE",
	4: "DELETE",
}
View Source
var TxnOperation_value = map[string]int32{
	"UNDEFINED": 0,
	"VALIDATE":  1,
	"CREATE":    2,
	"UPDATE":    3,
	"DELETE":    4,
}
View Source
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",
}
View Source
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

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 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 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 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.
	PushSBNotification(key string, value proto.Message, metadata Metadata) 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 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 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 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 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.

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

func (t TxnType) String() string

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

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

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