Skip to content

Commit 8db2dd3

Browse files
committed
kubeadm: add addon and post-upgrade phase for 'kubeadm upgrade node'
1 parent 17bae91 commit 8db2dd3

File tree

11 files changed

+229
-108
lines changed

11 files changed

+229
-108
lines changed

cmd/kubeadm/app/cmd/phases/upgrade/apply/kubeletconfig.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,16 +57,14 @@ func runKubeletConfigPhase(c workflow.RunData) error {
5757
return errors.New("kubelet-config phase invoked with an invalid data struct")
5858
}
5959

60-
initCfg, dryRun := data.InitCfg(), data.DryRun()
61-
6260
// Write the configuration for the kubelet down to disk and print the generated manifests instead of dry-running.
6361
// If not dry-running, the kubelet config file will be backed up to the /etc/kubernetes/tmp/ dir, so that it could be
6462
// recovered if anything goes wrong.
65-
err := upgrade.WriteKubeletConfigFiles(initCfg, data.PatchesDir(), dryRun, data.OutputWriter())
63+
err := upgrade.WriteKubeletConfigFiles(data.InitCfg(), data.PatchesDir(), data.DryRun(), data.OutputWriter())
6664
if err != nil {
6765
return err
6866
}
6967

70-
fmt.Println("[upgrade/kubelet-config] The kubelet configuration for this node was successfully updated!")
68+
fmt.Println("[upgrade/kubelet-config] The kubelet configuration for this node was successfully upgraded!")
7169
return nil
7270
}

