mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-25 20:53:33 +00:00
Merge pull request #69622 from fabriziopandini/kubeadm-add-phase-runner
kubeadm refactor cmd init
This commit is contained in:
commit
d169696b2e
@ -27,6 +27,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:go_default_library",
|
||||
"//cmd/kubeadm/app/cmd/phases/workflow:go_default_library",
|
||||
"//cmd/kubeadm/app/cmd/upgrade:go_default_library",
|
||||
"//cmd/kubeadm/app/cmd/util:go_default_library",
|
||||
"//cmd/kubeadm/app/componentconfigs:go_default_library",
|
||||
|
@ -30,7 +30,6 @@ import (
|
||||
"github.com/renstrom/dedent"
|
||||
"github.com/spf13/cobra"
|
||||
flag "github.com/spf13/pflag"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
@ -38,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/workflow"
|
||||
cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util"
|
||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/features"
|
||||
@ -106,48 +106,71 @@ var (
|
||||
`)))
|
||||
)
|
||||
|
||||
// initOptions defines all the init options exposed via flags by kubeadm init.
|
||||
// Please note that this structure includes the public kubeadm config API, but only a subset of the options
|
||||
// supported by this api will be exposed as a flag.
|
||||
type initOptions struct {
|
||||
cfgPath string
|
||||
skipTokenPrint bool
|
||||
dryRun bool
|
||||
featureGatesString string
|
||||
ignorePreflightErrors []string
|
||||
bto *options.BootstrapTokenOptions
|
||||
externalcfg *kubeadmapiv1beta1.InitConfiguration
|
||||
}
|
||||
|
||||
// initData defines all the runtime information used when running the kubeadm init worklow;
|
||||
// this data is shared across all the phases that are included in the workflow.
|
||||
type initData struct {
|
||||
cfg *kubeadmapi.InitConfiguration
|
||||
skipTokenPrint bool
|
||||
dryRun bool
|
||||
ignorePreflightErrors sets.String
|
||||
}
|
||||
|
||||
// NewCmdInit returns "kubeadm init" command.
|
||||
func NewCmdInit(out io.Writer) *cobra.Command {
|
||||
externalcfg := &kubeadmapiv1beta1.InitConfiguration{}
|
||||
kubeadmscheme.Scheme.Default(externalcfg)
|
||||
|
||||
var cfgPath string
|
||||
var skipTokenPrint bool
|
||||
var dryRun bool
|
||||
var featureGatesString string
|
||||
var ignorePreflightErrors []string
|
||||
// Create the options object for the bootstrap token-related flags, and override the default value for .Description
|
||||
bto := options.NewBootstrapTokenOptions()
|
||||
bto.Description = "The default bootstrap token generated by 'kubeadm init'."
|
||||
options := newInitOptions()
|
||||
initRunner := workflow.NewRunner()
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "init",
|
||||
Short: "Run this command in order to set up the Kubernetes master.",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
var err error
|
||||
if externalcfg.FeatureGates, err = features.NewFeatureGate(&features.InitFeatureGates, featureGatesString); err != nil {
|
||||
kubeadmutil.CheckErr(err)
|
||||
}
|
||||
|
||||
ignorePreflightErrorsSet, err := validation.ValidateIgnorePreflightErrors(ignorePreflightErrors)
|
||||
c, err := initRunner.InitData()
|
||||
kubeadmutil.CheckErr(err)
|
||||
|
||||
err = validation.ValidateMixedArguments(cmd.Flags())
|
||||
data := c.(initData)
|
||||
fmt.Printf("[init] using Kubernetes version: %s\n", data.cfg.KubernetesVersion)
|
||||
|
||||
err = initRunner.Run()
|
||||
kubeadmutil.CheckErr(err)
|
||||
|
||||
err = bto.ApplyTo(externalcfg)
|
||||
// TODO: the code in runInit should be progressively converted in phases; each phase will be exposed
|
||||
// via the subcommands automatically created by initRunner.BindToCommand
|
||||
err = runInit(&data, out)
|
||||
kubeadmutil.CheckErr(err)
|
||||
|
||||
i, err := NewInit(cfgPath, externalcfg, ignorePreflightErrorsSet, skipTokenPrint, dryRun)
|
||||
kubeadmutil.CheckErr(err)
|
||||
kubeadmutil.CheckErr(i.Run(out))
|
||||
},
|
||||
}
|
||||
|
||||
AddInitConfigFlags(cmd.PersistentFlags(), externalcfg, &featureGatesString)
|
||||
AddInitOtherFlags(cmd.PersistentFlags(), &cfgPath, &skipTokenPrint, &dryRun, &ignorePreflightErrors)
|
||||
bto.AddTokenFlag(cmd.PersistentFlags())
|
||||
bto.AddTTLFlag(cmd.PersistentFlags())
|
||||
// adds command flags
|
||||
AddInitConfigFlags(cmd.PersistentFlags(), options.externalcfg, &options.featureGatesString)
|
||||
AddInitOtherFlags(cmd.PersistentFlags(), &options.cfgPath, &options.skipTokenPrint, &options.dryRun, &options.ignorePreflightErrors)
|
||||
options.bto.AddTokenFlag(cmd.PersistentFlags())
|
||||
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)
|
||||
|
||||
// sets the data builder function, that will be used by the runner
|
||||
// both when running the entire workflow or single phases
|
||||
initRunner.SetDataInitializer(func() (workflow.RunData, error) {
|
||||
return newInitData(cmd, options)
|
||||
})
|
||||
|
||||
// binds the Runner to kubeadm init command by altering
|
||||
// command help, adding --skip-phases flag and by adding phases subcommands
|
||||
initRunner.BindToCommand(cmd)
|
||||
|
||||
return cmd
|
||||
}
|
||||
@ -220,56 +243,86 @@ func AddInitOtherFlags(flagSet *flag.FlagSet, cfgPath *string, skipTokenPrint, d
|
||||
)
|
||||
}
|
||||
|
||||
// NewInit validates given arguments and instantiates Init struct with provided information.
|
||||
func NewInit(cfgPath string, externalcfg *kubeadmapiv1beta1.InitConfiguration, ignorePreflightErrors sets.String, skipTokenPrint, dryRun bool) (*Init, error) {
|
||||
// newInitOptions returns a struct ready for being used for creating cmd init flags.
|
||||
func newInitOptions() *initOptions {
|
||||
// initialize the public kubeadm config API by appling defaults
|
||||
externalcfg := &kubeadmapiv1beta1.InitConfiguration{}
|
||||
kubeadmscheme.Scheme.Default(externalcfg)
|
||||
|
||||
// Either use the config file if specified, or convert the defaults in the external to an internal cfg representation
|
||||
cfg, err := configutil.ConfigFileAndDefaultsToInternalConfig(cfgPath, externalcfg)
|
||||
// Create the options object for the bootstrap token-related flags, and override the default value for .Description
|
||||
bto := options.NewBootstrapTokenOptions()
|
||||
bto.Description = "The default bootstrap token generated by 'kubeadm init'."
|
||||
|
||||
return &initOptions{
|
||||
externalcfg: externalcfg,
|
||||
bto: bto,
|
||||
}
|
||||
}
|
||||
|
||||
// newInitData returns a new initData struct to be used for the execution of the kubeadm init workflow.
|
||||
// This func takes care of validating initOptions passed to the command, and then it converts
|
||||
// options into the internal InitConfiguration type that is used as input all the phases in the kubeadm init workflow
|
||||
func newInitData(cmd *cobra.Command, options *initOptions) (initData, error) {
|
||||
// Re-apply defaults to the public kubeadm API (this will set only values not exposed/not set as a flags)
|
||||
kubeadmscheme.Scheme.Default(options.externalcfg)
|
||||
|
||||
// Validate standalone flags values and/or combination of flags and then assigns
|
||||
// validated values to the public kubeadm config API when applicable
|
||||
var err error
|
||||
if options.externalcfg.FeatureGates, err = features.NewFeatureGate(&features.InitFeatureGates, options.featureGatesString); err != nil {
|
||||
return initData{}, err
|
||||
}
|
||||
|
||||
ignorePreflightErrorsSet, err := validation.ValidateIgnorePreflightErrors(options.ignorePreflightErrors)
|
||||
kubeadmutil.CheckErr(err)
|
||||
|
||||
if err = validation.ValidateMixedArguments(cmd.Flags()); err != nil {
|
||||
return initData{}, err
|
||||
}
|
||||
|
||||
if err = options.bto.ApplyTo(options.externalcfg); err != nil {
|
||||
return initData{}, err
|
||||
}
|
||||
|
||||
// Either use the config file if specified, or convert public kubeadm API to the internal InitConfiguration
|
||||
// and validates InitConfiguration
|
||||
cfg, err := configutil.ConfigFileAndDefaultsToInternalConfig(options.cfgPath, options.externalcfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return initData{}, err
|
||||
}
|
||||
if err := configutil.VerifyAPIServerBindAddress(cfg.APIEndpoint.AdvertiseAddress); err != nil {
|
||||
return nil, err
|
||||
return initData{}, err
|
||||
}
|
||||
|
||||
glog.V(1).Infof("[init] validating feature gates")
|
||||
if err := features.ValidateVersion(features.InitFeatureGates, cfg.FeatureGates, cfg.KubernetesVersion); err != nil {
|
||||
return nil, err
|
||||
return initData{}, err
|
||||
}
|
||||
|
||||
fmt.Printf("[init] using Kubernetes version: %s\n", cfg.KubernetesVersion)
|
||||
return initData{
|
||||
cfg: cfg,
|
||||
skipTokenPrint: options.skipTokenPrint,
|
||||
dryRun: options.dryRun,
|
||||
ignorePreflightErrors: ignorePreflightErrorsSet,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 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(), cfg, ignorePreflightErrors); err != nil {
|
||||
return nil, err
|
||||
if err := preflight.RunInitMasterChecks(utilsexec.New(), i.cfg, i.ignorePreflightErrors); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !dryRun {
|
||||
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(), cfg, ignorePreflightErrors); err != nil {
|
||||
return nil, err
|
||||
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')")
|
||||
}
|
||||
|
||||
return &Init{cfg: cfg, skipTokenPrint: skipTokenPrint, dryRun: dryRun, ignorePreflightErrors: ignorePreflightErrors}, nil
|
||||
}
|
||||
|
||||
// Init defines struct used by "kubeadm init" command
|
||||
type Init struct {
|
||||
cfg *kubeadmapi.InitConfiguration
|
||||
skipTokenPrint bool
|
||||
dryRun bool
|
||||
ignorePreflightErrors sets.String
|
||||
}
|
||||
|
||||
// Run executes master node provisioning, including certificates, needed static pod manifests, etc.
|
||||
func (i *Init) Run(out io.Writer) error {
|
||||
|
||||
// Get directories to write files to; can be faked if we're dry-running
|
||||
glog.V(1).Infof("[init] Getting certificates directory from configuration")
|
||||
realCertsDir := i.cfg.CertificatesDir
|
||||
@ -579,8 +632,8 @@ func printFilesIfDryRunning(dryRun bool, manifestDir string) error {
|
||||
}
|
||||
|
||||
// getWaiter gets the right waiter implementation for the right occasion
|
||||
func getWaiter(i *Init, client clientset.Interface) apiclient.Waiter {
|
||||
if i.dryRun {
|
||||
func getWaiter(ctx *initData, client clientset.Interface) apiclient.Waiter {
|
||||
if ctx.dryRun {
|
||||
return dryrunutil.NewWaiter()
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user