node.go 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. /*
  2. Copyright 2018 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package upgrade
  14. import (
  15. "os"
  16. "github.com/pkg/errors"
  17. "github.com/spf13/cobra"
  18. flag "github.com/spf13/pflag"
  19. clientset "k8s.io/client-go/kubernetes"
  20. kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
  21. "k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
  22. phases "k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/upgrade/node"
  23. "k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/workflow"
  24. "k8s.io/kubernetes/cmd/kubeadm/app/constants"
  25. configutil "k8s.io/kubernetes/cmd/kubeadm/app/util/config"
  26. )
  27. // nodeOptions defines all the options exposed via flags by kubeadm upgrade node.
  28. // Please note that this structure includes the public kubeadm config API, but only a subset of the options
  29. // supported by this api will be exposed as a flag.
  30. type nodeOptions struct {
  31. kubeConfigPath string
  32. kubeletVersion string
  33. etcdUpgrade bool
  34. renewCerts bool
  35. dryRun bool
  36. kustomizeDir string
  37. }
  38. // compile-time assert that the local data object satisfies the phases data interface.
  39. var _ phases.Data = &nodeData{}
  40. // nodeData defines all the runtime information used when running the kubeadm upgrade node worklow;
  41. // this data is shared across all the phases that are included in the workflow.
  42. type nodeData struct {
  43. etcdUpgrade bool
  44. renewCerts bool
  45. dryRun bool
  46. kubeletVersion string
  47. cfg *kubeadmapi.InitConfiguration
  48. isControlPlaneNode bool
  49. client clientset.Interface
  50. kustomizeDir string
  51. }
  52. // NewCmdNode returns the cobra command for `kubeadm upgrade node`
  53. func NewCmdNode() *cobra.Command {
  54. nodeOptions := newNodeOptions()
  55. nodeRunner := workflow.NewRunner()
  56. cmd := &cobra.Command{
  57. Use: "node",
  58. Short: "Upgrade commands for a node in the cluster",
  59. RunE: func(cmd *cobra.Command, args []string) error {
  60. return nodeRunner.Run(args)
  61. },
  62. Args: cobra.NoArgs,
  63. }
  64. // adds flags to the node command
  65. // flags could be eventually inherited by the sub-commands automatically generated for phases
  66. addUpgradeNodeFlags(cmd.Flags(), nodeOptions)
  67. options.AddKustomizePodsFlag(cmd.Flags(), &nodeOptions.kustomizeDir)
  68. // initialize the workflow runner with the list of phases
  69. nodeRunner.AppendPhase(phases.NewControlPlane())
  70. nodeRunner.AppendPhase(phases.NewKubeletConfigPhase())
  71. // sets the data builder function, that will be used by the runner
  72. // both when running the entire workflow or single phases
  73. nodeRunner.SetDataInitializer(func(cmd *cobra.Command, args []string) (workflow.RunData, error) {
  74. return newNodeData(cmd, args, nodeOptions)
  75. })
  76. // binds the Runner to kubeadm upgrade node command by altering
  77. // command help, adding --skip-phases flag and by adding phases subcommands
  78. nodeRunner.BindToCommand(cmd)
  79. return cmd
  80. }
  81. // newNodeOptions returns a struct ready for being used for creating cmd kubeadm upgrade node flags.
  82. func newNodeOptions() *nodeOptions {
  83. return &nodeOptions{
  84. kubeConfigPath: constants.GetKubeletKubeConfigPath(),
  85. dryRun: false,
  86. renewCerts: true,
  87. etcdUpgrade: true,
  88. }
  89. }
  90. func addUpgradeNodeFlags(flagSet *flag.FlagSet, nodeOptions *nodeOptions) {
  91. options.AddKubeConfigFlag(flagSet, &nodeOptions.kubeConfigPath)
  92. flagSet.BoolVar(&nodeOptions.dryRun, options.DryRun, nodeOptions.dryRun, "Do not change any state, just output the actions that would be performed.")
  93. flagSet.StringVar(&nodeOptions.kubeletVersion, options.KubeletVersion, nodeOptions.kubeletVersion, "The *desired* version for the kubelet config after the upgrade. If not specified, the KubernetesVersion from the kubeadm-config ConfigMap will be used")
  94. flagSet.MarkDeprecated(options.KubeletVersion, "This flag is deprecated and will be removed in a future version.")
  95. flagSet.BoolVar(&nodeOptions.renewCerts, options.CertificateRenewal, nodeOptions.renewCerts, "Perform the renewal of certificates used by component changed during upgrades.")
  96. flagSet.BoolVar(&nodeOptions.etcdUpgrade, options.EtcdUpgrade, nodeOptions.etcdUpgrade, "Perform the upgrade of etcd.")
  97. }
  98. // newNodeData returns a new nodeData struct to be used for the execution of the kubeadm upgrade node workflow.
  99. // This func takes care of validating nodeOptions passed to the command, and then it converts
  100. // options into the internal InitConfiguration type that is used as input all the phases in the kubeadm upgrade node workflow
  101. func newNodeData(cmd *cobra.Command, args []string, options *nodeOptions) (*nodeData, error) {
  102. client, err := getClient(options.kubeConfigPath, options.dryRun)
  103. if err != nil {
  104. return nil, errors.Wrapf(err, "couldn't create a Kubernetes client from file %q", options.kubeConfigPath)
  105. }
  106. // isControlPlane checks if a node is a control-plane node by looking up
  107. // the kube-apiserver manifest file
  108. isControlPlaneNode := true
  109. filepath := constants.GetStaticPodFilepath(constants.KubeAPIServer, constants.GetStaticPodDirectory())
  110. if _, err := os.Stat(filepath); os.IsNotExist(err) {
  111. isControlPlaneNode = false
  112. }
  113. // Fetches the cluster configuration
  114. // NB in case of control-plane node, we are reading all the info for the node; in case of NOT control-plane node
  115. // (worker node), we are not reading local API address and the CRI socket from the node object
  116. cfg, err := configutil.FetchInitConfigurationFromCluster(client, os.Stdout, "upgrade", !isControlPlaneNode)
  117. if err != nil {
  118. return nil, errors.Wrap(err, "unable to fetch the kubeadm-config ConfigMap")
  119. }
  120. return &nodeData{
  121. etcdUpgrade: options.etcdUpgrade,
  122. renewCerts: options.renewCerts,
  123. dryRun: options.dryRun,
  124. kubeletVersion: options.kubeletVersion,
  125. cfg: cfg,
  126. client: client,
  127. isControlPlaneNode: isControlPlaneNode,
  128. kustomizeDir: options.kustomizeDir,
  129. }, nil
  130. }
  131. // DryRun returns the dryRun flag.
  132. func (d *nodeData) DryRun() bool {
  133. return d.dryRun
  134. }
  135. // EtcdUpgrade returns the etcdUpgrade flag.
  136. func (d *nodeData) EtcdUpgrade() bool {
  137. return d.etcdUpgrade
  138. }
  139. // RenewCerts returns the renewCerts flag.
  140. func (d *nodeData) RenewCerts() bool {
  141. return d.renewCerts
  142. }
  143. // KubeletVersion returns the kubeletVersion flag.
  144. func (d *nodeData) KubeletVersion() string {
  145. return d.kubeletVersion
  146. }
  147. // Cfg returns initConfiguration.
  148. func (d *nodeData) Cfg() *kubeadmapi.InitConfiguration {
  149. return d.cfg
  150. }
  151. // IsControlPlaneNode returns the isControlPlaneNode flag.
  152. func (d *nodeData) IsControlPlaneNode() bool {
  153. return d.isControlPlaneNode
  154. }
  155. // Client returns a Kubernetes client to be used by kubeadm.
  156. func (d *nodeData) Client() clientset.Interface {
  157. return d.client
  158. }
  159. // KustomizeDir returns the folder where kustomize patches for static pod manifest are stored
  160. func (d *nodeData) KustomizeDir() string {
  161. return d.kustomizeDir
  162. }