From abac950cd72101b073e05250b99e3e3c2d067ef8 Mon Sep 17 00:00:00 2001 From: fabriziopandini Date: Thu, 18 Oct 2018 11:52:04 +0200 Subject: [PATCH 1/2] kubeadm graduate preflight phase --- cmd/kubeadm/app/cmd/init.go | 119 ++++++++++++++++++++---- cmd/kubeadm/app/cmd/phases/preflight.go | 94 ++++++++++--------- 2 files changed, 154 insertions(+), 59 deletions(-) diff --git a/cmd/kubeadm/app/cmd/init.go b/cmd/kubeadm/app/cmd/init.go index aa9047fa605..286a64533ce 100644 --- a/cmd/kubeadm/app/cmd/init.go +++ b/cmd/kubeadm/app/cmd/init.go @@ -37,6 +37,7 @@ import ( kubeadmapiv1beta1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta1" "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation" "k8s.io/kubernetes/cmd/kubeadm/app/cmd/options" + "k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases" "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" @@ -126,6 +127,9 @@ type initData struct { skipTokenPrint bool dryRun bool ignorePreflightErrors sets.String + certificatesDir string + dryRunDir string + client clientset.Interface } // NewCmdInit returns "kubeadm init" command. @@ -160,7 +164,8 @@ func NewCmdInit(out io.Writer) *cobra.Command { options.bto.AddTTLFlag(cmd.PersistentFlags()) // initialize the workflow runner with the list of phases - // TODO: add the phases to the runner. e.g. initRunner.AppendPhase(phases.PreflightMaster) + initRunner.AppendPhase(phases.NewPreflightMasterPhase()) + // TODO: add other phases to the runner. // sets the data builder function, that will be used by the runner // both when running the entire workflow or single phases @@ -297,31 +302,113 @@ func newInitData(cmd *cobra.Command, options *initOptions) (initData, error) { return initData{}, err } + // if dry running creates a temporary folder for saving kubeadm generated files + dryRunDir := "" + if options.dryRun { + if dryRunDir, err = ioutil.TempDir("", "kubeadm-init-dryrun"); err != nil { + return initData{}, fmt.Errorf("couldn't create a temporary directory: %v", err) + } + } + return initData{ cfg: cfg, + certificatesDir: cfg.CertificatesDir, skipTokenPrint: options.skipTokenPrint, dryRun: options.dryRun, + dryRunDir: dryRunDir, ignorePreflightErrors: ignorePreflightErrorsSet, }, nil } +// Cfg returns initConfiguration. +func (d initData) Cfg() *kubeadmapi.InitConfiguration { + return d.cfg +} + +// DryRun returns the DryRun flag. +func (d initData) DryRun() bool { + return d.dryRun +} + +// SkipTokenPrint returns the SkipTokenPrint flag. +func (d initData) SkipTokenPrint() bool { + return d.skipTokenPrint +} + +// IgnorePreflightErrors returns the IgnorePreflightErrors flag. +func (d initData) IgnorePreflightErrors() sets.String { + return d.ignorePreflightErrors +} + +// CertificateWriteDir returns the path to the certificate folder or the temporary folder path in case of DryRun. +func (d initData) CertificateWriteDir() string { + if d.dryRun { + return d.dryRunDir + } + return d.certificatesDir +} + +// CertificateDir returns the CertificateDir as originally specified by the user. +func (d initData) CertificateDir() string { + return d.certificatesDir +} + +// KubeConfigDir returns the path of the kubernetes configuration folder or the temporary folder path in case of DryRun. +func (d initData) KubeConfigDir() string { + if d.dryRun { + return d.dryRunDir + } + return kubeadmconstants.KubernetesDir +} + +// KubeConfigDir returns the path where manifest should be stored or the temporary folder path in case of DryRun. +func (d initData) ManifestDir() string { + if d.dryRun { + return d.dryRunDir + } + return kubeadmconstants.GetStaticPodDirectory() +} + +// KubeletDir returns path of the kubelet configuration folder or the temporary folder in case of DryRun. +func (d initData) KubeletDir() string { + if d.dryRun { + return d.dryRunDir + } + return kubeadmconstants.KubeletRunDirectory +} + +// Client returns a Kubernetes client to be used by kubeadm. +// This function is implemented as a singleton, thus avoiding to recreate the client when it is used by different phases. +// Important. This function must be called after the admin.conf kubeconfig file is created. +func (d initData) Client() (clientset.Interface, error) { + if d.client == nil { + if d.dryRun { + // If we're dry-running; we should create a faked client that answers some GETs in order to be able to do the full init flow and just logs the rest of requests + dryRunGetter := apiclient.NewInitDryRunGetter(d.cfg.NodeRegistration.Name, d.cfg.Networking.ServiceSubnet) + d.client = apiclient.NewDryRunClient(dryRunGetter, os.Stdout) + } else { + // If we're acting for real, we should create a connection to the API server and wait for it to come up + var err error + d.client, err = kubeconfigutil.ClientSetFromFile(kubeadmconstants.GetAdminKubeConfigPath()) + if err != nil { + return nil, err + } + } + } + return d.client, nil +} + +// Tokens returns an array of token strings. +func (d initData) Tokens() []string { + tokens := []string{} + for _, bt := range d.cfg.BootstrapTokens { + tokens = append(tokens, bt.Token.String()) + } + return tokens +} + // runInit executes master node provisioning func runInit(i *initData, out io.Writer) error { - fmt.Println("[preflight] running pre-flight checks") - if err := preflight.RunInitMasterChecks(utilsexec.New(), i.cfg, i.ignorePreflightErrors); err != nil { - return err - } - - if !i.dryRun { - fmt.Println("[preflight/images] Pulling images required for setting up a Kubernetes cluster") - fmt.Println("[preflight/images] This might take a minute or two, depending on the speed of your internet connection") - fmt.Println("[preflight/images] You can also perform this action in beforehand using 'kubeadm config images pull'") - if err := preflight.RunPullImagesCheck(utilsexec.New(), i.cfg, i.ignorePreflightErrors); err != nil { - return err - } - } else { - fmt.Println("[preflight/images] Would pull the required images (like 'kubeadm config images pull')") - } // Get directories to write files to; can be faked if we're dry-running glog.V(1).Infof("[init] Getting certificates directory from configuration") diff --git a/cmd/kubeadm/app/cmd/phases/preflight.go b/cmd/kubeadm/app/cmd/phases/preflight.go index 662499b8e33..ac55b9a3796 100644 --- a/cmd/kubeadm/app/cmd/phases/preflight.go +++ b/cmd/kubeadm/app/cmd/phases/preflight.go @@ -21,11 +21,13 @@ import ( "fmt" "github.com/spf13/cobra" - + "k8s.io/apimachinery/pkg/util/sets" + kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" kubeadmscheme "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/scheme" kubeadmapiv1beta1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta1" "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation" "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/preflight" kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util" @@ -35,13 +37,9 @@ import ( ) var ( - masterPreflightLongDesc = normalizer.LongDesc(` - Run master pre-flight checks, functionally equivalent to what implemented by kubeadm init. - ` + cmdutil.AlphaDisclaimer) - masterPreflightExample = normalizer.Examples(` - # Run master pre-flight checks. - kubeadm alpha phase preflight master + # Run master pre-flight checks using a config file. + kubeadm init phase preflight --config kubeadm-config.yml `) nodePreflightLongDesc = normalizer.LongDesc(` @@ -56,6 +54,52 @@ var ( errorMissingConfigFlag = errors.New("the --config flag is mandatory") ) +// preflightMasterData defines the behavior that a runtime data struct passed to the PreflightMaster master phase +// should have. Please note that we are using an interface in order to make this phase reusable in different workflows +// (and thus with different runtime data struct, all of them requested to be compliant to this interface) +type preflightMasterData interface { + Cfg() *kubeadmapi.InitConfiguration + DryRun() bool + IgnorePreflightErrors() sets.String +} + +// NewPreflightMasterPhase creates a kubeadm workflow phase that implements preflight checks for a new master node. +func NewPreflightMasterPhase() workflow.Phase { + return workflow.Phase{ + Name: "preflight", + Short: "Run master pre-flight checks", + Long: "Run master pre-flight checks, functionally equivalent to what implemented by kubeadm init.", + Example: masterPreflightExample, + Run: runPreflightMaster, + } +} + +// runPreflightMaster executes preflight checks logic. +func runPreflightMaster(c workflow.RunData) error { + data, ok := c.(preflightMasterData) + if !ok { + return fmt.Errorf("preflight phase invoked with an invalid data struct") + } + + fmt.Println("[preflight] running pre-flight checks") + if err := preflight.RunInitMasterChecks(utilsexec.New(), data.Cfg(), data.IgnorePreflightErrors()); err != nil { + return nil + } + + if !data.DryRun() { + fmt.Println("[preflight] Pulling images required for setting up a Kubernetes cluster") + fmt.Println("[preflight] This might take a minute or two, depending on the speed of your internet connection") + fmt.Println("[preflight] You can also perform this action in beforehand using 'kubeadm config images pull'") + if err := preflight.RunPullImagesCheck(utilsexec.New(), data.Cfg(), data.IgnorePreflightErrors()); err != nil { + return err + } + } else { + fmt.Println("[preflight] Would pull the required images (like 'kubeadm config images pull')") + } + + return nil +} + // NewCmdPreFlight calls cobra.Command for preflight checks func NewCmdPreFlight() *cobra.Command { var cfgPath string @@ -70,47 +114,11 @@ func NewCmdPreFlight() *cobra.Command { options.AddConfigFlag(cmd.PersistentFlags(), &cfgPath) options.AddIgnorePreflightErrorsFlag(cmd.PersistentFlags(), &ignorePreflightErrors) - cmd.AddCommand(NewCmdPreFlightMaster(&cfgPath, &ignorePreflightErrors)) cmd.AddCommand(NewCmdPreFlightNode(&cfgPath, &ignorePreflightErrors)) return cmd } -// NewCmdPreFlightMaster calls cobra.Command for master preflight checks -func NewCmdPreFlightMaster(cfgPath *string, ignorePreflightErrors *[]string) *cobra.Command { - - cmd := &cobra.Command{ - Use: "master", - Short: "Run master pre-flight checks", - Long: masterPreflightLongDesc, - Example: masterPreflightExample, - Run: func(cmd *cobra.Command, args []string) { - if len(*cfgPath) == 0 { - kubeadmutil.CheckErr(errorMissingConfigFlag) - } - ignorePreflightErrorsSet, err := validation.ValidateIgnorePreflightErrors(*ignorePreflightErrors) - kubeadmutil.CheckErr(err) - - cfg := &kubeadmapiv1beta1.InitConfiguration{} - kubeadmscheme.Scheme.Default(cfg) - - internalcfg, err := configutil.ConfigFileAndDefaultsToInternalConfig(*cfgPath, cfg) - kubeadmutil.CheckErr(err) - err = configutil.VerifyAPIServerBindAddress(internalcfg.APIEndpoint.AdvertiseAddress) - kubeadmutil.CheckErr(err) - - fmt.Println("[preflight] running pre-flight checks") - - err = preflight.RunInitMasterChecks(utilsexec.New(), internalcfg, ignorePreflightErrorsSet) - kubeadmutil.CheckErr(err) - - fmt.Println("[preflight] pre-flight checks passed") - }, - } - - return cmd -} - // NewCmdPreFlightNode calls cobra.Command for node preflight checks func NewCmdPreFlightNode(cfgPath *string, ignorePreflightErrors *[]string) *cobra.Command { cmd := &cobra.Command{ From 22da6a66a22e8a2c017cbdca6211c6b6439bd023 Mon Sep 17 00:00:00 2001 From: fabriziopandini Date: Thu, 18 Oct 2018 11:52:15 +0200 Subject: [PATCH 2/2] autogenerated --- cmd/kubeadm/app/cmd/phases/BUILD | 2 ++ docs/.generated_docs | 6 ++++-- ...lpha_phase_preflight_master.md => kubeadm_init_phase.md} | 0 .../kubeadm_init_phase_preflight.md} | 0 docs/man/man1/kubeadm-init-phase-preflight.1 | 3 +++ docs/man/man1/kubeadm-init-phase.1 | 3 +++ 6 files changed, 12 insertions(+), 2 deletions(-) rename docs/admin/{kubeadm_alpha_phase_preflight_master.md => kubeadm_init_phase.md} (100%) rename docs/{man/man1/kubeadm-alpha-phase-preflight-master.1 => admin/kubeadm_init_phase_preflight.md} (100%) create mode 100644 docs/man/man1/kubeadm-init-phase-preflight.1 create mode 100644 docs/man/man1/kubeadm-init-phase.1 diff --git a/cmd/kubeadm/app/cmd/phases/BUILD b/cmd/kubeadm/app/cmd/phases/BUILD index bed47649f9f..24def1c2889 100644 --- a/cmd/kubeadm/app/cmd/phases/BUILD +++ b/cmd/kubeadm/app/cmd/phases/BUILD @@ -26,6 +26,7 @@ go_library( "//cmd/kubeadm/app/apis/kubeadm/validation:go_default_library", "//cmd/kubeadm/app/cmd/options:go_default_library", "//cmd/kubeadm/app/cmd/phases/certs:go_default_library", + "//cmd/kubeadm/app/cmd/phases/workflow:go_default_library", "//cmd/kubeadm/app/cmd/util:go_default_library", "//cmd/kubeadm/app/constants:go_default_library", "//cmd/kubeadm/app/features:go_default_library", @@ -50,6 +51,7 @@ go_library( "//pkg/util/normalizer:go_default_library", "//pkg/version:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/version:go_default_library", "//staging/src/k8s.io/apiserver/pkg/util/flag:go_default_library", "//staging/src/k8s.io/client-go/kubernetes:go_default_library", diff --git a/docs/.generated_docs b/docs/.generated_docs index 294c91fd39f..e67c3285186 100644 --- a/docs/.generated_docs +++ b/docs/.generated_docs @@ -64,7 +64,6 @@ docs/admin/kubeadm_alpha_phase_kubelet_config_write-to-disk.md docs/admin/kubeadm_alpha_phase_kubelet_write-env-file.md docs/admin/kubeadm_alpha_phase_mark-master.md docs/admin/kubeadm_alpha_phase_preflight.md -docs/admin/kubeadm_alpha_phase_preflight_master.md docs/admin/kubeadm_alpha_phase_preflight_node.md docs/admin/kubeadm_alpha_phase_selfhosting.md docs/admin/kubeadm_alpha_phase_selfhosting_convert-from-staticpods.md @@ -81,6 +80,8 @@ docs/admin/kubeadm_config_upload_from-file.md docs/admin/kubeadm_config_upload_from-flags.md docs/admin/kubeadm_config_view.md docs/admin/kubeadm_init.md +docs/admin/kubeadm_init_phase.md +docs/admin/kubeadm_init_phase_preflight.md docs/admin/kubeadm_join.md docs/admin/kubeadm_reset.md docs/admin/kubeadm_token.md @@ -158,7 +159,6 @@ docs/man/man1/kubeadm-alpha-phase-kubelet-config.1 docs/man/man1/kubeadm-alpha-phase-kubelet-write-env-file.1 docs/man/man1/kubeadm-alpha-phase-kubelet.1 docs/man/man1/kubeadm-alpha-phase-mark-master.1 -docs/man/man1/kubeadm-alpha-phase-preflight-master.1 docs/man/man1/kubeadm-alpha-phase-preflight-node.1 docs/man/man1/kubeadm-alpha-phase-preflight.1 docs/man/man1/kubeadm-alpha-phase-selfhosting-convert-from-staticpods.1 @@ -177,6 +177,8 @@ docs/man/man1/kubeadm-config-upload-from-flags.1 docs/man/man1/kubeadm-config-upload.1 docs/man/man1/kubeadm-config-view.1 docs/man/man1/kubeadm-config.1 +docs/man/man1/kubeadm-init-phase-preflight.1 +docs/man/man1/kubeadm-init-phase.1 docs/man/man1/kubeadm-init.1 docs/man/man1/kubeadm-join.1 docs/man/man1/kubeadm-reset.1 diff --git a/docs/admin/kubeadm_alpha_phase_preflight_master.md b/docs/admin/kubeadm_init_phase.md similarity index 100% rename from docs/admin/kubeadm_alpha_phase_preflight_master.md rename to docs/admin/kubeadm_init_phase.md diff --git a/docs/man/man1/kubeadm-alpha-phase-preflight-master.1 b/docs/admin/kubeadm_init_phase_preflight.md similarity index 100% rename from docs/man/man1/kubeadm-alpha-phase-preflight-master.1 rename to docs/admin/kubeadm_init_phase_preflight.md diff --git a/docs/man/man1/kubeadm-init-phase-preflight.1 b/docs/man/man1/kubeadm-init-phase-preflight.1 new file mode 100644 index 00000000000..b6fd7a0f989 --- /dev/null +++ b/docs/man/man1/kubeadm-init-phase-preflight.1 @@ -0,0 +1,3 @@ +This file is autogenerated, but we've stopped checking such files into the +repository to reduce the need for rebases. Please run hack/generate-docs.sh to +populate this file. diff --git a/docs/man/man1/kubeadm-init-phase.1 b/docs/man/man1/kubeadm-init-phase.1 new file mode 100644 index 00000000000..b6fd7a0f989 --- /dev/null +++ b/docs/man/man1/kubeadm-init-phase.1 @@ -0,0 +1,3 @@ +This file is autogenerated, but we've stopped checking such files into the +repository to reduce the need for rebases. Please run hack/generate-docs.sh to +populate this file.