github.com/cilium/cilium@v1.16.2/pkg/kvstore/backend.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package kvstore
     5  
     6  import (
     7  	"context"
     8  
     9  	"google.golang.org/grpc"
    10  
    11  	"github.com/cilium/cilium/pkg/time"
    12  )
    13  
    14  type backendOption struct {
    15  	// description is the description of the option
    16  	description string
    17  
    18  	// value is the value the option has been configured to
    19  	value string
    20  
    21  	// validate, if set, is called to validate the value before assignment
    22  	validate func(value string) error
    23  }
    24  
    25  type backendOptions map[string]*backendOption
    26  
    27  type ClusterSizeDependantIntervalFunc func(baseInterval time.Duration) time.Duration
    28  
    29  // ExtraOptions represents any options that can not be represented in a textual
    30  // format and need to be set programmatically.
    31  type ExtraOptions struct {
    32  	DialOption []grpc.DialOption
    33  
    34  	// ClusterSizeDependantInterval defines the function to calculate
    35  	// intervals based on cluster size
    36  	ClusterSizeDependantInterval ClusterSizeDependantIntervalFunc
    37  
    38  	// NoLockQuorumCheck disables the lock acquisition quorum check
    39  	NoLockQuorumCheck bool
    40  
    41  	// ClusterName is the name of each etcd cluster
    42  	ClusterName string
    43  
    44  	// BootstrapComplete is an optional channel that can be provided to signal
    45  	// to the client that bootstrap is complete. If provided, the client will
    46  	// have an initial rate limit equal to etcd.bootstrapQps and be updated to
    47  	// etcd.qps after this channel is closed.
    48  	BootstrapComplete <-chan struct{}
    49  
    50  	// NoEndpointStatusChecks disables the status checks for the endpoints
    51  	NoEndpointStatusChecks bool
    52  }
    53  
    54  // StatusCheckInterval returns the interval of status checks depending on the
    55  // cluster size and the current connectivity state
    56  //
    57  // nodes      OK  Failing
    58  // 1         20s       3s
    59  // 4         45s       7s
    60  // 8       1m05s      11s
    61  // 32      1m45s      18s
    62  // 128     2m25s      24s
    63  // 512     3m07s      32s
    64  // 2048    3m46s      38s
    65  // 8192    4m30s      45s
    66  func (e *ExtraOptions) StatusCheckInterval(allConnected bool) time.Duration {
    67  	interval := 30 * time.Second
    68  
    69  	// Reduce the interval while connectivity issues are being detected
    70  	if !allConnected {
    71  		interval = 5 * time.Second
    72  	}
    73  
    74  	if e != nil && e.ClusterSizeDependantInterval != nil {
    75  		interval = e.ClusterSizeDependantInterval(interval)
    76  	}
    77  	return interval
    78  }
    79  
    80  // backendModule is the interface that each kvstore backend has to implement.
    81  type backendModule interface {
    82  	// getName must return the name of the backend
    83  	getName() string
    84  
    85  	// setConfig must configure the backend with the specified options.
    86  	// This function is called once before newClient().
    87  	setConfig(opts map[string]string) error
    88  
    89  	// setExtraConfig sets more options in the kvstore that are not able to
    90  	// be set by strings.
    91  	setExtraConfig(opts *ExtraOptions) error
    92  
    93  	// setConfigDummy must configure the backend with dummy configuration
    94  	// for testing purposes. This is a replacement for setConfig().
    95  	setConfigDummy()
    96  
    97  	// getConfig must return the backend configuration.
    98  	getConfig() map[string]string
    99  
   100  	// newClient must initializes the backend and create a new kvstore
   101  	// client which implements the BackendOperations interface
   102  	newClient(ctx context.Context, opts *ExtraOptions) (BackendOperations, chan error)
   103  
   104  	// createInstance creates a new instance of the module
   105  	createInstance() backendModule
   106  }
   107  
   108  var (
   109  	// registeredBackends is a slice of all backends that have registered
   110  	// itself via registerBackend()
   111  	registeredBackends = map[string]backendModule{}
   112  )
   113  
   114  // registerBackend must be called by kvstore backends to register themselves
   115  func registerBackend(name string, module backendModule) {
   116  	if _, ok := registeredBackends[name]; ok {
   117  		log.Panicf("backend with name '%s' already registered", name)
   118  	}
   119  
   120  	registeredBackends[name] = module
   121  }
   122  
   123  // getBackend finds a registered backend by name
   124  func getBackend(name string) backendModule {
   125  	if backend, ok := registeredBackends[name]; ok {
   126  		return backend.createInstance()
   127  	}
   128  
   129  	return nil
   130  }
   131  
   132  // BackendOperations are the individual kvstore operations that each backend
   133  // must implement. Direct use of this interface is possible but will bypass the
   134  // tracing layer.
   135  type BackendOperations interface {
   136  	// Connected returns a channel which is closed whenever the kvstore client
   137  	// is connected to the kvstore server.
   138  	Connected(ctx context.Context) <-chan error
   139  
   140  	// Disconnected returns a channel which is closed whenever the kvstore
   141  	// client is not connected to the kvstore server. (Only implemented for etcd)
   142  	Disconnected() <-chan struct{}
   143  
   144  	// Status returns the status of the kvstore client including an
   145  	// eventual error
   146  	Status() (string, error)
   147  
   148  	// StatusCheckErrors returns a channel which receives status check
   149  	// errors
   150  	StatusCheckErrors() <-chan error
   151  
   152  	// LockPath locks the provided path
   153  	LockPath(ctx context.Context, path string) (KVLocker, error)
   154  
   155  	// Get returns value of key
   156  	Get(ctx context.Context, key string) ([]byte, error)
   157  
   158  	// GetIfLocked returns value of key if the client is still holding the given lock.
   159  	GetIfLocked(ctx context.Context, key string, lock KVLocker) ([]byte, error)
   160  
   161  	// Delete deletes a key. It does not return an error if the key does not exist.
   162  	Delete(ctx context.Context, key string) error
   163  
   164  	// DeleteIfLocked deletes a key if the client is still holding the given lock. It does not return an error if the key does not exist.
   165  	DeleteIfLocked(ctx context.Context, key string, lock KVLocker) error
   166  
   167  	DeletePrefix(ctx context.Context, path string) error
   168  
   169  	// Update creates or updates a key.
   170  	Update(ctx context.Context, key string, value []byte, lease bool) error
   171  
   172  	// UpdateIfLocked updates a key if the client is still holding the given lock.
   173  	UpdateIfLocked(ctx context.Context, key string, value []byte, lease bool, lock KVLocker) error
   174  
   175  	// UpdateIfDifferent updates a key if the value is different
   176  	UpdateIfDifferent(ctx context.Context, key string, value []byte, lease bool) (bool, error)
   177  
   178  	// UpdateIfDifferentIfLocked updates a key if the value is different and if the client is still holding the given lock.
   179  	UpdateIfDifferentIfLocked(ctx context.Context, key string, value []byte, lease bool, lock KVLocker) (bool, error)
   180  
   181  	// CreateOnly atomically creates a key or fails if it already exists
   182  	CreateOnly(ctx context.Context, key string, value []byte, lease bool) (bool, error)
   183  
   184  	// CreateOnlyIfLocked atomically creates a key if the client is still holding the given lock or fails if it already exists
   185  	CreateOnlyIfLocked(ctx context.Context, key string, value []byte, lease bool, lock KVLocker) (bool, error)
   186  
   187  	// ListPrefix returns a list of keys matching the prefix
   188  	ListPrefix(ctx context.Context, prefix string) (KeyValuePairs, error)
   189  
   190  	// ListPrefixIfLocked returns a list of keys matching the prefix only if the client is still holding the given lock.
   191  	ListPrefixIfLocked(ctx context.Context, prefix string, lock KVLocker) (KeyValuePairs, error)
   192  
   193  	// Close closes the kvstore client
   194  	Close()
   195  
   196  	// Encodes a binary slice into a character set that the backend
   197  	// supports
   198  	Encode(in []byte) string
   199  
   200  	// Decodes a key previously encoded back into the original binary slice
   201  	Decode(in string) ([]byte, error)
   202  
   203  	// ListAndWatch creates a new watcher which will watch the specified
   204  	// prefix for changes. Before doing this, it will list the current keys
   205  	// matching the prefix and report them as new keys. The Events channel is
   206  	// created with the specified sizes. Upon every change observed, a
   207  	// KeyValueEvent will be sent to the Events channel
   208  	ListAndWatch(ctx context.Context, prefix string, chanSize int) *Watcher
   209  
   210  	// RegisterLeaseExpiredObserver registers a function which is executed when
   211  	// the lease associated with a key having the given prefix is detected as expired.
   212  	// If the function is nil, the previous observer (if any) is unregistered.
   213  	RegisterLeaseExpiredObserver(prefix string, fn func(key string))
   214  
   215  	BackendOperationsUserMgmt
   216  }
   217  
   218  // BackendOperationsUserMgmt are the kvstore operations for users management.
   219  type BackendOperationsUserMgmt interface {
   220  	// UserEnforcePresence creates a user in the kvstore if not already present, and grants the specified roles.
   221  	UserEnforcePresence(ctx context.Context, name string, roles []string) error
   222  
   223  	// UserEnforcePresence deletes a user from the kvstore, if present.
   224  	UserEnforceAbsence(ctx context.Context, name string) error
   225  }