cmd/kubeadm/app/cmd/phases/upgrade/apply/postupgrade.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ func NewPostUpgradePhase() workflow.Phase {
4141
func runPostUpgrade(c workflow.RunData) error {
4242
_, ok := c.(Data)
4343
if !ok {
44-
return errors.New("preflight phase invoked with an invalid data struct")
44+
return errors.New("post-upgrade phase invoked with an invalid data struct")
4545
}
4646
// PLACEHOLDER: this phase should contain any release specific post-upgrade tasks.
4747

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
/*
2+
Copyright 2024 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
// Package node implements phases of 'kubeadm upgrade node'.
18+
package node
19+
20+
import (
21+
"fmt"
22+
"io"
23+
24+
"github.com/pkg/errors"
25+
26+
clientset "k8s.io/client-go/kubernetes"
27+
28+
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
29+
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
30+
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/workflow"
31+
cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util"
32+
dnsaddon "k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/dns"
33+
proxyaddon "k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/proxy"
34+
"k8s.io/kubernetes/cmd/kubeadm/app/phases/upgrade"
35+
)
36+
37+
// NewAddonPhase returns a new addon phase.
38+
func NewAddonPhase() workflow.Phase {
39+
return workflow.Phase{
40+
Name: "addon",
41+
Short: "Upgrade the default kubeadm addons",
42+
Long: cmdutil.MacroCommandLongDescription,
43+
Phases: []workflow.Phase{
44+
{
45+
Name: "all",
46+
Short: "Upgrade all the addons",
47+
InheritFlags: getAddonPhaseFlags("all"),
48+
RunAllSiblings: true,
49+
},
50+
{
51+
Name: "coredns",
52+
Short: "Upgrade the CoreDNS addon",
53+
InheritFlags: getAddonPhaseFlags("coredns"),
54+
Run: runCoreDNSAddon,
55+
},
56+
{
57+
Name: "kube-proxy",
58+
Short: "Upgrade the kube-proxy addon",
59+
InheritFlags: getAddonPhaseFlags("kube-proxy"),
60+
Run: runKubeProxyAddon,
61+
},
62+
},
63+
}
64+
}
65+
66+
func shouldUpgradeAddons(client clientset.Interface, cfg *kubeadmapi.InitConfiguration, out io.Writer) (bool, error) {
67+
unupgradedControlPlanes, err := upgrade.UnupgradedControlPlaneInstances(client, cfg.NodeRegistration.Name)
68+
if err != nil {
69+
return false, errors.Wrapf(err, "failed to determine whether all the control plane instances have been upgraded")
70+
}
71+
if len(unupgradedControlPlanes) > 0 {
72+
fmt.Fprintf(out, "[upgrade/addon] Skipping upgrade of addons because control plane instances %v have not been upgraded\n", unupgradedControlPlanes)
73+
return false, nil
74+
}
75+
return true, nil
76+
}
77+
78+
func getInitData(c workflow.RunData) (*kubeadmapi.InitConfiguration, clientset.Interface, string, io.Writer, bool, error) {
79+
data, ok := c.(Data)
80+
if !ok {
81+
return nil, nil, "", nil, false, errors.New("addon phase invoked with an invalid data struct")
82+
}
83+
return data.InitCfg(), data.Client(), data.PatchesDir(), data.OutputWriter(), data.DryRun(), nil
84+
}
85+
86+
// runCoreDNSAddon upgrades the CoreDNS addon.
87+
func runCoreDNSAddon(c workflow.RunData) error {
88+
cfg, client, patchesDir, out, dryRun, err := getInitData(c)
89+
if err != nil {
90+
return err
91+
}
92+
93+
shouldUpgradeAddons, err := shouldUpgradeAddons(client, cfg, out)
94+
if err != nil {
95+
return err
96+
}
97+
if !shouldUpgradeAddons {
98+
return nil
99+
}
100+
101+
// Upgrade CoreDNS
102+
if err := dnsaddon.EnsureDNSAddon(&cfg.ClusterConfiguration, client, patchesDir, out, dryRun); err != nil {
103+
return err
104+
}
105+
106+
return nil
107+
}
108+
109+
// runKubeProxyAddon upgrades the kube-proxy addon.
110+
func runKubeProxyAddon(c workflow.RunData) error {
111+
cfg, client, _, out, dryRun, err := getInitData(c)
112+
if err != nil {
113+
return err
114+
}
115+
116+
shouldUpgradeAddons, err := shouldUpgradeAddons(client, cfg, out)
117+
if err != nil {
118+
return err
119+
}
120+
if !shouldUpgradeAddons {
121+
return nil
122+
}
123+
124+
// Upgrade kube-proxy
125+
if err := proxyaddon.EnsureProxyAddon(&cfg.ClusterConfiguration, &cfg.LocalAPIEndpoint, client, out, dryRun); err != nil {
126+
return err
127+
}
128+
129+
return nil
130+
}
131+
132+
func getAddonPhaseFlags(name string) []string {
133+
flags := []string{
134+
options.CfgPath,
135+
options.KubeconfigPath,
136+
options.DryRun,
137+
}
138+
if name == "all" || name == "coredns" {
139+
flags = append(flags,
140+
options.Patches,
141+
)
142+
}
143+
return flags
144+
}

cmd/kubeadm/app/cmd/phases/upgrade/node/controlplane.go

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17+
// Package node implements phases of 'kubeadm upgrade node'.
1718
package node
1819

1920
import (
@@ -28,13 +29,14 @@ import (
2829
"k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
2930
)
3031

31-
// NewControlPlane creates a kubeadm workflow phase that implements handling of control-plane upgrade.
32+
// NewControlPlane returns a new control-plane phase.
3233
func NewControlPlane() workflow.Phase {
3334
phase := workflow.Phase{
3435
Name: "control-plane",
3536
Short: "Upgrade the control plane instance deployed on this node, if any",
3637
Run: runControlPlane(),
3738
InheritFlags: []string{
39+
options.CfgPath,
3840
options.DryRun,
3941
options.KubeconfigPath,
4042
options.CertificateRenewal,
@@ -54,7 +56,7 @@ func runControlPlane() func(c workflow.RunData) error {
5456

5557
// if this is not a control-plane node, this phase should not be executed
5658
if !data.IsControlPlaneNode() {
57-
fmt.Println("[upgrade] Skipping phase. Not a control plane node.")
59+
fmt.Println("[upgrade/control-plane] Skipping phase. Not a control plane node.")
5860
return nil
5961
}
6062

@@ -67,8 +69,9 @@ func runControlPlane() func(c workflow.RunData) error {
6769
patchesDir := data.PatchesDir()
6870

6971
// Upgrade the control plane and etcd if installed on this node
70-
fmt.Printf("[upgrade] Upgrading your Static Pod-hosted control plane instance to version %q...\n", cfg.KubernetesVersion)
72+
fmt.Printf("[upgrade/control-plane] Upgrading your Static Pod-hosted control plane instance to version %q...\n", cfg.KubernetesVersion)
7173
if dryRun {
74+
fmt.Printf("[dryrun] Would upgrade your static Pod-hosted control plane to version %q", cfg.KubernetesVersion)
7275
return upgrade.DryRunStaticPodUpgrade(patchesDir, cfg)
7376
}
7477

@@ -78,11 +81,7 @@ func runControlPlane() func(c workflow.RunData) error {
7881
return errors.Wrap(err, "couldn't complete the static pod upgrade")
7982
}
8083

81-
if err := upgrade.PerformAddonsUpgrade(client, cfg, data.PatchesDir(), data.OutputWriter()); err != nil {
82-
return errors.Wrap(err, "failed to perform addons upgrade")
83-
}
84-
85-
fmt.Println("[upgrade] The control plane instance for this node was successfully updated!")
84+
fmt.Println("[upgrade/control-plane] The control plane instance for this node was successfully upgraded!")
8685

8786
return nil
8887
}

cmd/kubeadm/app/cmd/phases/upgrade/node/data.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17+
// Package node implements phases of 'kubeadm upgrade node'.
1718
package node
1819

1920
import (

cmd/kubeadm/app/cmd/phases/upgrade/node/kubeconfig.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17-
// Package node holds phases of "kubeadm upgrade node".
17+
// Package node implements phases of 'kubeadm upgrade node'.
1818
package node
1919

2020
import (
@@ -28,14 +28,15 @@ import (
2828
"k8s.io/kubernetes/cmd/kubeadm/app/phases/upgrade"
2929
)
3030

31-
// NewKubeconfigPhase creates a kubeadm workflow phase that implements handling of kubeconfig upgrade.
31+
// NewKubeconfigPhase returns a new kubeconfig phase.
3232
func NewKubeconfigPhase() workflow.Phase {
3333
phase := workflow.Phase{
3434
Name: "kubeconfig",
3535
Short: "Upgrade kubeconfig files for this node",
3636
Run: runKubeconfig(),
3737
Hidden: true,
3838
InheritFlags: []string{
39+
options.CfgPath,
3940
options.DryRun,
4041
options.KubeconfigPath,
4142
},
@@ -50,23 +51,22 @@ func runKubeconfig() func(c workflow.RunData) error {
5051
return errors.New("kubeconfig phase invoked with an invalid data struct")
5152
}
5253

53-
// if this is not a control-plane node, this phase should not be executed
54+
// If this is not a control-plane node, this phase should not be executed.
5455
if !data.IsControlPlaneNode() {
55-
fmt.Println("[upgrade] Skipping phase. Not a control plane node.")
56+
fmt.Println("[upgrade/kubeconfig] Skipping phase. Not a control plane node.")
5657
return nil
5758
}
5859

59-
// otherwise, retrieve all the info required for kubeconfig upgrade
60+
// Otherwise, retrieve all the info required for kubeconfig upgrade.
6061
cfg := data.InitCfg()
61-
dryRun := data.DryRun()
6262

6363
if features.Enabled(cfg.FeatureGates, features.ControlPlaneKubeletLocalMode) {
64-
if err := upgrade.UpdateKubeletLocalMode(cfg, dryRun); err != nil {
64+
if err := upgrade.UpdateKubeletLocalMode(cfg, data.DryRun()); err != nil {
6565
return errors.Wrap(err, "failed to update kubelet local mode")
6666
}
6767
}
6868

69-
fmt.Println("[upgrade] The kubeconfig for this node was successfully updated!")
69+
fmt.Println("[upgrade/kubeconfig] The kubeconfig files for this node were successfully upgraded!")
7070

7171
return nil
7272
}

cmd/kubeadm/app/cmd/phases/upgrade/node/kubeletconfig.go

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,18 +29,19 @@ import (
2929

3030
var (
3131
kubeletConfigLongDesc = cmdutil.LongDesc(`
32-
Download the kubelet configuration from the kubelet-config ConfigMap stored in the cluster
32+
Upgrade the kubelet configuration for this node by downloading it from the kubelet-config ConfigMap stored in the cluster
3333
`)
3434
)
3535

36-
// NewKubeletConfigPhase creates a kubeadm workflow phase that implements handling of kubelet-config upgrade.
36+
// NewKubeletConfigPhase returns a new kubelet-config phase.
3737
func NewKubeletConfigPhase() workflow.Phase {
3838
phase := workflow.Phase{
3939
Name: "kubelet-config",
4040
Short: "Upgrade the kubelet configuration for this node",
4141
Long: kubeletConfigLongDesc,
4242
Run: runKubeletConfigPhase(),
4343
InheritFlags: []string{
44+
options.CfgPath,
4445
options.DryRun,
4546
options.KubeconfigPath,
4647
options.Patches,
@@ -56,20 +57,15 @@ func runKubeletConfigPhase() func(c workflow.RunData) error {
5657
return errors.New("kubelet-config phase invoked with an invalid data struct")
5758
}
5859

59-
// otherwise, retrieve all the info required for kubelet config upgrade
60-
cfg := data.InitCfg()
61-
dryRun := data.DryRun()
62-
6360
// Write the configuration for the kubelet down to disk and print the generated manifests instead if dry-running.
6461
// If not dry-running, the kubelet config file will be backed up to /etc/kubernetes/tmp/ dir, so that it could be
6562
// recovered if there is anything goes wrong.
66-
err := upgrade.WriteKubeletConfigFiles(cfg, data.PatchesDir(), dryRun, data.OutputWriter())
63+
err := upgrade.WriteKubeletConfigFiles(data.InitCfg(), data.PatchesDir(), data.DryRun(), data.OutputWriter())
6764
if err != nil {
6865
return err
6966
}
7067

71-
fmt.Println("[upgrade] The configuration for this node was successfully updated!")
72-
fmt.Println("[upgrade] Now you should go ahead and upgrade the kubelet package using your package manager.")
68+
fmt.Println("[upgrade/kubelet-config] The configuration for this node was successfully upgraded!")
7369
return nil
7470
}
7571
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
Copyright 2024 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
// Package node implements phases of 'kubeadm upgrade node'.
18+
package node
19+
20+
import (
21+
"github.com/pkg/errors"
22+
23+
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
24+
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/workflow"
25+
)
26+
27+
// NewPostUpgradePhase returns a new post-upgrade phase.
28+
func NewPostUpgradePhase() workflow.Phase {
29+
return workflow.Phase{
30+
Name: "post-upgrade",
31+
Short: "Run post upgrade tasks",
32+
Run: runPostUpgrade,
33+
InheritFlags: []string{
34+
options.CfgPath,
35+
options.KubeconfigPath,
36+
options.DryRun,
37+
},
38+
}
39+
}
40+
41+
func runPostUpgrade(c workflow.RunData) error {
42+
_, ok := c.(Data)
43+
if !ok {
44+
return errors.New("post-upgrade phase invoked with an invalid data struct")
45+
}
46+
// PLACEHOLDER: this phase should contain any release specific post-upgrade tasks.
47+
48+
return nil
49+
}

0 commit comments

Comments
 (0)