From 61a8b581190edba4a24987ca812c9a2977050476 Mon Sep 17 00:00:00 2001 From: Francesco Romani Date: Tue, 29 Oct 2024 17:31:26 +0100 Subject: [PATCH] UPSTREAM: : require configuration file enablement similarly to what we do for the managed CPU (aka workload partitioning) feature, introduce a master configuration file `/etc/kubernetes/openshift-llc-alignment` which needs to be present for the LLC alignment feature to be activated, in addition to the policy option being required. This can be dropped when the feature per KEP https://github.com/kubernetes/enhancements/issues/4800 goes beta. Signed-off-by: Francesco Romani --- pkg/kubelet/cm/cpumanager/policy_options.go | 3 ++ .../cpumanager/policy_options_enablement.go | 50 +++++++++++++++++++ .../cm/cpumanager/policy_options_test.go | 8 +++ .../cm/cpumanager/policy_static_test.go | 2 + .../cm/cpumanager/topology_hints_test.go | 2 + pkg/kubelet/optenable/optenable.go | 41 +++++++++++++++ 6 files changed, 106 insertions(+) create mode 100644 pkg/kubelet/cm/cpumanager/policy_options_enablement.go create mode 100644 pkg/kubelet/optenable/optenable.go diff --git a/pkg/kubelet/cm/cpumanager/policy_options.go b/pkg/kubelet/cm/cpumanager/policy_options.go index 58ad86d9dc680..1231700b46fa4 100644 --- a/pkg/kubelet/cm/cpumanager/policy_options.go +++ b/pkg/kubelet/cm/cpumanager/policy_options.go @@ -59,6 +59,9 @@ func CheckPolicyOptionAvailable(option string) error { if alphaOptions.Has(option) && !utilfeature.DefaultFeatureGate.Enabled(kubefeatures.CPUManagerPolicyAlphaOptions) { return fmt.Errorf("CPU Manager Policy Alpha-level Options not enabled, but option %q provided", option) } + if alphaOptions.Has(option) && utilfeature.DefaultFeatureGate.Enabled(kubefeatures.CPUManagerPolicyAlphaOptions) { + return checkAlphaPolicyOptionHasEnablement(option) + } if betaOptions.Has(option) && !utilfeature.DefaultFeatureGate.Enabled(kubefeatures.CPUManagerPolicyBetaOptions) { return fmt.Errorf("CPU Manager Policy Beta-level Options not enabled, but option %q provided", option) diff --git a/pkg/kubelet/cm/cpumanager/policy_options_enablement.go b/pkg/kubelet/cm/cpumanager/policy_options_enablement.go new file mode 100644 index 0000000000000..7ada207307717 --- /dev/null +++ b/pkg/kubelet/cm/cpumanager/policy_options_enablement.go @@ -0,0 +1,50 @@ +/* +Copyright 2024 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cpumanager + +import ( + "fmt" + + "k8s.io/klog/v2" + "k8s.io/kubernetes/pkg/kubelet/optenable" +) + +var ( + forceEnablement bool +) + +func testOnlyForceEnablement() func() { + forceEnablement = true + return func() { + forceEnablement = false + } +} + +func checkAlphaPolicyOptionHasEnablement(option string) error { + switch option { + case PreferAlignByUnCoreCacheOption: + klog.InfoS("CPU Manager Policy Alpha level", "option", option, "enablementFile", optenable.LLCAlignment()) + if optenable.LLCAlignment() { + return nil + } + return fmt.Errorf("CPU Manager Policy Alpha-level Option %q is enabled but miss enablement file", option) + } + if forceEnablement { + return nil + } + return fmt.Errorf("CPU Manager Policy Alpha-level Option %q is not eligible for enablement", option) +} diff --git a/pkg/kubelet/cm/cpumanager/policy_options_test.go b/pkg/kubelet/cm/cpumanager/policy_options_test.go index 2b14b90429f3e..6ff86ea742991 100644 --- a/pkg/kubelet/cm/cpumanager/policy_options_test.go +++ b/pkg/kubelet/cm/cpumanager/policy_options_test.go @@ -122,6 +122,10 @@ func TestPolicyOptionsAvailable(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.option, func(t *testing.T) { featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, testCase.featureGate, testCase.featureGateEnable) + if testCase.featureGateEnable { + revertEnablement := testOnlyForceEnablement() + t.Cleanup(revertEnablement) + } err := CheckPolicyOptionAvailable(testCase.option) isEnabled := (err == nil) if isEnabled != testCase.expectedAvailable { @@ -191,6 +195,8 @@ func TestValidateStaticPolicyOptions(t *testing.T) { topoMgrStore := topologymanager.NewFakeManagerWithPolicy(topoMgrPolicy) featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, pkgfeatures.CPUManagerPolicyAlphaOptions, true) + revertEnablement := testOnlyForceEnablement() + t.Cleanup(revertEnablement) policyOpt, _ := NewStaticPolicyOptions(testCase.policyOption) err := ValidateStaticPolicyOptions(policyOpt, testCase.topology, topoMgrStore) gotError := (err != nil) @@ -238,6 +244,8 @@ func TestPolicyOptionsCompatibility(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.description, func(t *testing.T) { featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, testCase.featureGate, true) + revertEnablement := testOnlyForceEnablement() + t.Cleanup(revertEnablement) _, err := NewStaticPolicyOptions(testCase.policyOptions) gotError := err != nil if gotError != testCase.expectedErr { diff --git a/pkg/kubelet/cm/cpumanager/policy_static_test.go b/pkg/kubelet/cm/cpumanager/policy_static_test.go index f86b01d9ea7f8..1e32512f83a37 100644 --- a/pkg/kubelet/cm/cpumanager/policy_static_test.go +++ b/pkg/kubelet/cm/cpumanager/policy_static_test.go @@ -659,6 +659,8 @@ func runStaticPolicyTestCase(t *testing.T, testCase staticPolicyTest) { func runStaticPolicyTestCaseWithFeatureGate(t *testing.T, testCase staticPolicyTest) { featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, pkgfeatures.CPUManagerPolicyAlphaOptions, true) + revertEnablement := testOnlyForceEnablement() + t.Cleanup(revertEnablement) runStaticPolicyTestCase(t, testCase) } diff --git a/pkg/kubelet/cm/cpumanager/topology_hints_test.go b/pkg/kubelet/cm/cpumanager/topology_hints_test.go index 3c491ae84df99..670c4a9e7a7c9 100644 --- a/pkg/kubelet/cm/cpumanager/topology_hints_test.go +++ b/pkg/kubelet/cm/cpumanager/topology_hints_test.go @@ -449,6 +449,8 @@ func TestGetPodTopologyHintsWithPolicyOptions(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.description, func(t *testing.T) { featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, pkgfeatures.CPUManagerPolicyAlphaOptions, true) + revertEnablement := testOnlyForceEnablement() + t.Cleanup(revertEnablement) var activePods []*v1.Pod for p := range testCase.assignments { diff --git a/pkg/kubelet/optenable/optenable.go b/pkg/kubelet/optenable/optenable.go new file mode 100644 index 0000000000000..50b768c2188b0 --- /dev/null +++ b/pkg/kubelet/optenable/optenable.go @@ -0,0 +1,41 @@ +/* +Copyright 2024 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package optenable + +import ( + "os" +) + +var ( + // cpumanager: prefer-align-cpus-by-uncorecache + llcAlignmentEnabled bool + llcAlignmentFilename = "/etc/kubernetes/openshift-llc-alignment" +) + +func init() { + readEnablementFiles() +} + +func readEnablementFiles() { + if _, err := os.Stat(llcAlignmentFilename); err == nil { + llcAlignmentEnabled = true + } +} + +func LLCAlignment() bool { + return llcAlignmentEnabled +}