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 }