From 1308c7d2f5a8d24da8640e179ba8b8c9e475af91 Mon Sep 17 00:00:00 2001 From: fabriziopandini Date: Fri, 16 Nov 2018 16:39:04 +0100 Subject: [PATCH] kubeadm phases add all subcommands --- cmd/kubeadm/app/cmd/phases/addons.go | 13 +++++-- cmd/kubeadm/app/cmd/phases/certs.go | 22 ++++++++---- cmd/kubeadm/app/cmd/phases/controlplane.go | 17 ++++++--- cmd/kubeadm/app/cmd/phases/etcd.go | 8 ++--- cmd/kubeadm/app/cmd/phases/kubeconfig.go | 11 ++++-- cmd/kubeadm/app/cmd/phases/uploadconfig.go | 5 +++ cmd/kubeadm/app/cmd/phases/workflow/phase.go | 5 +++ cmd/kubeadm/app/cmd/phases/workflow/runner.go | 36 ++++++++++++++++--- 8 files changed, 92 insertions(+), 25 deletions(-) diff --git a/cmd/kubeadm/app/cmd/phases/addons.go b/cmd/kubeadm/app/cmd/phases/addons.go index 4a4b708998..298ac80c40 100644 --- a/cmd/kubeadm/app/cmd/phases/addons.go +++ b/cmd/kubeadm/app/cmd/phases/addons.go @@ -23,6 +23,7 @@ import ( 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" dnsaddon "k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/dns" proxyaddon "k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/proxy" "k8s.io/kubernetes/pkg/util/normalizer" @@ -47,10 +48,16 @@ type addonData interface { // NewAddonPhase returns the addon Cobra command func NewAddonPhase() workflow.Phase { return workflow.Phase{ - Name: "addon", - Short: "Installs required addons for passing Conformance tests", - InheritFlags: getAddonPhaseFlags("all"), + Name: "addon", + Short: "Installs required addons for passing Conformance tests", + Long: cmdutil.MacroCommandLongDescription, Phases: []workflow.Phase{ + { + Name: "all", + Short: "Installs all the addons", + InheritFlags: getAddonPhaseFlags("all"), + RunAllSiblings: true, + }, { Name: "coredns", Short: "Installs the CoreDNS addon to a Kubernetes cluster", diff --git a/cmd/kubeadm/app/cmd/phases/certs.go b/cmd/kubeadm/app/cmd/phases/certs.go index e75929e13c..36fe4ff67f 100644 --- a/cmd/kubeadm/app/cmd/phases/certs.go +++ b/cmd/kubeadm/app/cmd/phases/certs.go @@ -66,12 +66,11 @@ type certsData interface { // NewCertsPhase returns the phase for the certs func NewCertsPhase() workflow.Phase { return workflow.Phase{ - Name: "certs", - Short: "Certificate generation", - Phases: newCertSubPhases(), - Run: runCerts, - InheritFlags: getCertPhaseFlags("all"), - LocalFlags: localFlags(), + Name: "certs", + Short: "Certificate generation", + Phases: newCertSubPhases(), + Run: runCerts, + Long: cmdutil.MacroCommandLongDescription, } } @@ -86,6 +85,17 @@ func localFlags() *pflag.FlagSet { func newCertSubPhases() []workflow.Phase { subPhases := []workflow.Phase{} + // All subphase + allPhase := workflow.Phase{ + Name: "all", + Short: "Generates all certificates", + InheritFlags: getCertPhaseFlags("all"), + RunAllSiblings: true, + LocalFlags: localFlags(), + } + + subPhases = append(subPhases, allPhase) + certTree, _ := certsphase.GetDefaultCertList().AsMap().CertTree() for ca, certList := range certTree { diff --git a/cmd/kubeadm/app/cmd/phases/controlplane.go b/cmd/kubeadm/app/cmd/phases/controlplane.go index 7960e5c84c..c08ab312d8 100644 --- a/cmd/kubeadm/app/cmd/phases/controlplane.go +++ b/cmd/kubeadm/app/cmd/phases/controlplane.go @@ -19,9 +19,11 @@ package phases import ( "errors" "fmt" + 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" "k8s.io/kubernetes/cmd/kubeadm/app/phases/controlplane" "k8s.io/kubernetes/pkg/util/normalizer" @@ -69,16 +71,21 @@ func getPhaseDescription(component string) string { // NewControlPlanePhase creates a kubeadm workflow phase that implements bootstrapping the control plane. func NewControlPlanePhase() workflow.Phase { phase := workflow.Phase{ - Name: "control-plane", - Short: "Generates all static Pod manifest files necessary to establish the control plane", - Example: controlPlaneExample, + Name: "control-plane", + Short: "Generates all static Pod manifest files necessary to establish the control plane", + Long: cmdutil.MacroCommandLongDescription, Phases: []workflow.Phase{ + { + Name: "all", + Short: "Generates all static Pod manifest files", + InheritFlags: getControlPlanePhaseFlags("all"), + RunAllSiblings: true, + }, newControlPlaneSubPhase(kubeadmconstants.KubeAPIServer), newControlPlaneSubPhase(kubeadmconstants.KubeControllerManager), newControlPlaneSubPhase(kubeadmconstants.KubeScheduler), }, - Run: runControlPlanePhase, - InheritFlags: getControlPlanePhaseFlags("all"), + Run: runControlPlanePhase, } return phase } diff --git a/cmd/kubeadm/app/cmd/phases/etcd.go b/cmd/kubeadm/app/cmd/phases/etcd.go index 85a82c54be..9727d0914f 100644 --- a/cmd/kubeadm/app/cmd/phases/etcd.go +++ b/cmd/kubeadm/app/cmd/phases/etcd.go @@ -24,6 +24,7 @@ import ( 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" etcdphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/etcd" "k8s.io/kubernetes/pkg/util/normalizer" ) @@ -48,13 +49,12 @@ type etcdData interface { // NewEtcdPhase creates a kubeadm workflow phase that implements handling of etcd. func NewEtcdPhase() workflow.Phase { phase := workflow.Phase{ - Name: "etcd", - Short: "Generates static Pod manifest file for local etcd.", - Example: etcdLocalExample, + Name: "etcd", + Short: "Generates static Pod manifest file for local etcd.", + Long: cmdutil.MacroCommandLongDescription, Phases: []workflow.Phase{ newEtcdLocalSubPhase(), }, - InheritFlags: getEtcdPhaseFlags(), } return phase } diff --git a/cmd/kubeadm/app/cmd/phases/kubeconfig.go b/cmd/kubeadm/app/cmd/phases/kubeconfig.go index d9240242d2..64a3698ce5 100644 --- a/cmd/kubeadm/app/cmd/phases/kubeconfig.go +++ b/cmd/kubeadm/app/cmd/phases/kubeconfig.go @@ -23,6 +23,7 @@ import ( 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" kubeconfigphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig" "k8s.io/kubernetes/pkg/util/normalizer" @@ -77,14 +78,20 @@ func NewKubeConfigPhase() workflow.Phase { return workflow.Phase{ Name: "kubeconfig", Short: "Generates all kubeconfig files necessary to establish the control plane and the admin kubeconfig file", + Long: cmdutil.MacroCommandLongDescription, Phases: []workflow.Phase{ + { + Name: "all", + Short: "Generates all kubeconfig files", + InheritFlags: getKubeConfigPhaseFlags("all"), + RunAllSiblings: true, + }, NewKubeConfigFilePhase(kubeadmconstants.AdminKubeConfigFileName), NewKubeConfigFilePhase(kubeadmconstants.KubeletKubeConfigFileName), NewKubeConfigFilePhase(kubeadmconstants.ControllerManagerKubeConfigFileName), NewKubeConfigFilePhase(kubeadmconstants.SchedulerKubeConfigFileName), }, - Run: runKubeConfig, - InheritFlags: getKubeConfigPhaseFlags("all"), + Run: runKubeConfig, } } diff --git a/cmd/kubeadm/app/cmd/phases/uploadconfig.go b/cmd/kubeadm/app/cmd/phases/uploadconfig.go index cb24652626..c11844ad81 100644 --- a/cmd/kubeadm/app/cmd/phases/uploadconfig.go +++ b/cmd/kubeadm/app/cmd/phases/uploadconfig.go @@ -71,6 +71,11 @@ func NewUploadConfigPhase() workflow.Phase { Short: "Uploads the kubeadm and kubelet configuration to a ConfigMap", Long: cmdutil.MacroCommandLongDescription, Phases: []workflow.Phase{ + { + Name: "all", + Short: "Uploads all configuration to a config map", + RunAllSiblings: true, + }, { Name: "kubeadm", Short: "Uploads the kubeadm ClusterConfiguration to a ConfigMap", diff --git a/cmd/kubeadm/app/cmd/phases/workflow/phase.go b/cmd/kubeadm/app/cmd/phases/workflow/phase.go index f3d14e2249..42ac7f337e 100644 --- a/cmd/kubeadm/app/cmd/phases/workflow/phase.go +++ b/cmd/kubeadm/app/cmd/phases/workflow/phase.go @@ -45,6 +45,11 @@ type Phase struct { // Phases defines a nested, ordered sequence of phases. Phases []Phase + // RunAllSiblings allows to assign to a phase the responsibility to + // run all the sibling phases + // Nb. phase marked as RunAllSiblings can not have Run functions + RunAllSiblings bool + // Run defines a function implementing the phase action. // It is recommended to implent type assertion, e.g. using golang type switch, // for validating the RunData type. diff --git a/cmd/kubeadm/app/cmd/phases/workflow/runner.go b/cmd/kubeadm/app/cmd/phases/workflow/runner.go index 7f0fe95b15..e9fa49b541 100644 --- a/cmd/kubeadm/app/cmd/phases/workflow/runner.go +++ b/cmd/kubeadm/app/cmd/phases/workflow/runner.go @@ -211,6 +211,12 @@ func (e *Runner) Run() error { return nil } + // Errors if phases that are meant to create special subcommands only + // are wrongly assigned Run Methods + if p.RunAllSiblings && (p.RunIf != nil || p.Run != nil) { + return errors.Wrapf(err, "phase marked as RunAllSiblings can not have Run functions %s", p.generatedName) + } + // If the phase defines a condition to be checked before executing the phase action. if p.RunIf != nil { // Check the condition and returns if the condition isn't satisfied (or fails) @@ -244,7 +250,7 @@ func (e *Runner) Help(cmdUse string) string { // computes the max length of for each phase use line maxLength := 0 e.visitAll(func(p *phaseRunner) error { - if !p.Hidden { + if !p.Hidden && !p.RunAllSiblings { length := len(p.use) if maxLength < length { maxLength = length @@ -259,7 +265,7 @@ func (e *Runner) Help(cmdUse string) string { line += "```\n" offset := 2 e.visitAll(func(p *phaseRunner) error { - if !p.Hidden { + if !p.Hidden && !p.RunAllSiblings { padding := maxLength - len(p.use) + offset line += strings.Repeat(" ", offset*p.level) // indentation line += p.use // name + aliases @@ -312,17 +318,31 @@ func (e *Runner) BindToCommand(cmd *cobra.Command) { return nil } - // creates nested phase subcommand - var phaseCmd = &cobra.Command{ + // initialize phase selector + phaseSelector := p.generatedName + + // if requested, set the phase to run all the sibling phases + if p.RunAllSiblings { + phaseSelector = p.parent.generatedName + } + + // creates phase subcommand + phaseCmd := &cobra.Command{ Use: strings.ToLower(p.Name), Short: p.Short, Long: p.Long, Example: p.Example, Aliases: p.Aliases, Run: func(cmd *cobra.Command, args []string) { + // if the phase has subphases, print the help and exits + if len(p.Phases) > 0 { + cmd.Help() + return + } + // overrides the command triggering the Runner using the phaseCmd e.runCmd = cmd - e.Options.FilterPhases = []string{p.generatedName} + e.Options.FilterPhases = []string{phaseSelector} if err := e.Run(); err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) @@ -405,6 +425,12 @@ func (e *Runner) prepareForExecution() { e.phaseRunners = []*phaseRunner{} var parentRunner *phaseRunner for _, phase := range e.Phases { + // skips phases that are meant to create special subcommands only + if phase.RunAllSiblings { + continue + } + + // add phases to the execution list addPhaseRunner(e, parentRunner, phase) } }