github.com/cilium/cilium@v1.16.2/pkg/node/store/store.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package store 5 6 import ( 7 "context" 8 "fmt" 9 "path" 10 11 "github.com/cilium/cilium/pkg/defaults" 12 "github.com/cilium/cilium/pkg/kvstore" 13 "github.com/cilium/cilium/pkg/kvstore/store" 14 nodeTypes "github.com/cilium/cilium/pkg/node/types" 15 "github.com/cilium/cilium/pkg/option" 16 "github.com/cilium/cilium/pkg/source" 17 "github.com/cilium/cilium/pkg/time" 18 ) 19 20 var ( 21 // NodeStorePrefix is the kvstore prefix of the shared store 22 // 23 // WARNING - STABLE API: Changing the structure or values of this will 24 // break backwards compatibility 25 NodeStorePrefix = path.Join(kvstore.BaseKeyPrefix, "state", "nodes", "v1") 26 27 // KeyCreator creates a node for a shared store 28 KeyCreator = func() store.Key { 29 n := nodeTypes.Node{} 30 return &n 31 } 32 33 // NodeRegisterStorePrefix is the kvstore prefix of the shared 34 // store for node registration 35 // 36 // WARNING - STABLE API: Changing the structure or values of this will 37 // break backwards compatibility 38 NodeRegisterStorePrefix = path.Join(kvstore.BaseKeyPrefix, "state", "noderegister", "v1") 39 40 // RegisterKeyCreator creates a node for a shared store 41 RegisterKeyCreator = func() store.Key { 42 n := nodeTypes.RegisterNode{} 43 return &n 44 } 45 ) 46 47 // ValidatingNode wraps a Node to perform additional validation at unmarshal time. 48 type ValidatingNode struct { 49 nodeTypes.Node 50 51 validators []nodeValidator 52 } 53 54 type nodeValidator func(key string, n *nodeTypes.Node) error 55 56 func (vn *ValidatingNode) Unmarshal(key string, data []byte) error { 57 if err := vn.Node.Unmarshal(key, data); err != nil { 58 return err 59 } 60 61 for _, validator := range vn.validators { 62 if err := validator(key, &vn.Node); err != nil { 63 return err 64 } 65 } 66 67 return nil 68 } 69 70 // ClusterNameValidator returns a validator enforcing that the cluster field 71 // of the unmarshaled node matches the provided one. 72 func ClusterNameValidator(clusterName string) nodeValidator { 73 return func(_ string, n *nodeTypes.Node) error { 74 if n.Cluster != clusterName { 75 return fmt.Errorf("unexpected cluster name: got %s, expected %s", n.Cluster, clusterName) 76 } 77 return nil 78 } 79 } 80 81 // NameValidator returns a validator enforcing that the name of the the unmarshaled 82 // node matches the kvstore key. 83 func NameValidator() nodeValidator { 84 return func(key string, n *nodeTypes.Node) error { 85 if n.Name != key { 86 return fmt.Errorf("name does not match key: got %s, expected %s", n.Name, key) 87 } 88 return nil 89 } 90 } 91 92 // ClusterIDValidator returns a validator enforcing that the cluster ID of the 93 // unmarshaled node matches the provided one. The access to the provided 94 // clusterID value is not synchronized, and it shall not be mutated concurrently. 95 func ClusterIDValidator(clusterID *uint32) nodeValidator { 96 return func(_ string, n *nodeTypes.Node) error { 97 if n.ClusterID != *clusterID { 98 return fmt.Errorf("unexpected cluster ID: got %d, expected %d", n.ClusterID, *clusterID) 99 } 100 return nil 101 } 102 } 103 104 // ValidatingKeyCreator returns a store.KeyCreator for Nodes, configuring the 105 // specified extra validators. 106 func ValidatingKeyCreator(validators ...nodeValidator) store.KeyCreator { 107 return func() store.Key { 108 return &ValidatingNode{validators: validators} 109 } 110 } 111 112 // NodeObserver implements the store.Observer interface and delegates update 113 // and deletion events to the node object itself. 114 type NodeObserver struct { 115 manager NodeManager 116 source source.Source 117 } 118 119 // NewNodeObserver returns a new NodeObserver associated with the specified 120 // node manager 121 func NewNodeObserver(manager NodeManager, source source.Source) *NodeObserver { 122 return &NodeObserver{manager: manager, source: source} 123 } 124 125 func (o *NodeObserver) OnUpdate(k store.Key) { 126 if n, ok := k.(*ValidatingNode); ok && !n.IsLocal() { 127 nodeCopy := n.DeepCopy() 128 nodeCopy.Source = o.source 129 o.manager.NodeUpdated(*nodeCopy) 130 } 131 } 132 133 func (o *NodeObserver) OnDelete(k store.NamedKey) { 134 if n, ok := k.(*ValidatingNode); ok && !n.IsLocal() { 135 nodeCopy := n.DeepCopy() 136 nodeCopy.Source = o.source 137 o.manager.NodeDeleted(*nodeCopy) 138 } 139 } 140 141 // NodeManager is the interface that the manager of nodes has to implement 142 type NodeManager interface { 143 // NodeUpdated is called when the store detects a change in node 144 // information 145 NodeUpdated(n nodeTypes.Node) 146 147 // NodeDeleted is called when the store detects a deletion of a node 148 NodeDeleted(n nodeTypes.Node) 149 } 150 151 type NodeExtendedManager interface { 152 NodeManager 153 154 // NodeSync is called when the store completes the initial nodes listing 155 NodeSync() 156 } 157 158 // NodeRegistrar is a wrapper around store.SharedStore. 159 type NodeRegistrar struct { 160 *store.SharedStore 161 162 registerStore *store.SharedStore 163 } 164 165 // RegisterObserver implements the store.Observer interface and sends 166 // named node's identity updates on a channel. 167 type RegisterObserver struct { 168 name string 169 updates chan *nodeTypes.RegisterNode 170 } 171 172 // NewRegisterObserver returns a new RegisterObserver 173 func NewRegisterObserver(name string, updateChan chan *nodeTypes.RegisterNode) *RegisterObserver { 174 return &RegisterObserver{ 175 name: name, 176 updates: updateChan, 177 } 178 } 179 180 func (o *RegisterObserver) OnUpdate(k store.Key) { 181 if n, ok := k.(*nodeTypes.RegisterNode); ok { 182 log.Debugf("noderegister update on key %s while waiting for %s: %v", n.GetKeyName(), o.name, n) 183 if n.NodeIdentity != 0 && n.GetKeyName() == o.name { 184 select { 185 case o.updates <- n: 186 default: 187 // Register Node updateChan would block, not sending 188 } 189 } 190 } 191 } 192 193 func (o *RegisterObserver) OnDelete(k store.NamedKey) { 194 log.Debugf("noderegister key %s deleted while registering %s", k.GetKeyName(), o.name) 195 } 196 197 // JoinCluster registers the local node in the cluster. 198 // Blocks until timeout occurs or an updated Node is received from the kv-store and returns it. 199 // Otherwise this does not block and returns nil. 200 func (nr *NodeRegistrar) JoinCluster(name string) (*nodeTypes.Node, error) { 201 n := &nodeTypes.RegisterNode{ 202 Node: nodeTypes.Node{ 203 Name: name, 204 Source: source.Local, 205 }, 206 } 207 208 registerObserver := NewRegisterObserver(n.GetKeyName(), make(chan *nodeTypes.RegisterNode, 10)) 209 // Join the shared store for node registrations 210 registerStore, err := store.JoinSharedStore(store.Configuration{ 211 Prefix: NodeRegisterStorePrefix, 212 KeyCreator: RegisterKeyCreator, 213 SharedKeyDeleteDelay: defaults.NodeDeleteDelay, 214 Observer: registerObserver, 215 }) 216 if err != nil { 217 return nil, err 218 } 219 220 // Drain the channel of old updates first 221 for len(registerObserver.updates) > 0 { 222 dump := <-registerObserver.updates 223 log.Debugf("bypassing stale noderegister key: %s", dump.GetKeyName()) 224 } 225 226 log.Debugf("updating noderegister key %s with: %v", n.GetKeyName(), n) 227 err = registerStore.UpdateLocalKeySync(context.TODO(), n) 228 if err != nil { 229 registerStore.Release() 230 return nil, err 231 } 232 233 // Wait until an updated key is received from the kvstore 234 select { 235 case n = <-registerObserver.updates: 236 case <-time.After(defaults.NodeInitTimeout / 10): 237 registerStore.Release() 238 return nil, fmt.Errorf("timed out waiting for node identity") 239 } 240 241 nr.registerStore = registerStore 242 return &n.Node, nil 243 } 244 245 // RegisterNode registers the local node in the cluster. 246 func (nr *NodeRegistrar) RegisterNode(n *nodeTypes.Node, manager NodeExtendedManager) error { 247 if option.Config.KVStore == "" { 248 return nil 249 } 250 251 // Join the shared store holding node information of entire cluster 252 nodeStore, err := store.JoinSharedStore(store.Configuration{ 253 Prefix: NodeStorePrefix, 254 KeyCreator: ValidatingKeyCreator(), 255 SharedKeyDeleteDelay: defaults.NodeDeleteDelay, 256 Observer: NewNodeObserver(manager, source.KVStore), 257 }) 258 if err != nil { 259 return err 260 } 261 262 // Use nodeTypes.RegisterNode for updating local node info if not nil, but keep nodeStore for cluster node updates 263 if nr.registerStore != nil { 264 err = nr.registerStore.UpdateLocalKeySync(context.TODO(), &nodeTypes.RegisterNode{Node: *n}) 265 } else { 266 err = nodeStore.UpdateLocalKeySync(context.TODO(), n) 267 } 268 if err != nil { 269 nodeStore.Release() 270 return err 271 } 272 273 nr.SharedStore = nodeStore 274 275 manager.NodeSync() 276 277 return nil 278 } 279 280 // UpdateLocalKeySync synchronizes the local key for the node using the 281 // SharedStore. 282 func (nr *NodeRegistrar) UpdateLocalKeySync(n *nodeTypes.Node) error { 283 if nr.registerStore != nil { 284 return nr.registerStore.UpdateLocalKeySync(context.TODO(), &nodeTypes.RegisterNode{Node: *n}) 285 } 286 return nr.SharedStore.UpdateLocalKeySync(context.TODO(), n) 287 }