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 }