From b177a749829587a3bc66c7632de69b67edb89f50 Mon Sep 17 00:00:00 2001 From: Amal Sebastian Date: Wed, 30 Sep 2026 15:18:55 +0530 Subject: [PATCH] Feat: Add patches for kubernetes 1.37 (#5610) * add patches for kubernetes 1.37 * remove --containerd flag from kubelet args (removed in k8s-1.37) * use python venv to avoid system vs pip package conflicts * add snap hook to remove --containerd from current/args * fix: migrate space-separated containerd flag * fix: use postrefresh hook to remove the --containerd instead of configure hook * fix: use appropriate post-refresh hook to remove --containerd flag --- .github/actions/test-prep/action.yaml | 10 +- .github/workflows/build-snap.yml | 22 +- .github/workflows/check-unit-tests.yml | 30 +- .../v1.37.0/0000-Kubelite-integration.patch | 418 ++++++++++++++++++ ...reapply-handling-to-ignore-unchanged.patch | 25 ++ ...fix-allow-node-to-get-endpointslices.patch | 24 + microk8s-resources/default-args/kubelet | 1 - snap/hooks/post-refresh | 8 + 8 files changed, 521 insertions(+), 17 deletions(-) create mode 100644 build-scripts/components/kubernetes/patches/v1.37.0/0000-Kubelite-integration.patch create mode 100644 build-scripts/components/kubernetes/patches/v1.37.0/0001-Set-log-reapply-handling-to-ignore-unchanged.patch create mode 100644 build-scripts/components/kubernetes/patches/v1.37.0/0002-fix-allow-node-to-get-endpointslices.patch diff --git a/.github/actions/test-prep/action.yaml b/.github/actions/test-prep/action.yaml index 2b2ac8ae3a..ca00d44d4d 100644 --- a/.github/actions/test-prep/action.yaml +++ b/.github/actions/test-prep/action.yaml @@ -10,9 +10,13 @@ runs: - name: Install test dependencies shell: bash run: | - set -x - sudo apt-get remove -y python3-yaml - sudo pip3 install -r ./tests/requirements.txt + set -eux + python -m venv "$RUNNER_TEMP/microk8s-test-venv" + "$RUNNER_TEMP/microk8s-test-venv/bin/python" -m pip install --upgrade pip + "$RUNNER_TEMP/microk8s-test-venv/bin/python" -m pip install \ + -r ./tests/requirements.txt + echo "MICROK8S_TEST_VENV=$RUNNER_TEMP/microk8s-test-venv" >> "$GITHUB_ENV" + echo "$RUNNER_TEMP/microk8s-test-venv/bin" >> "$GITHUB_PATH" # Docker sets iptables rules that interfere with LXD and K8s. # https://documentation.ubuntu.com/lxd/en/latest/howto/network_bridge_firewalld/#prevent-connectivity-issues-with-lxd-and-docker - name: Apply Docker iptables workaround diff --git a/.github/workflows/build-snap.yml b/.github/workflows/build-snap.yml index fd79728f31..e3a71779aa 100644 --- a/.github/workflows/build-snap.yml +++ b/.github/workflows/build-snap.yml @@ -54,7 +54,10 @@ jobs: uses: ./.github/actions/test-prep - name: Running upgrade path test run: | - sudo -E UPGRADE_MICROK8S_FROM=latest/edge UPGRADE_MICROK8S_TO=$PWD/build/microk8s.snap pytest -s ./tests/test-upgrade-path.py + sudo -E env \ + UPGRADE_MICROK8S_FROM=latest/edge \ + UPGRADE_MICROK8S_TO=$PWD/build/microk8s.snap \ + "$MICROK8S_TEST_VENV/bin/pytest" -s ./tests/test-upgrade-path.py test-addons-core: name: Test core addons @@ -82,7 +85,9 @@ jobs: export POD_GATEWAY="10.200.0.1" export SKIP_PROMETHEUS="False" export UNDER_TIME_PRESSURE=${UNDER_TIME_PRESSURE@u} - sudo -E bash -c "cd /var/snap/microk8s/common/addons/core/tests; pytest -s -ra test-addons.py" + sudo -E bash -c \ + "cd /var/snap/microk8s/common/addons/core/tests && \ + exec \"$MICROK8S_TEST_VENV/bin/pytest\" -s -ra test-addons.py" test-addons-community: name: Test community addons @@ -102,7 +107,9 @@ jobs: sudo snap install build/microk8s.snap --classic --dangerous sudo microk8s enable community export UNDER_TIME_PRESSURE=${UNDER_TIME_PRESSURE@u} - sudo -E bash -c "cd /var/snap/microk8s/common/addons/community/; pytest -s -ra ./tests/" + sudo -E bash -c \ + "cd /var/snap/microk8s/common/addons/community && \ + exec \"$MICROK8S_TEST_VENV/bin/pytest\" -s -ra ./tests/" test-addons-core-upgrade: name: Test core addons upgrade @@ -120,7 +127,11 @@ jobs: run: | set -x export UNDER_TIME_PRESSURE=${UNDER_TIME_PRESSURE@u} - sudo -E bash -c "UPGRADE_MICROK8S_FROM=latest/edge UPGRADE_MICROK8S_TO=$PWD/build/microk8s.snap pytest -s ./tests/test-upgrade.py" + + sudo -E env \ + UPGRADE_MICROK8S_FROM=latest/edge \ + UPGRADE_MICROK8S_TO=$PWD/build/microk8s.snap \ + "$MICROK8S_TEST_VENV/bin/pytest" -s ./tests/test-upgrade.py test-cluster-agent: name: Cluster agent health check @@ -136,7 +147,8 @@ jobs: run: | set -x sudo snap install build/microk8s.snap --classic --dangerous - sudo -E bash -c "pytest -s ./tests/test-cluster-agent.py" + sudo -E "$MICROK8S_TEST_VENV/bin/pytest" \ + -s ./tests/test-cluster-agent.py test-airgap: name: Test airgap installation diff --git a/.github/workflows/check-unit-tests.yml b/.github/workflows/check-unit-tests.yml index f1c169cd85..4f37f76b6d 100644 --- a/.github/workflows/check-unit-tests.yml +++ b/.github/workflows/check-unit-tests.yml @@ -12,16 +12,30 @@ jobs: - name: Check out code uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - - name: Install dependencies + - name: Set up Python + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + with: + python-version: "3.10" + + - name: Install dependencies in venv run: | - sudo apt-get update - sudo apt-get install tox --fix-missing - sudo pip3 install -U pytest==7.1.3 sh==1.14.3 + set -eux + venv="$RUNNER_TEMP/microk8s-unit-test-venv" + python -m venv "$venv" + "$venv/bin/python" -m pip install --upgrade pip + "$venv/bin/python" -m pip install \ + -r tests/requirements.txt \ + tox \ + pytest==7.1.3 \ + sh==1.14.3 + echo "MICROK8S_UNIT_TEST_VENV=$venv" >> "$GITHUB_ENV" + - name: Check Units run: | - tox -e scripts - tox -e wrappers - tox -e cluster + "$MICROK8S_UNIT_TEST_VENV/bin/tox" -e scripts + "$MICROK8S_UNIT_TEST_VENV/bin/tox" -e wrappers + "$MICROK8S_UNIT_TEST_VENV/bin/tox" -e cluster + - name: Verify branches run: | - pytest -s ./tests/verify-branches.py + "$MICROK8S_UNIT_TEST_VENV/bin/pytest" -s ./tests/verify-branches.py diff --git a/build-scripts/components/kubernetes/patches/v1.37.0/0000-Kubelite-integration.patch b/build-scripts/components/kubernetes/patches/v1.37.0/0000-Kubelite-integration.patch new file mode 100644 index 0000000000..dda9a9a2a4 --- /dev/null +++ b/build-scripts/components/kubernetes/patches/v1.37.0/0000-Kubelite-integration.patch @@ -0,0 +1,418 @@ +From 7122e94c80140adb31ac6beaef04ce616134b8dc Mon Sep 17 00:00:00 2001 +From: Amal Sebastian +Date: Thu, 24 Sep 2026 14:49:40 +0530 +Subject: [PATCH] Kubelite integration + +--- + cmd/kube-apiserver/app/server.go | 9 ++- + cmd/kube-scheduler/app/server.go | 6 +- + cmd/kubelet/app/server.go | 4 -- + cmd/kubelite/app/daemons/daemon.go | 85 +++++++++++++++++++++++++++ + cmd/kubelite/app/options/options.go | 79 +++++++++++++++++++++++++ + cmd/kubelite/app/server.go | 91 +++++++++++++++++++++++++++++ + cmd/kubelite/kubelite.go | 25 ++++++++ + pkg/volume/csi/csi_plugin.go | 11 +++- + 8 files changed, 300 insertions(+), 10 deletions(-) + create mode 100644 cmd/kubelite/app/daemons/daemon.go + create mode 100644 cmd/kubelite/app/options/options.go + create mode 100644 cmd/kubelite/app/server.go + create mode 100644 cmd/kubelite/kubelite.go + +diff --git a/cmd/kube-apiserver/app/server.go b/cmd/kube-apiserver/app/server.go +index f689bb81..b31b2819 100644 +--- a/cmd/kube-apiserver/app/server.go ++++ b/cmd/kube-apiserver/app/server.go +@@ -68,9 +68,14 @@ func init() { + } + + // NewAPIServerCommand creates a *cobra.Command object with default parameters +-func NewAPIServerCommand() *cobra.Command { ++func NewAPIServerCommand(ctxs ...context.Context) *cobra.Command { + s := options.NewServerRunOptions() +- ctx := genericapiserver.SetupSignalContext() ++ ctx := context.Background() ++ if len(ctxs) == 0 { ++ ctx = genericapiserver.SetupSignalContext() ++ } else { ++ ctx = ctxs[0] ++ } + featureGate := s.GenericServerRunOptions.ComponentGlobalsRegistry.FeatureGateFor(basecompatibility.DefaultKubeComponent) + + cmd := &cobra.Command{ +diff --git a/cmd/kube-scheduler/app/server.go b/cmd/kube-scheduler/app/server.go +index 4b012fca..c2a8de3c 100644 +--- a/cmd/kube-scheduler/app/server.go ++++ b/cmd/kube-scheduler/app/server.go +@@ -162,7 +162,11 @@ func runCommand(cmd *cobra.Command, opts *options.Options, registryOptions ...Op + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + go func() { +- stopCh := server.SetupSignalHandler() ++ c := cmd.Context() ++ if c == nil { ++ c = server.SetupSignalContext() ++ } ++ stopCh := c.Done() + <-stopCh + cancel() + }() +diff --git a/cmd/kubelet/app/server.go b/cmd/kubelet/app/server.go +index 618e5191..ca49822c 100644 +--- a/cmd/kubelet/app/server.go ++++ b/cmd/kubelet/app/server.go +@@ -64,7 +64,6 @@ import ( + "k8s.io/apimachinery/pkg/util/validation/field" + utilversion "k8s.io/apimachinery/pkg/util/version" + "k8s.io/apimachinery/pkg/util/wait" +- genericapiserver "k8s.io/apiserver/pkg/server" + "k8s.io/apiserver/pkg/server/flagz" + "k8s.io/apiserver/pkg/server/healthz" + utilfeature "k8s.io/apiserver/pkg/util/feature" +@@ -300,9 +299,6 @@ is checked every 20 seconds (also configurable with a flag).`, + } + } + +- // set up signal context for kubelet shutdown +- ctx := genericapiserver.SetupSignalContext() +- + utilfeature.DefaultMutableFeatureGate.AddMetrics() + // run the kubelet + return Run(ctx, kubeletServer, kubeletDeps, utilfeature.DefaultFeatureGate) +diff --git a/cmd/kubelite/app/daemons/daemon.go b/cmd/kubelite/app/daemons/daemon.go +new file mode 100644 +index 00000000..46c1af7f +--- /dev/null ++++ b/cmd/kubelite/app/daemons/daemon.go +@@ -0,0 +1,85 @@ ++package daemon ++ ++import ( ++ "context" ++ ++ "k8s.io/client-go/kubernetes" ++ "k8s.io/client-go/tools/clientcmd" ++ genericcontrollermanager "k8s.io/controller-manager/app" ++ "k8s.io/klog/v2" ++ apiserver "k8s.io/kubernetes/cmd/kube-apiserver/app" ++ controller "k8s.io/kubernetes/cmd/kube-controller-manager/app" ++ proxy "k8s.io/kubernetes/cmd/kube-proxy/app" ++ scheduler "k8s.io/kubernetes/cmd/kube-scheduler/app" ++ kubelet "k8s.io/kubernetes/cmd/kubelet/app" ++ ++ "time" ++) ++ ++func StartControllerManager(args []string, ctx context.Context) { ++ command := controller.NewControllerManagerCommand() ++ command.SetArgs(args) ++ ++ klog.Info("Starting Controller Manager") ++ if err := command.ExecuteContext(ctx); err != nil { ++ klog.Fatalf("Controller Manager exited %v", err) ++ } ++ klog.Info("Stopping Controller Manager") ++} ++ ++func StartScheduler(args []string, ctx context.Context) { ++ command := scheduler.NewSchedulerCommand() ++ command.SetArgs(args) ++ ++ klog.Info("Starting Scheduler") ++ if err := command.ExecuteContext(ctx); err != nil { ++ klog.Fatalf("Scheduler exited %v", err) ++ } ++ klog.Info("Stopping Scheduler") ++} ++ ++func StartProxy(args []string) { ++ command := proxy.NewProxyCommand() ++ command.SetArgs(args) ++ ++ klog.Info("Starting Proxy") ++ if err := command.Execute(); err != nil { ++ klog.Fatalf("Proxy exited %v", err) ++ } ++ klog.Info("Stopping Proxy") ++} ++ ++func StartKubelet(args []string, ctx context.Context) { ++ command := kubelet.NewKubeletCommand(ctx) ++ command.SetArgs(args) ++ ++ klog.Info("Starting Kubelet") ++ if err := command.Execute(); err != nil { ++ klog.Fatalf("Kubelet exited %v", err) ++ } ++ klog.Info("Stopping Kubelet") ++} ++ ++func StartAPIServer(args []string, ctx context.Context) { ++ command := apiserver.NewAPIServerCommand(ctx) ++ command.SetArgs(args) ++ klog.Info("Starting API Server") ++ if err := command.Execute(); err != nil { ++ klog.Fatalf("API Server exited %v", err) ++ } ++ klog.Info("Stopping API Server") ++} ++ ++func WaitForAPIServer(kubeconfigpath string, timeout time.Duration) { ++ klog.Info("Waiting for the API server") ++ config, err := clientcmd.BuildConfigFromFlags("", kubeconfigpath) ++ if err != nil { ++ klog.Fatalf("could not find the cluster's kubeconfig file %v", err) ++ } ++ // create the client ++ client, err := kubernetes.NewForConfig(config) ++ if err != nil { ++ klog.Fatalf("could not create client to the cluster %v", err) ++ } ++ genericcontrollermanager.WaitForAPIServer(client, timeout) ++} +diff --git a/cmd/kubelite/app/options/options.go b/cmd/kubelite/app/options/options.go +new file mode 100644 +index 00000000..80f1d8b0 +--- /dev/null ++++ b/cmd/kubelite/app/options/options.go +@@ -0,0 +1,79 @@ ++/* ++Copyright 2018 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 options ++ ++import ( ++ "bufio" ++ "k8s.io/klog/v2" ++ "os" ++ "strings" ++) ++ ++// Options has all the params needed to run a Kubelite ++type Options struct { ++ SchedulerArgsFile string ++ ControllerManagerArgsFile string ++ ProxyArgsFile string ++ KubeletArgsFile string ++ APIServerArgsFile string ++ KubeconfigFile string ++ StartControlPlane bool ++} ++ ++func NewOptions() (*Options){ ++ o := Options{ ++ "/var/snap/microk8s/current/args/kube-scheduler", ++ "/var/snap/microk8s/current/args/kube-controller-manager", ++ "/var/snap/microk8s/current/args/kube-proxy", ++ "/var/snap/microk8s/current/args/kubelet", ++ "/var/snap/microk8s/current/args/kube-apiserver", ++ "/var/snap/microk8s/current/credentials/client.config", ++ true, ++ } ++ return &o ++} ++ ++func ReadArgsFromFile(filename string) []string { ++ var args []string ++ file, err := os.Open(filename) ++ if err != nil { ++ klog.Fatalf("Failed to open arguments file %v", err) ++ } ++ defer file.Close() ++ ++ scanner := bufio.NewScanner(file) ++ for scanner.Scan() { ++ line := scanner.Text() ++ line = strings.TrimSpace(line) ++ // ignore lines with # and empty lines ++ if len(line) <= 0 || strings.HasPrefix(line, "#") { ++ continue ++ } ++ // remove " and ' ++ for _, r := range "\"'" { ++ line = strings.ReplaceAll(line, string(r), "") ++ } ++ for _, part := range strings.Split(line, " ") { ++ ++ args = append(args, os.ExpandEnv(part)) ++ } ++ } ++ if err := scanner.Err(); err != nil { ++ klog.Fatalf("Failed to read arguments file %v", err) ++ } ++ return args ++} +diff --git a/cmd/kubelite/app/server.go b/cmd/kubelite/app/server.go +new file mode 100644 +index 00000000..858a7c10 +--- /dev/null ++++ b/cmd/kubelite/app/server.go +@@ -0,0 +1,91 @@ ++/* ++Copyright © 2020 NAME HERE ++ ++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 app ++ ++import ( ++ "fmt" ++ "os" ++ "time" ++ ++ "github.com/spf13/cobra" ++ "k8s.io/apimachinery/pkg/util/version" ++ genericapiserver "k8s.io/apiserver/pkg/server" ++ utilfeature "k8s.io/apiserver/pkg/util/feature" ++ clientgofeaturegate "k8s.io/client-go/features" ++ "k8s.io/component-base/featuregate" ++ daemon "k8s.io/kubernetes/cmd/kubelite/app/daemons" ++ "k8s.io/kubernetes/cmd/kubelite/app/options" ++) ++ ++var opts = options.NewOptions() ++ ++// liteCmd represents the base command when called without any subcommands ++var liteCmd = &cobra.Command{ ++ Use: "kubelite", ++ Short: "Single server kubernetes", ++ Long: `A single server that spawns all other kubernetes servers as threads`, ++ // Uncomment the following line if your bare application ++ // has an action associated with it: ++ Run: func(cmd *cobra.Command, args []string) { ++ ctx := genericapiserver.SetupSignalContext() ++ ++ if opts.StartControlPlane { ++ if !utilfeature.DefaultFeatureGate.Enabled(featuregate.Feature(clientgofeaturegate.WatchListClient)) { ++ ver := version.MustParse("1.34") ++ if err := utilfeature.DefaultMutableFeatureGate.OverrideDefaultAtVersion(featuregate.Feature(clientgofeaturegate.WatchListClient), true, ver); err != nil { ++ panic(fmt.Sprintf("unable to set %s feature gate, err: %v", clientgofeaturegate.WatchListClient, err)) ++ } ++ } ++ ++ apiserverArgs := options.ReadArgsFromFile(opts.APIServerArgsFile) ++ go daemon.StartAPIServer(apiserverArgs, ctx) ++ daemon.WaitForAPIServer(opts.KubeconfigFile, 360*time.Second) ++ ++ controllerArgs := options.ReadArgsFromFile(opts.ControllerManagerArgsFile) ++ go daemon.StartControllerManager(controllerArgs, ctx) ++ ++ schedulerArgs := options.ReadArgsFromFile(opts.SchedulerArgsFile) ++ go daemon.StartScheduler(schedulerArgs, ctx) ++ } ++ ++ proxyArgs := options.ReadArgsFromFile(opts.ProxyArgsFile) ++ go daemon.StartProxy(proxyArgs) ++ ++ kubeletArgs := options.ReadArgsFromFile(opts.KubeletArgsFile) ++ daemon.StartKubelet(kubeletArgs, ctx) ++ }, ++} ++ ++// Execute adds all child commands to the root command and sets flags appropriately. ++// This is called by main.main(). It only needs to happen once to the liteCmd. ++func Execute() { ++ if err := liteCmd.Execute(); err != nil { ++ fmt.Println(err) ++ os.Exit(1) ++ } ++} ++ ++func init() { ++ cobra.OnInitialize() ++ ++ liteCmd.Flags().StringVar(&opts.SchedulerArgsFile, "scheduler-args-file", opts.SchedulerArgsFile, "file with the arguments for the scheduler") ++ liteCmd.Flags().StringVar(&opts.ControllerManagerArgsFile, "controller-manager-args-file", opts.ControllerManagerArgsFile, "file with the arguments for the controller manager") ++ liteCmd.Flags().StringVar(&opts.ProxyArgsFile, "proxy-args-file", opts.ProxyArgsFile, "file with the arguments for kube-proxy") ++ liteCmd.Flags().StringVar(&opts.KubeletArgsFile, "kubelet-args-file", opts.KubeletArgsFile, "file with the arguments for kubelet") ++ liteCmd.Flags().StringVar(&opts.APIServerArgsFile, "apiserver-args-file", opts.APIServerArgsFile, "file with the arguments for the API server") ++ liteCmd.Flags().StringVar(&opts.KubeconfigFile, "kubeconfig-file", opts.KubeconfigFile, "the kubeconfig file to use to healthcheck the API server") ++ liteCmd.Flags().BoolVar(&opts.StartControlPlane, "start-control-plane", opts.StartControlPlane, "start the control plane (API server, scheduler and controller manager)") ++} +diff --git a/cmd/kubelite/kubelite.go b/cmd/kubelite/kubelite.go +new file mode 100644 +index 00000000..30ab604f +--- /dev/null ++++ b/cmd/kubelite/kubelite.go +@@ -0,0 +1,25 @@ ++package main ++ ++import ( ++ "github.com/spf13/pflag" ++ cliflag "k8s.io/component-base/cli/flag" ++ ++ "k8s.io/component-base/logs" ++ _ "k8s.io/component-base/metrics/prometheus/clientgo" // load all the prometheus client-go plugin ++ _ "k8s.io/component-base/metrics/prometheus/version" // for version metric registration ++ "k8s.io/kubernetes/cmd/kubelite/app" ++) ++ ++func main() { ++ println("Starting kubelite") ++ // TODO: once we switch everything over to Cobra commands, we can go back to calling ++ // utilflag.InitFlags() (by removing its pflag.Parse() call). For now, we have to set the ++ // normalize func and add the go flag set by hand. ++ pflag.CommandLine.SetNormalizeFunc(cliflag.WordSepNormalizeFunc) ++ // utilflag.InitFlags() ++ logs.InitLogs() ++ defer logs.FlushLogs() ++ ++ app.Execute() ++ println("Stopping kubelite") ++} +diff --git a/pkg/volume/csi/csi_plugin.go b/pkg/volume/csi/csi_plugin.go +index 876e33e2..a0b167be 100644 +--- a/pkg/volume/csi/csi_plugin.go ++++ b/pkg/volume/csi/csi_plugin.go +@@ -347,18 +347,23 @@ func (p *csiPlugin) Init(host volume.VolumeHost) error { + } + + // Initializing the label management channels +- nim = nodeinfomanager.NewNodeInfoManager(host.GetNodeName(), host, migratedPlugins) ++ localNim := nodeinfomanager.NewNodeInfoManager(host.GetNodeName(), host, migratedPlugins) + PluginHandler.csiPlugin = p + + // This function prevents Kubelet from posting Ready status until CSINode + // is both installed and initialized +- if err := initializeCSINode(host, p.csiDriverInformer); err != nil { ++ if err := initializeCSINode(host, p.csiDriverInformer, localNim); err != nil { + return errors.New(log("failed to initialize CSINode: %v", err)) + } ++ ++ if _, ok := host.(volume.KubeletVolumeHost); ok { ++ nim = localNim ++ } ++ + return nil + } + +-func initializeCSINode(host volume.VolumeHost, csiDriverInformer cache.SharedIndexInformer) error { ++func initializeCSINode(host volume.VolumeHost, csiDriverInformer cache.SharedIndexInformer, nim nodeinfomanager.Interface) error { + kvh, ok := host.(volume.KubeletVolumeHost) + if !ok { + klog.V(4).Info("Cast from VolumeHost to KubeletVolumeHost failed. Skipping CSINode initialization, not running on kubelet") +-- +2.53.0 + diff --git a/build-scripts/components/kubernetes/patches/v1.37.0/0001-Set-log-reapply-handling-to-ignore-unchanged.patch b/build-scripts/components/kubernetes/patches/v1.37.0/0001-Set-log-reapply-handling-to-ignore-unchanged.patch new file mode 100644 index 0000000000..5b61a4b7c6 --- /dev/null +++ b/build-scripts/components/kubernetes/patches/v1.37.0/0001-Set-log-reapply-handling-to-ignore-unchanged.patch @@ -0,0 +1,25 @@ +From fba83811cc6542ac5331fa5906dffdcc5e596ebc Mon Sep 17 00:00:00 2001 +From: Angelos Kolaitis +Date: Thu, 27 Jul 2023 18:08:00 +0300 +Subject: [PATCH 2/3] Set log reapply handling to ignore unchanged + +--- + staging/src/k8s.io/component-base/logs/api/v1/options.go | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/staging/src/k8s.io/component-base/logs/api/v1/options.go b/staging/src/k8s.io/component-base/logs/api/v1/options.go +index a61d142c..75420a70 100644 +--- a/staging/src/k8s.io/component-base/logs/api/v1/options.go ++++ b/staging/src/k8s.io/component-base/logs/api/v1/options.go +@@ -65,7 +65,7 @@ func NewLoggingConfiguration() *LoggingConfiguration { + // are no goroutines which might call logging functions. The default for ValidateAndApply + // and ValidateAndApplyWithOptions is to return an error when called more than once. + // Binaries and unit tests can override that behavior. +-var ReapplyHandling = ReapplyHandlingError ++var ReapplyHandling = ReapplyHandlingIgnoreUnchanged + + type ReapplyHandlingType int + +-- +2.43.0 + diff --git a/build-scripts/components/kubernetes/patches/v1.37.0/0002-fix-allow-node-to-get-endpointslices.patch b/build-scripts/components/kubernetes/patches/v1.37.0/0002-fix-allow-node-to-get-endpointslices.patch new file mode 100644 index 0000000000..32f9080386 --- /dev/null +++ b/build-scripts/components/kubernetes/patches/v1.37.0/0002-fix-allow-node-to-get-endpointslices.patch @@ -0,0 +1,24 @@ +From 30efe62079bb60e86f3994ee1b85879b6dc71780 Mon Sep 17 00:00:00 2001 +From: Mateo Florido +Date: Thu, 11 Sep 2025 17:36:10 -0500 +Subject: [PATCH 3/3] fix: allow node to get endpointslices + +--- + plugin/pkg/auth/authorizer/rbac/bootstrappolicy/policy.go | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/policy.go b/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/policy.go +index 3211ec5e..a8236ed0 100644 +--- a/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/policy.go ++++ b/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/policy.go +@@ -239,6 +239,7 @@ func NodeRules() []rbacv1.PolicyRule { + // TODO: add to the Node authorizer and restrict to endpoints referenced by pods or PVs bound to the node + // Needed for glusterfs volumes + rbacv1helpers.NewRule("get").Groups(legacyGroup).Resources("endpoints").RuleOrDie(), ++ rbacv1helpers.NewRule("get", "list", "watch").Groups(discoveryGroup).Resources("endpointslices").RuleOrDie(), + // Used to create a certificatesigningrequest for a node-specific client certificate, and watch + // for it to be signed. This allows the kubelet to rotate it's own certificate. + rbacv1helpers.NewRule("create", "get", "list", "watch").Groups(certificatesGroup).Resources("certificatesigningrequests").RuleOrDie(), +-- +2.43.0 + diff --git a/microk8s-resources/default-args/kubelet b/microk8s-resources/default-args/kubelet index ff62fa38ec..a5ccb1807c 100644 --- a/microk8s-resources/default-args/kubelet +++ b/microk8s-resources/default-args/kubelet @@ -6,7 +6,6 @@ --fail-swap-on=false --eviction-hard="memory.available<100Mi,nodefs.available<1Gi,imagefs.available<1Gi" --container-runtime-endpoint=${SNAP_COMMON}/run/containerd.sock ---containerd=${SNAP_COMMON}/run/containerd.sock --node-labels="microk8s.io/cluster=true,node.kubernetes.io/microk8s-controlplane=microk8s-controlplane" --authentication-token-webhook=true --read-only-port=0 diff --git a/snap/hooks/post-refresh b/snap/hooks/post-refresh index 4f11dc1f9a..e309b76ecb 100755 --- a/snap/hooks/post-refresh +++ b/snap/hooks/post-refresh @@ -4,5 +4,13 @@ use_snap_env +# Kubernetes 1.37 removed the --containerd kubelet flag. +if grep -qE '^[[:space:]]*--containerd([=[:space:]])' "${SNAP_DATA}/args/kubelet" +then + echo "Removing obsolete kubelet --containerd argument" + skip_opt_in_config containerd kubelet + snapctl restart "${SNAP_NAME}.daemon-kubelite" +fi + # Run post-refresh hooks $SNAP/usr/bin/python3 $SNAP/scripts/run-lifecycle-hooks.py post-refresh || true