mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-28 05:57:25 +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/apis/kubeadm/validation:go_default_library",
|
||||||
"//cmd/kubeadm/app/cmd/options:go_default_library",
|
"//cmd/kubeadm/app/cmd/options:go_default_library",
|
||||||
"//cmd/kubeadm/app/cmd/phases: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/upgrade:go_default_library",
|
||||||
"//cmd/kubeadm/app/cmd/util:go_default_library",
|
"//cmd/kubeadm/app/cmd/util:go_default_library",
|
||||||
"//cmd/kubeadm/app/componentconfigs:go_default_library",
|
"//cmd/kubeadm/app/componentconfigs:go_default_library",
|
||||||
|
@ -30,7 +30,6 @@ import (
|
|||||||
"github.com/renstrom/dedent"
|
"github.com/renstrom/dedent"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
flag "github.com/spf13/pflag"
|
flag "github.com/spf13/pflag"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
clientset "k8s.io/client-go/kubernetes"
|
clientset "k8s.io/client-go/kubernetes"
|
||||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||||
@ -38,6 +37,7 @@ import (
|
|||||||
kubeadmapiv1beta1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta1"
|
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/apis/kubeadm/validation"
|
||||||
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
|
"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"
|
cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util"
|
||||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||||
"k8s.io/kubernetes/cmd/kubeadm/app/features"
|
"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.
|
// NewCmdInit returns "kubeadm init" command.
|
||||||
func NewCmdInit(out io.Writer) *cobra.Command {
|
func NewCmdInit(out io.Writer) *cobra.Command {
|
||||||
externalcfg := &kubeadmapiv1beta1.InitConfiguration{}
|
options := newInitOptions()
|
||||||
kubeadmscheme.Scheme.Default(externalcfg)
|
initRunner := workflow.NewRunner()
|
||||||
|
|
||||||
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'."
|
|
||||||
|
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "init",
|
Use: "init",
|
||||||
Short: "Run this command in order to set up the Kubernetes master.",
|
Short: "Run this command in order to set up the Kubernetes master.",
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
var err error
|
c, err := initRunner.InitData()
|
||||||
if externalcfg.FeatureGates, err = features.NewFeatureGate(&features.InitFeatureGates, featureGatesString); err != nil {
|
|
||||||
kubeadmutil.CheckErr(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
ignorePreflightErrorsSet, err := validation.ValidateIgnorePreflightErrors(ignorePreflightErrors)
|
|
||||||
kubeadmutil.CheckErr(err)
|
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)
|
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)
|
kubeadmutil.CheckErr(err)
|
||||||
|
|
||||||
i, err := NewInit(cfgPath, externalcfg, ignorePreflightErrorsSet, skipTokenPrint, dryRun)
|
|
||||||
kubeadmutil.CheckErr(err)
|
|
||||||
kubeadmutil.CheckErr(i.Run(out))
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
AddInitConfigFlags(cmd.PersistentFlags(), externalcfg, &featureGatesString)
|
// adds command flags
|
||||||
AddInitOtherFlags(cmd.PersistentFlags(), &cfgPath, &skipTokenPrint, &dryRun, &ignorePreflightErrors)
|
AddInitConfigFlags(cmd.PersistentFlags(), options.externalcfg, &options.featureGatesString)
|
||||||
bto.AddTokenFlag(cmd.PersistentFlags())
|
AddInitOtherFlags(cmd.PersistentFlags(), &options.cfgPath, &options.skipTokenPrint, &options.dryRun, &options.ignorePreflightErrors)
|
||||||
bto.AddTTLFlag(cmd.PersistentFlags())
|
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
|
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.
|
// newInitOptions returns a struct ready for being used for creating cmd init flags.
|
||||||
func NewInit(cfgPath string, externalcfg *kubeadmapiv1beta1.InitConfiguration, ignorePreflightErrors sets.String, skipTokenPrint, dryRun bool) (*Init, error) {
|
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
|
// Create the options object for the bootstrap token-related flags, and override the default value for .Description
|
||||||
cfg, err := configutil.ConfigFileAndDefaultsToInternalConfig(cfgPath, externalcfg)
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return initData{}, err
|
||||||
}
|
}
|
||||||
if err := configutil.VerifyAPIServerBindAddress(cfg.APIEndpoint.AdvertiseAddress); err != nil {
|
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 {
|
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")
|
fmt.Println("[preflight] running pre-flight checks")
|
||||||
|
if err := preflight.RunInitMasterChecks(utilsexec.New(), i.cfg, i.ignorePreflightErrors); err != nil {
|
||||||
if err := preflight.RunInitMasterChecks(utilsexec.New(), cfg, ignorePreflightErrors); err != nil {
|
return err
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !dryRun {
|
if !i.dryRun {
|
||||||
fmt.Println("[preflight/images] Pulling images required for setting up a Kubernetes cluster")
|
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] 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'")
|
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 {
|
if err := preflight.RunPullImagesCheck(utilsexec.New(), i.cfg, i.ignorePreflightErrors); err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fmt.Println("[preflight/images] Would pull the required images (like 'kubeadm config images pull')")
|
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
|
// Get directories to write files to; can be faked if we're dry-running
|
||||||
glog.V(1).Infof("[init] Getting certificates directory from configuration")
|
glog.V(1).Infof("[init] Getting certificates directory from configuration")
|
||||||
realCertsDir := i.cfg.CertificatesDir
|
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
|
// getWaiter gets the right waiter implementation for the right occasion
|
||||||
func getWaiter(i *Init, client clientset.Interface) apiclient.Waiter {
|
func getWaiter(ctx *initData, client clientset.Interface) apiclient.Waiter {
|
||||||
if i.dryRun {
|
if ctx.dryRun {
|
||||||
return dryrunutil.NewWaiter()
|
return dryrunutil.NewWaiter()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user