From 7a6b7b69242c1ba1e20dc0be9e9e390c60e760ce Mon Sep 17 00:00:00 2001 From: Alexey Makhov Date: Fri, 15 Nov 2024 10:17:08 +0200 Subject: [PATCH] Strip default images from the config Signed-off-by: Alexey Makhov --- pkg/apis/k0s/v1beta1/clusterconfig_types.go | 35 ++++++++ .../k0s/v1beta1/clusterconfig_types_test.go | 10 +-- pkg/apis/k0s/v1beta1/images.go | 72 ++++++++--------- pkg/apis/k0s/v1beta1/images_test.go | 24 ++++++ pkg/apis/k0s/v1beta1/zz_generated.deepcopy.go | 80 +++++++++++++++---- 5 files changed, 166 insertions(+), 55 deletions(-) diff --git a/pkg/apis/k0s/v1beta1/clusterconfig_types.go b/pkg/apis/k0s/v1beta1/clusterconfig_types.go index 902930c5d1b2..b9d411a42a43 100644 --- a/pkg/apis/k0s/v1beta1/clusterconfig_types.go +++ b/pkg/apis/k0s/v1beta1/clusterconfig_types.go @@ -91,12 +91,20 @@ func (c *ClusterConfig) StripDefaults() *ClusterConfig { } if reflect.DeepEqual(copy.Spec.Network, DefaultNetwork()) { copy.Spec.Network = nil + } else { + if copy.Spec.Network.NodeLocalLoadBalancing != nil && + copy.Spec.Network.NodeLocalLoadBalancing.EnvoyProxy != nil && + reflect.DeepEqual(copy.Spec.Network.NodeLocalLoadBalancing.EnvoyProxy.Image, DefaultEnvoyProxyImage()) { + copy.Spec.Network.NodeLocalLoadBalancing.EnvoyProxy.Image = nil + } } if reflect.DeepEqual(copy.Spec.Telemetry, DefaultClusterTelemetry()) { copy.Spec.Telemetry = nil } if reflect.DeepEqual(copy.Spec.Images, DefaultClusterImages()) { copy.Spec.Images = nil + } else { + stripDefaultImages(copy.Spec.Images, DefaultClusterImages()) } if reflect.DeepEqual(copy.Spec.Konnectivity, DefaultKonnectivitySpec()) { copy.Spec.Konnectivity = nil @@ -104,6 +112,33 @@ func (c *ClusterConfig) StripDefaults() *ClusterConfig { return copy } +func stripDefaultImages(cfgImages, defaultImages *ClusterImages) { + cfgVal := reflect.ValueOf(cfgImages).Elem() + defaultVal := reflect.ValueOf(defaultImages).Elem() + stripDefaults(cfgVal, defaultVal) +} + +func stripDefaults(cfgVal, defaultVal reflect.Value) { + for i := range cfgVal.NumField() { + f1 := cfgVal.Field(i) + f2 := defaultVal.Field(i) + switch f1.Kind() { + case reflect.Pointer: + if f1.Elem().Equal(f2.Elem()) { + f1.Set(reflect.Zero(f1.Type())) + } else { + stripDefaults(f1.Elem(), f2.Elem()) + } + case reflect.Struct: + stripDefaults(f1, f2) + default: + if f1.Equal(f2) { + f1.Set(reflect.Zero(f1.Type())) + } + } + } +} + // InstallSpec defines the required fields for the `k0s install` command type InstallSpec struct { SystemUsers *SystemUser `json:"users,omitempty"` diff --git a/pkg/apis/k0s/v1beta1/clusterconfig_types_test.go b/pkg/apis/k0s/v1beta1/clusterconfig_types_test.go index 140244dbaced..a2ea790c690b 100644 --- a/pkg/apis/k0s/v1beta1/clusterconfig_types_test.go +++ b/pkg/apis/k0s/v1beta1/clusterconfig_types_test.go @@ -81,11 +81,11 @@ func TestClusterSpecCustomImages(t *testing.T) { }, } validTestCase.Spec.Images.DefaultPullPolicy = string(corev1.PullIfNotPresent) - validTestCase.Spec.Images.Konnectivity = ImageSpec{ + validTestCase.Spec.Images.Konnectivity = &ImageSpec{ Image: "foo", Version: "v1", } - validTestCase.Spec.Images.PushGateway = ImageSpec{ + validTestCase.Spec.Images.PushGateway = &ImageSpec{ Image: "bar", Version: "v2@sha256:0000000000000000000000000000000000000000000000000000000000000000", } @@ -98,17 +98,17 @@ func TestClusterSpecCustomImages(t *testing.T) { Images: DefaultClusterImages(), }, } - invalidTestCase.Spec.Images.MetricsServer = ImageSpec{ + invalidTestCase.Spec.Images.MetricsServer = &ImageSpec{ Image: "baz", // digest only is currently not supported Version: "sha256:0000000000000000000000000000000000000000000000000000000000000000", } - invalidTestCase.Spec.Images.Calico.CNI = ImageSpec{ + invalidTestCase.Spec.Images.Calico.CNI = &ImageSpec{ Image: "qux", // digest only is currently not supported Version: "sha256:0000000000000000000000000000000000000000000000000000000000000000", } - invalidTestCase.Spec.Images.KubeRouter.CNI = ImageSpec{ + invalidTestCase.Spec.Images.KubeRouter.CNI = &ImageSpec{ Image: "quux", // digest only is currently not supported Version: "sha256:0000000000000000000000000000000000000000000000000000000000000000", diff --git a/pkg/apis/k0s/v1beta1/images.go b/pkg/apis/k0s/v1beta1/images.go index 4a9afa553139..9afaca93f3cf 100644 --- a/pkg/apis/k0s/v1beta1/images.go +++ b/pkg/apis/k0s/v1beta1/images.go @@ -67,15 +67,15 @@ func (s *ImageSpec) URI() string { // ClusterImages sets docker images for addon components type ClusterImages struct { - Konnectivity ImageSpec `json:"konnectivity,omitempty"` - PushGateway ImageSpec `json:"pushgateway,omitempty"` - MetricsServer ImageSpec `json:"metricsserver,omitempty"` - KubeProxy ImageSpec `json:"kubeproxy,omitempty"` - CoreDNS ImageSpec `json:"coredns,omitempty"` - Pause ImageSpec `json:"pause,omitempty"` + Konnectivity *ImageSpec `json:"konnectivity,omitempty"` + PushGateway *ImageSpec `json:"pushgateway,omitempty"` + MetricsServer *ImageSpec `json:"metricsserver,omitempty"` + KubeProxy *ImageSpec `json:"kubeproxy,omitempty"` + CoreDNS *ImageSpec `json:"coredns,omitempty"` + Pause *ImageSpec `json:"pause,omitempty"` - Calico CalicoImageSpec `json:"calico,omitempty"` - KubeRouter KubeRouterImageSpec `json:"kuberouter,omitempty"` + Calico *CalicoImageSpec `json:"calico,omitempty"` + KubeRouter *KubeRouterImageSpec `json:"kuberouter,omitempty"` Repository string `json:"repository,omitempty"` @@ -134,23 +134,23 @@ func (ci *ClusterImages) overrideImageRepositories() { override := func(dst *ImageSpec) { dst.Image = overrideRepository(ci.Repository, dst.Image) } - override(&ci.Konnectivity) - override(&ci.MetricsServer) - override(&ci.KubeProxy) - override(&ci.CoreDNS) - override(&ci.Calico.CNI) - override(&ci.Calico.Node) - override(&ci.Calico.KubeControllers) - override(&ci.KubeRouter.CNI) - override(&ci.KubeRouter.CNIInstaller) - override(&ci.Pause) + override(ci.Konnectivity) + override(ci.MetricsServer) + override(ci.KubeProxy) + override(ci.CoreDNS) + override(ci.Calico.CNI) + override(ci.Calico.Node) + override(ci.Calico.KubeControllers) + override(ci.KubeRouter.CNI) + override(ci.KubeRouter.CNIInstaller) + override(ci.Pause) } // CalicoImageSpec config group for calico related image settings type CalicoImageSpec struct { - CNI ImageSpec `json:"cni,omitempty"` - Node ImageSpec `json:"node,omitempty"` - KubeControllers ImageSpec `json:"kubecontrollers,omitempty"` + CNI *ImageSpec `json:"cni,omitempty"` + Node *ImageSpec `json:"node,omitempty"` + KubeControllers *ImageSpec `json:"kubecontrollers,omitempty"` } func (s *CalicoImageSpec) Validate(path *field.Path) (errs field.ErrorList) { @@ -165,8 +165,8 @@ func (s *CalicoImageSpec) Validate(path *field.Path) (errs field.ErrorList) { // KubeRouterImageSpec config group for kube-router related images type KubeRouterImageSpec struct { - CNI ImageSpec `json:"cni,omitempty"` - CNIInstaller ImageSpec `json:"cniInstaller,omitempty"` + CNI *ImageSpec `json:"cni,omitempty"` + CNIInstaller *ImageSpec `json:"cniInstaller,omitempty"` } func (s *KubeRouterImageSpec) Validate(path *field.Path) (errs field.ErrorList) { @@ -182,51 +182,51 @@ func (s *KubeRouterImageSpec) Validate(path *field.Path) (errs field.ErrorList) func DefaultClusterImages() *ClusterImages { return &ClusterImages{ DefaultPullPolicy: "IfNotPresent", - Konnectivity: ImageSpec{ + Konnectivity: &ImageSpec{ Image: constant.KonnectivityImage, Version: constant.KonnectivityImageVersion, }, - PushGateway: ImageSpec{ + PushGateway: &ImageSpec{ Image: constant.PushGatewayImage, Version: constant.PushGatewayImageVersion, }, - MetricsServer: ImageSpec{ + MetricsServer: &ImageSpec{ Image: constant.MetricsImage, Version: constant.MetricsImageVersion, }, - KubeProxy: ImageSpec{ + KubeProxy: &ImageSpec{ Image: constant.KubeProxyImage, Version: constant.KubeProxyImageVersion, }, - CoreDNS: ImageSpec{ + CoreDNS: &ImageSpec{ Image: constant.CoreDNSImage, Version: constant.CoreDNSImageVersion, }, - Calico: CalicoImageSpec{ - CNI: ImageSpec{ + Calico: &CalicoImageSpec{ + CNI: &ImageSpec{ Image: constant.CalicoImage, Version: constant.CalicoComponentImagesVersion, }, - Node: ImageSpec{ + Node: &ImageSpec{ Image: constant.CalicoNodeImage, Version: constant.CalicoComponentImagesVersion, }, - KubeControllers: ImageSpec{ + KubeControllers: &ImageSpec{ Image: constant.KubeControllerImage, Version: constant.CalicoComponentImagesVersion, }, }, - KubeRouter: KubeRouterImageSpec{ - CNI: ImageSpec{ + KubeRouter: &KubeRouterImageSpec{ + CNI: &ImageSpec{ Image: constant.KubeRouterCNIImage, Version: constant.KubeRouterCNIImageVersion, }, - CNIInstaller: ImageSpec{ + CNIInstaller: &ImageSpec{ Image: constant.KubeRouterCNIInstallerImage, Version: constant.KubeRouterCNIInstallerImageVersion, }, }, - Pause: ImageSpec{ + Pause: &ImageSpec{ Image: constant.KubePauseContainerImage, Version: constant.KubePauseContainerImageVersion, }, diff --git a/pkg/apis/k0s/v1beta1/images_test.go b/pkg/apis/k0s/v1beta1/images_test.go index 3fbbb6acca25..50e93b3f9185 100644 --- a/pkg/apis/k0s/v1beta1/images_test.go +++ b/pkg/apis/k0s/v1beta1/images_test.go @@ -56,6 +56,30 @@ spec: assert.Equal(t, "registry.k8s.io/metrics-server/metrics-server", a.MetricsServer.Image) } +func TestStripDefaultsForDefaultImageList(t *testing.T) { + yamlData := ` +apiVersion: k0s.k0sproject.io/v1beta1s +kind: ClusterConfig +spec: + images: + default_pull_policy: Never + network: + nodeLocalLoadBalancing: + enabled: true + type: EnvoyProxy +` + + cfg, err := ConfigFromString(yamlData) + require.NoError(t, err) + + strippedCfg := cfg.StripDefaults() + + require.Equal(t, "Never", strippedCfg.Spec.Images.DefaultPullPolicy) + require.Nil(t, strippedCfg.Spec.Images.Konnectivity) + require.True(t, strippedCfg.Spec.Network.NodeLocalLoadBalancing.Enabled) + require.Nil(t, strippedCfg.Spec.Network.NodeLocalLoadBalancing.EnvoyProxy.Image) +} + func TestImagesRepoOverrideInConfiguration(t *testing.T) { t.Run("if_has_repository_not_empty_add_prefix_to_all_images", func(t *testing.T) { t.Run("default_config", func(t *testing.T) { diff --git a/pkg/apis/k0s/v1beta1/zz_generated.deepcopy.go b/pkg/apis/k0s/v1beta1/zz_generated.deepcopy.go index 2542567c5299..0c45c14c44fc 100644 --- a/pkg/apis/k0s/v1beta1/zz_generated.deepcopy.go +++ b/pkg/apis/k0s/v1beta1/zz_generated.deepcopy.go @@ -126,9 +126,21 @@ func (in *Calico) DeepCopy() *Calico { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CalicoImageSpec) DeepCopyInto(out *CalicoImageSpec) { *out = *in - out.CNI = in.CNI - out.Node = in.Node - out.KubeControllers = in.KubeControllers + if in.CNI != nil { + in, out := &in.CNI, &out.CNI + *out = new(ImageSpec) + **out = **in + } + if in.Node != nil { + in, out := &in.Node, &out.Node + *out = new(ImageSpec) + **out = **in + } + if in.KubeControllers != nil { + in, out := &in.KubeControllers, &out.KubeControllers + *out = new(ImageSpec) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CalicoImageSpec. @@ -293,14 +305,46 @@ func (in *ClusterExtensions) DeepCopy() *ClusterExtensions { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ClusterImages) DeepCopyInto(out *ClusterImages) { *out = *in - out.Konnectivity = in.Konnectivity - out.PushGateway = in.PushGateway - out.MetricsServer = in.MetricsServer - out.KubeProxy = in.KubeProxy - out.CoreDNS = in.CoreDNS - out.Pause = in.Pause - out.Calico = in.Calico - out.KubeRouter = in.KubeRouter + if in.Konnectivity != nil { + in, out := &in.Konnectivity, &out.Konnectivity + *out = new(ImageSpec) + **out = **in + } + if in.PushGateway != nil { + in, out := &in.PushGateway, &out.PushGateway + *out = new(ImageSpec) + **out = **in + } + if in.MetricsServer != nil { + in, out := &in.MetricsServer, &out.MetricsServer + *out = new(ImageSpec) + **out = **in + } + if in.KubeProxy != nil { + in, out := &in.KubeProxy, &out.KubeProxy + *out = new(ImageSpec) + **out = **in + } + if in.CoreDNS != nil { + in, out := &in.CoreDNS, &out.CoreDNS + *out = new(ImageSpec) + **out = **in + } + if in.Pause != nil { + in, out := &in.Pause, &out.Pause + *out = new(ImageSpec) + **out = **in + } + if in.Calico != nil { + in, out := &in.Calico, &out.Calico + *out = new(CalicoImageSpec) + (*in).DeepCopyInto(*out) + } + if in.KubeRouter != nil { + in, out := &in.KubeRouter, &out.KubeRouter + *out = new(KubeRouterImageSpec) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterImages. @@ -361,7 +405,7 @@ func (in *ClusterSpec) DeepCopyInto(out *ClusterSpec) { if in.Images != nil { in, out := &in.Images, &out.Images *out = new(ClusterImages) - **out = **in + (*in).DeepCopyInto(*out) } if in.Extensions != nil { in, out := &in.Extensions, &out.Extensions @@ -873,8 +917,16 @@ func (in *KubeRouter) DeepCopy() *KubeRouter { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *KubeRouterImageSpec) DeepCopyInto(out *KubeRouterImageSpec) { *out = *in - out.CNI = in.CNI - out.CNIInstaller = in.CNIInstaller + if in.CNI != nil { + in, out := &in.CNI, &out.CNI + *out = new(ImageSpec) + **out = **in + } + if in.CNIInstaller != nil { + in, out := &in.CNIInstaller, &out.CNIInstaller + *out = new(ImageSpec) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeRouterImageSpec.