From 2c997475e894498576db15905dd21a48924afd08 Mon Sep 17 00:00:00 2001 From: Peter Hunt Date: Tue, 26 Nov 2024 13:08:23 -0500 Subject: [PATCH] add MinimumKubeletVersion authorization-mode if feature is on Signed-off-by: Peter Hunt --- pkg/cmd/render/render.go | 7 ++ .../node/minimum_kubelet_version.go | 33 ++++++++ .../node/minimum_kubelet_version_test.go | 78 +++++++++++++++++++ 3 files changed, 118 insertions(+) create mode 100644 pkg/operator/configobservation/node/minimum_kubelet_version.go create mode 100644 pkg/operator/configobservation/node/minimum_kubelet_version_test.go diff --git a/pkg/cmd/render/render.go b/pkg/cmd/render/render.go index d4954d7b73..67bb7859fa 100644 --- a/pkg/cmd/render/render.go +++ b/pkg/cmd/render/render.go @@ -22,6 +22,7 @@ import ( "github.com/openshift/cluster-kube-apiserver-operator/bindata" "github.com/openshift/cluster-kube-apiserver-operator/pkg/operator/configobservation/apienablement" "github.com/openshift/cluster-kube-apiserver-operator/pkg/operator/configobservation/auth" + "github.com/openshift/cluster-kube-apiserver-operator/pkg/operator/configobservation/node" libgoaudit "github.com/openshift/library-go/pkg/operator/apiserver/audit" "github.com/openshift/library-go/pkg/operator/configobserver/featuregates" genericrender "github.com/openshift/library-go/pkg/operator/render" @@ -357,6 +358,12 @@ func bootstrapDefaultConfig(featureGates featuregates.FeatureGate) ([]byte, erro } } + if featureGates.Enabled(features.FeatureGateMinimumKubeletVersion) { + if err := node.SetAPIServerArgumentsToEnforceMinimumKubeletVersion(defaultConfig); err != nil { + return nil, err + } + } + defaultConfigRaw, err := json.Marshal(defaultConfig) if err != nil { return nil, fmt.Errorf("failed to marshal default config - %s", err) diff --git a/pkg/operator/configobservation/node/minimum_kubelet_version.go b/pkg/operator/configobservation/node/minimum_kubelet_version.go new file mode 100644 index 0000000000..fa4f2c59b9 --- /dev/null +++ b/pkg/operator/configobservation/node/minimum_kubelet_version.go @@ -0,0 +1,33 @@ +package node + +import ( + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" +) + +var ( + ModeMinimumKubeletVersion = "MinimumKubeletVersion" + authorizationModeFlag = "authorization-mode" +) + +var configPath = []string{"apiServerArguments", authorizationModeFlag} + +func SetAPIServerArgumentsToEnforceMinimumKubeletVersion(config map[string]interface{}) error { + apiServerArguments, found, err := unstructured.NestedStringSlice(config, configPath...) + if err != nil { + return err + } + if found { + for _, arg := range apiServerArguments { + if arg == ModeMinimumKubeletVersion { + // Already specified! + return nil + } + } + apiServerArguments = append(apiServerArguments, ModeMinimumKubeletVersion) + unstructured.RemoveNestedField(config, configPath...) + } else { + apiServerArguments = []string{ModeMinimumKubeletVersion} + } + + return unstructured.SetNestedStringSlice(config, apiServerArguments, configPath...) +} diff --git a/pkg/operator/configobservation/node/minimum_kubelet_version_test.go b/pkg/operator/configobservation/node/minimum_kubelet_version_test.go new file mode 100644 index 0000000000..df56ead384 --- /dev/null +++ b/pkg/operator/configobservation/node/minimum_kubelet_version_test.go @@ -0,0 +1,78 @@ +package node + +import ( + "strings" + "testing" + + "github.com/google/go-cmp/cmp" +) + +func TestSetAPIServerArgumentsToEnforceMinimumKubeletVersion(t *testing.T) { + for _, tc := range []struct { + name string + existingConfig map[string]interface{} + // featureGateAccessor featuregates.FeatureGateAccess + expectedErr string + expectedConfig map[string]interface{} + }{ + { + name: "should not fail if apiServerArguments not present", + existingConfig: map[string]interface{}{ + "fakeconfig": "fake", + }, + expectedConfig: map[string]interface{}{ + "fakeconfig": "fake", + "apiServerArguments": map[string]any{"authorization-mode": []any{"MinimumKubeletVersion"}}, + }, + expectedErr: "", + }, + { + name: "should not fail if authorization-mode not present", + existingConfig: map[string]interface{}{ + "apiServerArguments": map[string]any{"fake": []any{"fake"}}, + }, + expectedConfig: map[string]interface{}{ + "apiServerArguments": map[string]any{"fake": []any{"fake"}, "authorization-mode": []any{"MinimumKubeletVersion"}}, + }, + expectedErr: "", + }, + { + name: "should not fail if MinimumKubeletVersion not present", + existingConfig: map[string]interface{}{ + "apiServerArguments": map[string]any{"authorization-mode": []any{"fake"}}, + }, + expectedConfig: map[string]interface{}{ + "apiServerArguments": map[string]any{"authorization-mode": []any{"fake", "MinimumKubeletVersion"}}, + }, + expectedErr: "", + }, + { + name: "should not fail if MinimumKubeletVersion already present", + existingConfig: map[string]interface{}{ + "apiServerArguments": map[string]any{"authorization-mode": []any{"MinimumKubeletVersion"}}, + }, + expectedConfig: map[string]interface{}{ + "apiServerArguments": map[string]any{"authorization-mode": []any{"MinimumKubeletVersion"}}, + }, + expectedErr: "", + }, + } { + t.Run(tc.name, func(t *testing.T) { + err := SetAPIServerArgumentsToEnforceMinimumKubeletVersion(tc.existingConfig) + switch { + case err == nil && len(tc.expectedErr) == 0: + case err == nil && len(tc.expectedErr) > 0: + t.Fatalf("missing err: %v", tc.expectedErr) + + case len(err.Error()) > 0 && len(tc.expectedErr) == 0: + t.Fatal(err) + case len(err.Error()) > 0 && len(tc.expectedErr) > 0 && !strings.Contains(err.Error(), tc.expectedErr): + t.Fatalf("missing err: %v in \n%v", tc.expectedErr, err) + } + + if diff := cmp.Diff(tc.expectedConfig, tc.existingConfig); diff != "" { + t.Errorf("unexpected config:\n%s", diff) + } + }) + } +}