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  }