Skip to content

Commit

Permalink
kubeadm graduate upload-config phase
Browse files Browse the repository at this point in the history
  • Loading branch information
yagonobre committed Nov 6, 2018
1 parent c2aa358 commit 79f1b66
Show file tree
Hide file tree
Showing 13 changed files with 119 additions and 189 deletions.
1 change: 0 additions & 1 deletion cmd/kubeadm/app/cmd/alpha/alpha.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ func newCmdPhase(out io.Writer) *cobra.Command {
cmd.AddCommand(phases.NewCmdBootstrapToken())
cmd.AddCommand(phases.NewCmdMarkMaster())
cmd.AddCommand(phases.NewCmdSelfhosting())
cmd.AddCommand(phases.NewCmdUploadConfig())

return cmd
}
21 changes: 1 addition & 20 deletions cmd/kubeadm/app/cmd/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,7 @@ import (
kubeconfigphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig"
kubeletphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/kubelet"
markmasterphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/markmaster"
patchnodephase "k8s.io/kubernetes/cmd/kubeadm/app/phases/patchnode"
selfhostingphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/selfhosting"
uploadconfigphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/uploadconfig"
"k8s.io/kubernetes/cmd/kubeadm/app/preflight"
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
"k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
Expand Down Expand Up @@ -183,6 +181,7 @@ func NewCmdInit(out io.Writer) *cobra.Command {
initRunner.AppendPhase(phases.NewControlPlanePhase())
initRunner.AppendPhase(phases.NewEtcdPhase())
initRunner.AppendPhase(phases.NewWaitControlPlanePhase())
initRunner.AppendPhase(phases.NewUploadConfigPhase())
// TODO: add other phases to the runner.

// sets the data builder function, that will be used by the runner
Expand Down Expand Up @@ -487,30 +486,12 @@ func runInit(i *initData, out io.Writer) error {
return errors.Wrap(err, "failed to create waiter")
}

// Upload currently used configuration to the cluster
// Note: This is done right in the beginning of cluster initialization; as we might want to make other phases
// depend on centralized information from this source in the future
glog.V(1).Infof("[init] uploading currently used configuration to the cluster")
if err := uploadconfigphase.UploadConfiguration(i.cfg, client); err != nil {
return errors.Wrap(err, "error uploading configuration")
}

glog.V(1).Infof("[init] creating kubelet configuration configmap")
if err := kubeletphase.CreateConfigMap(i.cfg, client); err != nil {
return errors.Wrap(err, "error creating kubelet configuration ConfigMap")
}

// PHASE 4: Mark the master with the right label/taint
glog.V(1).Infof("[init] marking the master with right label")
if err := markmasterphase.MarkMaster(client, i.cfg.NodeRegistration.Name, i.cfg.NodeRegistration.Taints); err != nil {
return errors.Wrap(err, "error marking master")
}

glog.V(1).Infof("[init] preserving the crisocket information for the master")
if err := patchnodephase.AnnotateCRISocket(client, i.cfg.NodeRegistration.Name, i.cfg.NodeRegistration.CRISocket); err != nil {
return errors.Wrap(err, "error uploading crisocket")
}

// This feature is disabled by default
if features.Enabled(i.cfg.FeatureGates, features.DynamicKubeletConfig) {
kubeletVersion, err := preflight.GetKubeletVersion(utilsexec.New())
Expand Down
127 changes: 0 additions & 127 deletions cmd/kubeadm/app/cmd/phases/kubelet.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,10 @@ package phases
import (
"github.com/golang/glog"
"github.com/pkg/errors"
"github.com/spf13/cobra"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
kubeadmapiv1beta1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta1"
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/workflow"
cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util"
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
kubeletphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/kubelet"
patchnodephase "k8s.io/kubernetes/cmd/kubeadm/app/phases/patchnode"
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
configutil "k8s.io/kubernetes/cmd/kubeadm/app/util/config"
kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig"
"k8s.io/kubernetes/pkg/util/normalizer"
)

Expand All @@ -39,24 +31,6 @@ var (
# Writes a dynamic environment file with kubelet flags from a InitConfiguration file.
kubeadm init phase kubelet-start --config masterconfig.yaml
`)

kubeletConfigUploadLongDesc = normalizer.LongDesc(`
Uploads kubelet configuration extracted from the kubeadm InitConfiguration object to a ConfigMap
of the form kubelet-config-1.X in the cluster, where X is the minor version of the current (API Server) Kubernetes version.
` + cmdutil.AlphaDisclaimer)

kubeletConfigUploadExample = normalizer.Examples(`
# Uploads the kubelet configuration from the kubeadm Config file to a ConfigMap in the cluster.
kubeadm alpha phase kubelet config upload --config kubeadm.yaml
`)

kubeletConfigAnnotateCRILongDesc = normalizer.LongDesc(`
Adds an annotation to the current node with the CRI socket specified in the kubeadm InitConfiguration object.
` + cmdutil.AlphaDisclaimer)

kubeletConfigAnnotateCRIExample = normalizer.Examples(`
kubeadm alpha phase kubelet config annotate-cri --config kubeadm.yaml
`)
)

// kubeletStartData defines the behavior that a runtime data struct passed to the kubelet start phase
Expand Down Expand Up @@ -118,104 +92,3 @@ func runKubeletStart(c workflow.RunData) error {

return nil
}

// NewCmdKubelet returns command for `kubeadm phase kubelet`
func NewCmdKubelet() *cobra.Command {
cmd := &cobra.Command{
Use: "kubelet",
Short: "Commands related to handling the kubelet.",
Long: cmdutil.MacroCommandLongDescription,
}

cmd.AddCommand(NewCmdKubeletConfig())
return cmd
}

// NewCmdKubeletConfig returns command for `kubeadm phase kubelet config`
func NewCmdKubeletConfig() *cobra.Command {
cmd := &cobra.Command{
Use: "config",
Short: "Handles kubelet configuration.",
Long: cmdutil.MacroCommandLongDescription,
}

cmd.AddCommand(NewCmdKubeletConfigUpload())
cmd.AddCommand(NewCmdKubeletAnnotateCRI())
return cmd
}

// NewCmdKubeletConfigUpload calls cobra.Command for uploading dynamic kubelet configuration
func NewCmdKubeletConfigUpload() *cobra.Command {
cfg := &kubeadmapiv1beta1.InitConfiguration{}
var cfgPath string
kubeConfigFile := constants.GetAdminKubeConfigPath()

cmd := &cobra.Command{
Use: "upload",
Short: "Uploads kubelet configuration to a ConfigMap based on a kubeadm InitConfiguration file.",
Long: kubeletConfigUploadLongDesc,
Example: kubeletConfigUploadExample,
Run: func(cmd *cobra.Command, args []string) {
if len(cfgPath) == 0 {
kubeadmutil.CheckErr(errors.New("The --config argument is required"))
}

// KubernetesVersion is not used, but we set it explicitly to avoid the lookup
// of the version from the internet when executing ConfigFileAndDefaultsToInternalConfig
SetKubernetesVersion(cfg)

// This call returns the ready-to-use configuration based on the configuration file
internalcfg, err := configutil.ConfigFileAndDefaultsToInternalConfig(cfgPath, cfg)
kubeadmutil.CheckErr(err)

kubeConfigFile = cmdutil.FindExistingKubeConfig(kubeConfigFile)
client, err := kubeconfigutil.ClientSetFromFile(kubeConfigFile)
kubeadmutil.CheckErr(err)

err = kubeletphase.CreateConfigMap(internalcfg, client)
kubeadmutil.CheckErr(err)
},
}

options.AddKubeConfigFlag(cmd.Flags(), &kubeConfigFile)
options.AddConfigFlag(cmd.Flags(), &cfgPath)
return cmd
}

// NewCmdKubeletAnnotateCRI calls cobra.Command for annotating the node with the given crisocket
func NewCmdKubeletAnnotateCRI() *cobra.Command {
cfg := &kubeadmapiv1beta1.InitConfiguration{}
var cfgPath string
kubeConfigFile := constants.GetAdminKubeConfigPath()

cmd := &cobra.Command{
Use: "annotate-cri",
Short: "annotates the node with the given crisocket",
Long: kubeletConfigAnnotateCRILongDesc,
Example: kubeletConfigAnnotateCRIExample,
Run: func(cmd *cobra.Command, args []string) {
if len(cfgPath) == 0 {
kubeadmutil.CheckErr(errors.New("The --config argument is required"))
}

// KubernetesVersion is not used, but we set it explicitly to avoid the lookup
// of the version from the internet when executing ConfigFileAndDefaultsToInternalConfig
SetKubernetesVersion(cfg)

// This call returns the ready-to-use configuration based on the configuration file
internalcfg, err := configutil.ConfigFileAndDefaultsToInternalConfig(cfgPath, cfg)
kubeadmutil.CheckErr(err)

kubeConfigFile = cmdutil.FindExistingKubeConfig(kubeConfigFile)
client, err := kubeconfigutil.ClientSetFromFile(kubeConfigFile)
kubeadmutil.CheckErr(err)

err = patchnodephase.AnnotateCRISocket(client, internalcfg.NodeRegistration.Name, internalcfg.NodeRegistration.CRISocket)
kubeadmutil.CheckErr(err)
},
}

options.AddKubeConfigFlag(cmd.Flags(), &kubeConfigFile)
options.AddConfigFlag(cmd.Flags(), &cfgPath)
return cmd
}
135 changes: 96 additions & 39 deletions cmd/kubeadm/app/cmd/phases/uploadconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,70 +19,127 @@ package phases
import (
"fmt"

"github.com/golang/glog"
"github.com/pkg/errors"
"github.com/spf13/cobra"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
kubeadmapiv1beta1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta1"
clientset "k8s.io/client-go/kubernetes"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/workflow"
cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util"
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
kubeletphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/kubelet"
patchnodephase "k8s.io/kubernetes/cmd/kubeadm/app/phases/patchnode"
"k8s.io/kubernetes/cmd/kubeadm/app/phases/uploadconfig"
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
configutil "k8s.io/kubernetes/cmd/kubeadm/app/util/config"
kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig"
"k8s.io/kubernetes/pkg/util/normalizer"
)

var (
uploadConfigLongDesc = fmt.Sprintf(normalizer.LongDesc(`
Uploads the kubeadm init configuration of your cluster to a ConfigMap called %s in the %s namespace.
uploadKubeadmConfigLongDesc = fmt.Sprintf(normalizer.LongDesc(`
Uploads the kubeadm ClusterConfiguration to a ConfigMap called %s in the %s namespace.
This enables correct configuration of system components and a seamless user experience when upgrading.
Alternatively, you can use kubeadm config.
`+cmdutil.AlphaDisclaimer), kubeadmconstants.KubeadmConfigConfigMap, metav1.NamespaceSystem)
`), kubeadmconstants.KubeadmConfigConfigMap, metav1.NamespaceSystem)

uploadConfigExample = normalizer.Examples(`
uploadKubeadmConfigExample = normalizer.Examples(`
# uploads the configuration of your cluster
kubeadm alpha phase upload-config --config=myConfig.yaml
`)

uploadKubeletConfigLongDesc = normalizer.LongDesc(`
Uploads kubelet configuration extracted from the kubeadm InitConfiguration object to a ConfigMap
of the form kubelet-config-1.X in the cluster, where X is the minor version of the current (API Server) Kubernetes version.
`)

uploadKubeletConfigExample = normalizer.Examples(`
# Uploads the kubelet configuration from the kubeadm Config file to a ConfigMap in the cluster.
kubeadm init phase upload-config kubelet --config kubeadm.yaml
`)
)

// NewCmdUploadConfig returns the Cobra command for running the uploadconfig phase
func NewCmdUploadConfig() *cobra.Command {
cfg := &kubeadmapiv1beta1.InitConfiguration{}
kubeConfigFile := kubeadmconstants.GetAdminKubeConfigPath()
var cfgPath string

cmd := &cobra.Command{
Use: "upload-config",
Short: "Uploads the currently used configuration for kubeadm to a ConfigMap",
Long: uploadConfigLongDesc,
Example: uploadConfigExample,
type uploadConfigData interface {
Cfg() *kubeadmapi.InitConfiguration
Client() (clientset.Interface, error)
}

// NewUploadConfigPhase returns the phase to uploadConfig
func NewUploadConfigPhase() workflow.Phase {
return workflow.Phase{
Name: "upload-config",
Aliases: []string{"uploadconfig"},
Run: func(_ *cobra.Command, args []string) {
if len(cfgPath) == 0 {
kubeadmutil.CheckErr(errors.New("the --config flag is mandatory"))
}
Short: "Uploads the kubeadm and kubelet configuration to a ConfigMap",
Long: cmdutil.MacroCommandLongDescription,
Phases: []workflow.Phase{
{
Name: "kubeadm",
Short: "Uploads the kubeadm ClusterConfiguration to a ConfigMap",
Long: uploadKubeadmConfigLongDesc,
Example: uploadKubeadmConfigExample,
Run: runUploadKubeadmConfig,
CmdFlags: getUploadConfigPhaseFlags(),
},
{
Name: "kubelet",
Short: "Uploads the kubelet component config to a ConfigMap",
Long: uploadKubeletConfigLongDesc,
Example: uploadKubeletConfigExample,
Run: runUploadKubeletConfig,
CmdFlags: getUploadConfigPhaseFlags(),
},
},
}
}

func getUploadConfigPhaseFlags() []string {
return []string{
options.CfgPath,
options.KubeconfigPath,
}
}

kubeConfigFile = cmdutil.FindExistingKubeConfig(kubeConfigFile)
client, err := kubeconfigutil.ClientSetFromFile(kubeConfigFile)
kubeadmutil.CheckErr(err)
// runUploadKubeadmConfig uploads the kubeadm configuration to a ConfigMap
func runUploadKubeadmConfig(c workflow.RunData) error {
cfg, client, err := getUploadConfigData(c)
if err != nil {
return err
}

// KubernetesVersion is not used, but we set it explicitly to avoid the lookup
// of the version from the internet when executing ConfigFileAndDefaultsToInternalConfig
SetKubernetesVersion(cfg)
glog.V(1).Infof("[upload-config] Uploading the kubeadm ClusterConfiguration to a ConfigMap")
if err := uploadconfig.UploadConfiguration(cfg, client); err != nil {
return errors.Wrap(err, "error uploading the kubeadm ClusterConfiguration")
}
return nil
}

internalcfg, err := configutil.ConfigFileAndDefaultsToInternalConfig(cfgPath, cfg)
kubeadmutil.CheckErr(err)
// runUploadKubeletConfig uploads the kubelet configuration to a ConfigMap
func runUploadKubeletConfig(c workflow.RunData) error {
cfg, client, err := getUploadConfigData(c)
if err != nil {
return err
}

err = uploadconfig.UploadConfiguration(internalcfg, client)
kubeadmutil.CheckErr(err)
},
glog.V(1).Infof("[upload-config] Uploading the kubelet component config to a ConfigMap")
if err = kubeletphase.CreateConfigMap(cfg, client); err != nil {
return errors.Wrap(err, "error creating kubelet configuration ConfigMap")
}

options.AddKubeConfigFlag(cmd.Flags(), &kubeConfigFile)
cmd.Flags().StringVar(&cfgPath, "config", "", "Path to a kubeadm config file. WARNING: Usage of a configuration file is experimental")
glog.V(1).Infof("[upload-config] Preserving the CRISocket information for the control-plane node")
if err := patchnodephase.AnnotateCRISocket(client, cfg.NodeRegistration.Name, cfg.NodeRegistration.CRISocket); err != nil {
return errors.Wrap(err, "Error writing Crisocket information for the control-plane node")
}
return nil
}

return cmd
func getUploadConfigData(c workflow.RunData) (*kubeadmapi.InitConfiguration, clientset.Interface, error) {
data, ok := c.(uploadConfigData)
if !ok {
return nil, nil, errors.New("upload-config phase invoked with an invalid data struct")
}
cfg := data.Cfg()
client, err := data.Client()
if err != nil {
return nil, nil, err
}
return cfg, client, err
}
3 changes: 3 additions & 0 deletions cmd/kubeadm/app/cmd/phases/workflow/phase.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ type Phase struct {
// the same workflow or phases belonging to the same parent phase).
Name string

// Aliases returns the aliases for the phase.
Aliases []string

// Short description of the phase.
Short string

Expand Down
1 change: 1 addition & 0 deletions cmd/kubeadm/app/cmd/phases/workflow/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,7 @@ func (e *Runner) BindToCommand(cmd *cobra.Command) {
Short: p.Short,
Long: p.Long,
Example: p.Example,
Aliases: p.Aliases,
Run: func(cmd *cobra.Command, args []string) {
e.Options.FilterPhases = []string{p.generatedName}
if err := e.Run(); err != nil {
Expand Down
Loading

0 comments on commit 79f1b66

Please sign in to comment.