github.com/cilium/cilium@v1.16.2/pkg/clustermesh/utils/clustercfg.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package utils
     5  
     6  import (
     7  	"context"
     8  	"encoding/json"
     9  	"errors"
    10  	"fmt"
    11  	"path"
    12  	"time"
    13  
    14  	"github.com/sirupsen/logrus"
    15  
    16  	cmtypes "github.com/cilium/cilium/pkg/clustermesh/types"
    17  	"github.com/cilium/cilium/pkg/controller"
    18  	"github.com/cilium/cilium/pkg/kvstore"
    19  )
    20  
    21  var (
    22  	// ErrClusterConfigNotFound is the sentinel error returned by
    23  	// GetClusterConfig if the cluster configuration is not found.
    24  	ErrClusterConfigNotFound = errors.New("not found")
    25  
    26  	// clusterConfigEnforcerGroup is the group for the controllers enforcing
    27  	clusterConfigEnforcerGroup = controller.NewGroup("clustermesh-cluster-config-enforcer")
    28  
    29  	// runInterval is the cluster configuration enforcement interval
    30  	runInterval = 5 * time.Minute
    31  )
    32  
    33  type ClusterConfigBackend interface {
    34  	Get(ctx context.Context, key string) ([]byte, error)
    35  	UpdateIfDifferent(ctx context.Context, key string, value []byte, lease bool) (bool, error)
    36  }
    37  
    38  func SetClusterConfig(ctx context.Context, clusterName string, config cmtypes.CiliumClusterConfig, backend ClusterConfigBackend) error {
    39  	key := path.Join(kvstore.ClusterConfigPrefix, clusterName)
    40  
    41  	val, err := json.Marshal(config)
    42  	if err != nil {
    43  		return err
    44  	}
    45  
    46  	ctx, cancel := context.WithTimeout(ctx, time.Minute)
    47  	defer cancel()
    48  
    49  	_, err = backend.UpdateIfDifferent(ctx, key, val, true)
    50  	if err != nil {
    51  		return err
    52  	}
    53  
    54  	return nil
    55  }
    56  
    57  // EnforceClusterConfig synchronously writes the cluster configuration, and
    58  // additionally registers a background task to periodically enforce its presence
    59  // (e.g., in case the associated lease unexpectedly expired).
    60  func EnforceClusterConfig(
    61  	ctx context.Context, clusterName string, config cmtypes.CiliumClusterConfig,
    62  	backend ClusterConfigBackend, log logrus.FieldLogger,
    63  ) (stopAndWait func(), err error) {
    64  	var (
    65  		mgr = controller.NewManager()
    66  		ch  = make(chan error, 1)
    67  	)
    68  
    69  	mgr.UpdateController(
    70  		fmt.Sprintf("clustermesh-cluster-config-enforcer-%s", clusterName),
    71  		controller.ControllerParams{
    72  			Context:     ctx,
    73  			Group:       clusterConfigEnforcerGroup,
    74  			RunInterval: runInterval,
    75  			DoFunc: func(ctx context.Context) error {
    76  				err := SetClusterConfig(ctx, clusterName, config, backend)
    77  				select {
    78  				case ch <- err:
    79  					if err != nil {
    80  						return controller.NewExitReason("initial enforcement failed")
    81  					}
    82  					return nil
    83  
    84  				default:
    85  					if err != nil {
    86  						log.WithError(err).Warning("Failed to write cluster configuration")
    87  					}
    88  
    89  					return err
    90  				}
    91  			},
    92  		},
    93  	)
    94  
    95  	// Wait to the initial synchronous enforcement, and then return.
    96  	err = <-ch
    97  	ch = nil
    98  
    99  	return mgr.RemoveAllAndWait, err
   100  }
   101  
   102  func GetClusterConfig(ctx context.Context, clusterName string, backend ClusterConfigBackend) (cmtypes.CiliumClusterConfig, error) {
   103  	var config cmtypes.CiliumClusterConfig
   104  
   105  	ctx, cancel := context.WithTimeout(ctx, time.Minute)
   106  	defer cancel()
   107  
   108  	val, err := backend.Get(ctx, path.Join(kvstore.ClusterConfigPrefix, clusterName))
   109  	if err != nil {
   110  		return cmtypes.CiliumClusterConfig{}, err
   111  	}
   112  
   113  	if val == nil {
   114  		return cmtypes.CiliumClusterConfig{}, ErrClusterConfigNotFound
   115  	}
   116  
   117  	if err := json.Unmarshal(val, &config); err != nil {
   118  		return cmtypes.CiliumClusterConfig{}, err
   119  	}
   120  
   121  	return config, nil
   122  }