diff --git a/cmd/controller/controller.go b/cmd/controller/controller.go index e7d9944c0219..59ca905e0e2e 100644 --- a/cmd/controller/controller.go +++ b/cmd/controller/controller.go @@ -455,16 +455,7 @@ func (c *command) start(ctx context.Context) error { if !slices.Contains(c.DisableComponents, constant.NetworkProviderComponentName) { logrus.Infof("Creating network reconcilers") - - calicoSaver, err := controller.NewManifestsSaver("calico", c.K0sVars.DataDir) - if err != nil { - return fmt.Errorf("failed to create calico manifests saver: %w", err) - } - calicoInitSaver, err := controller.NewManifestsSaver("calico_init", c.K0sVars.DataDir) - if err != nil { - return fmt.Errorf("failed to create calico_init manifests saver: %w", err) - } - clusterComponents.Add(ctx, controller.NewCalico(c.K0sVars, calicoInitSaver, calicoSaver)) + clusterComponents.Add(ctx, controller.NewCalico(c.K0sVars)) if !slices.Contains(c.DisableComponents, constant.WindowsNodeComponentName) { clusterComponents.Add(ctx, controller.NewWindowsStackComponent(c.K0sVars, adminClientFactory)) } diff --git a/pkg/component/controller/calico.go b/pkg/component/controller/calico.go index 159caa5bbc04..a7ab3f76d927 100644 --- a/pkg/component/controller/calico.go +++ b/pkg/component/controller/calico.go @@ -19,6 +19,7 @@ package controller import ( "bytes" "context" + "errors" "fmt" "io/fs" "path" @@ -36,6 +37,8 @@ import ( "github.com/sirupsen/logrus" + "github.com/k0sproject/k0s/internal/pkg/dir" + "github.com/k0sproject/k0s/internal/pkg/file" "github.com/k0sproject/k0s/internal/pkg/templatewriter" ) @@ -49,8 +52,6 @@ var calicoCRDOnce sync.Once type Calico struct { log logrus.FieldLogger - crdSaver manifestsSaver - saver manifestsSaver prevConfig calicoConfig k0sVars *config.CfgVars } @@ -88,24 +89,25 @@ type calicoConfig struct { } // NewCalico creates new Calico reconciler component -func NewCalico(k0sVars *config.CfgVars, crdSaver manifestsSaver, manifestsSaver manifestsSaver) *Calico { +func NewCalico(k0sVars *config.CfgVars) *Calico { return &Calico{ log: logrus.WithFields(logrus.Fields{"component": "calico"}), - crdSaver: crdSaver, - saver: manifestsSaver, prevConfig: calicoConfig{}, k0sVars: k0sVars, } } -// Init does nothing -func (c *Calico) Init(_ context.Context) error { - return nil +// Init implements [manager.Component]. +func (c *Calico) Init(context.Context) error { + return errors.Join( + dir.Init(filepath.Join(c.k0sVars.ManifestsDir, "calico_init"), constant.ManifestsDirMode), + dir.Init(filepath.Join(c.k0sVars.ManifestsDir, "calico"), constant.ManifestsDirMode), + ) } -// Run nothing really running, all logic based on reactive reconcile -func (c *Calico) Start(_ context.Context) error { +// Start implements [manager.Component]. +func (c *Calico) Start(context.Context) error { return nil } @@ -138,7 +140,9 @@ func (c *Calico) dumpCRDs() error { return fmt.Errorf("failed to write calico crd manifests %s: %w", manifestName, err) } - if err := c.crdSaver.Save(manifestName, output.Bytes()); err != nil { + if err := file.AtomicWithTarget(filepath.Join(c.k0sVars.ManifestsDir, "calico_init", manifestName)). + WithPermissions(constant.CertMode). + Write(output.Bytes()); err != nil { return fmt.Errorf("failed to save calico crd manifest %s: %w", manifestName, err) } } @@ -184,7 +188,9 @@ func (c *Calico) processConfigChanges(newConfig calicoConfig) error { Data: newConfig, } tryAndLog(manifestName, tw.WriteToBuffer(output)) - tryAndLog(manifestName, c.saver.Save(manifestName, output.Bytes())) + tryAndLog(manifestName, file.AtomicWithTarget(filepath.Join(c.k0sVars.ManifestsDir, "calico", manifestName)). + WithPermissions(constant.CertMode). + Write(output.Bytes())) } } @@ -227,7 +233,7 @@ func (c *Calico) getConfig(clusterConfig *v1beta1.ClusterConfig) (calicoConfig, return config, nil } -// Stop stops the calico reconciler +// Stop implements [manager.Component]. func (c *Calico) Stop() error { return nil } diff --git a/pkg/component/controller/calico_test.go b/pkg/component/controller/calico_test.go index 774c12e86a80..e295686bb0c0 100644 --- a/pkg/component/controller/calico_test.go +++ b/pkg/component/controller/calico_test.go @@ -17,11 +17,15 @@ limitations under the License. package controller import ( + "context" + "os" + "path/filepath" "testing" "github.com/k0sproject/k0s/pkg/apis/k0s/v1beta1" "github.com/k0sproject/k0s/pkg/config" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "sigs.k8s.io/yaml" ) @@ -34,37 +38,46 @@ func (i inMemorySaver) Save(dst string, content []byte) error { } func TestCalicoManifests(t *testing.T) { - k0sVars, err := config.NewCfgVars(nil, t.TempDir()) - require.NoError(t, err) + newTestInstance := func(t *testing.T) *Calico { + k0sVars, err := config.NewCfgVars(nil, t.TempDir()) + require.NoError(t, err) + calico := NewCalico(k0sVars) + require.NoError(t, calico.Init(context.TODO())) + require.NoError(t, calico.Start(context.TODO())) + t.Cleanup(func() { assert.NoError(t, calico.Stop()) }) + return calico + } + clusterConfig := v1beta1.DefaultClusterConfig() clusterConfig.Spec.Network.Calico = v1beta1.DefaultCalico() clusterConfig.Spec.Network.Provider = "calico" clusterConfig.Spec.Network.KubeRouter = nil t.Run("must_write_only_non_crd_on_change", func(t *testing.T) { - saver := inMemorySaver{} - crdSaver := inMemorySaver{} - calico := NewCalico(k0sVars, crdSaver, saver) + calico := newTestInstance(t) - _ = calico.processConfigChanges(calicoConfig{}) + assert.NoError(t, calico.processConfigChanges(calicoConfig{})) - for k := range saver { - require.NotContains(t, k, "calico-crd") + if entries, err := os.ReadDir(filepath.Join(calico.k0sVars.ManifestsDir, "calico")); assert.NoError(t, err) { + assert.NotEmpty(t, entries) + for _, entry := range entries { + assert.NotContains(t, entry.Name(), "calico-crd") + } + } + if entries, err := os.ReadDir(filepath.Join(calico.k0sVars.ManifestsDir, "calico_init")); assert.NoError(t, err) { + assert.Empty(t, entries) } - require.Len(t, crdSaver, 0) }) t.Run("must_have_wireguard_enabled_if_config_has", func(t *testing.T) { clusterConfig.Spec.Network.Calico.EnableWireguard = true - saver := inMemorySaver{} - crdSaver := inMemorySaver{} - calico := NewCalico(k0sVars, crdSaver, saver) + calico := newTestInstance(t) cfg, err := calico.getConfig(clusterConfig) require.NoError(t, err) require.NoError(t, calico.processConfigChanges(cfg)) - daemonSetManifestRaw, foundRaw := saver["calico-DaemonSet-calico-node.yaml"] - require.True(t, foundRaw, "must have daemon set for calico") + daemonSetManifestRaw, err := os.ReadFile(filepath.Join(calico.k0sVars.ManifestsDir, "calico", "calico-DaemonSet-calico-node.yaml")) + require.NoError(t, err, "must have daemon set for calico") spec := daemonSetContainersEnv{} require.NoError(t, yaml.Unmarshal(daemonSetManifestRaw, &spec)) spec.RequireContainerHasEnvVariable(t, "calico-node", "FELIX_WIREGUARDENABLED", "true") @@ -72,16 +85,14 @@ func TestCalicoManifests(t *testing.T) { t.Run("must_not_have_wireguard_enabled_if_config_has_no", func(t *testing.T) { clusterConfig.Spec.Network.Calico.EnableWireguard = false - saver := inMemorySaver{} - crdSaver := inMemorySaver{} - calico := NewCalico(k0sVars, crdSaver, saver) + calico := newTestInstance(t) cfg, err := calico.getConfig(clusterConfig) require.NoError(t, err) _ = calico.processConfigChanges(cfg) - daemonSetManifestRaw, foundRaw := saver["calico-DaemonSet-calico-node.yaml"] - require.True(t, foundRaw, "must have daemon set for calico") + daemonSetManifestRaw, err := os.ReadFile(filepath.Join(calico.k0sVars.ManifestsDir, "calico", "calico-DaemonSet-calico-node.yaml")) + require.NoError(t, err, "must have daemon set for calico") spec := daemonSetContainersEnv{} require.NoError(t, yaml.Unmarshal(daemonSetManifestRaw, &spec)) spec.RequireContainerHasNoEnvVariable(t, "calico-node", "FELIX_WIREGUARDENABLED") @@ -90,9 +101,7 @@ func TestCalicoManifests(t *testing.T) { t.Run("ip_autodetection", func(t *testing.T) { t.Run("use_IPAutodetectionMethod_for_both_families_by_default", func(t *testing.T) { clusterConfig.Spec.Network.Calico.IPAutodetectionMethod = "somemethod" - saver := inMemorySaver{} - crdSaver := inMemorySaver{} - calico := NewCalico(k0sVars, crdSaver, saver) + calico := newTestInstance(t) templateContext, err := calico.getConfig(clusterConfig) require.NoError(t, err) require.Equal(t, clusterConfig.Spec.Network.Calico.IPAutodetectionMethod, templateContext.IPAutodetectionMethod) @@ -100,8 +109,8 @@ func TestCalicoManifests(t *testing.T) { cfg, err := calico.getConfig(clusterConfig) require.NoError(t, err) _ = calico.processConfigChanges(cfg) - daemonSetManifestRaw, foundRaw := saver["calico-DaemonSet-calico-node.yaml"] - require.True(t, foundRaw, "must have daemon set for calico") + daemonSetManifestRaw, err := os.ReadFile(filepath.Join(calico.k0sVars.ManifestsDir, "calico", "calico-DaemonSet-calico-node.yaml")) + require.NoError(t, err, "must have daemon set for calico") spec := daemonSetContainersEnv{} require.NoError(t, yaml.Unmarshal(daemonSetManifestRaw, &spec)) @@ -111,9 +120,7 @@ func TestCalicoManifests(t *testing.T) { t.Run("use_IPV6AutodetectionMethod_for_ipv6_if_specified", func(t *testing.T) { clusterConfig.Spec.Network.Calico.IPAutodetectionMethod = "somemethod" clusterConfig.Spec.Network.Calico.IPv6AutodetectionMethod = "anothermethod" - saver := inMemorySaver{} - crdSaver := inMemorySaver{} - calico := NewCalico(k0sVars, crdSaver, saver) + calico := newTestInstance(t) templateContext, err := calico.getConfig(clusterConfig) require.NoError(t, err) require.Equal(t, clusterConfig.Spec.Network.Calico.IPAutodetectionMethod, templateContext.IPAutodetectionMethod) @@ -121,9 +128,9 @@ func TestCalicoManifests(t *testing.T) { cfg, err := calico.getConfig(clusterConfig) require.NoError(t, err) _ = calico.processConfigChanges(cfg) - daemonSetManifestRaw, foundRaw := saver["calico-DaemonSet-calico-node.yaml"] + daemonSetManifestRaw, err := os.ReadFile(filepath.Join(calico.k0sVars.ManifestsDir, "calico", "calico-DaemonSet-calico-node.yaml")) + require.NoError(t, err, "must have daemon set for calico") - require.True(t, foundRaw, "must have daemon set for calico") spec := daemonSetContainersEnv{} require.NoError(t, yaml.Unmarshal(daemonSetManifestRaw, &spec)) spec.RequireContainerHasEnvVariable(t, "calico-node", "IP6_AUTODETECTION_METHOD", templateContext.IPV6AutodetectionMethod)