diff --git a/cmd/kubeadm/app/apis/kubeadm/validation/validation.go b/cmd/kubeadm/app/apis/kubeadm/validation/validation.go index 4459af6db3..5a97b63507 100644 --- a/cmd/kubeadm/app/apis/kubeadm/validation/validation.go +++ b/cmd/kubeadm/app/apis/kubeadm/validation/validation.go @@ -284,8 +284,8 @@ func ValidateMixedArguments(flag *pflag.FlagSet) error { mixedInvalidFlags := []string{} flag.Visit(func(f *pflag.Flag) { - if f.Name == "config" || strings.HasPrefix(f.Name, "skip-") || f.Name == "dry-run" { - // "--skip-*" flags can be set with --config + if f.Name == "config" || strings.HasPrefix(f.Name, "skip-") || f.Name == "dry-run" || f.Name == "kubeconfig" { + // "--skip-*" flags or other whitelisted flags can be set with --config return } mixedInvalidFlags = append(mixedInvalidFlags, f.Name) diff --git a/cmd/kubeadm/app/cmd/phases/selfhosting.go b/cmd/kubeadm/app/cmd/phases/selfhosting.go index 8e3f8d80e0..2fd9c3a820 100644 --- a/cmd/kubeadm/app/cmd/phases/selfhosting.go +++ b/cmd/kubeadm/app/cmd/phases/selfhosting.go @@ -21,44 +21,77 @@ import ( "github.com/spf13/cobra" - kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" kubeadmapiext "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha1" + "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation" "k8s.io/kubernetes/cmd/kubeadm/app/features" "k8s.io/kubernetes/cmd/kubeadm/app/phases/selfhosting" 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/api" ) // NewCmdSelfhosting returns the self-hosting Cobra command func NewCmdSelfhosting() *cobra.Command { - var kubeConfigFile, featureFlagsString string - cfg := &kubeadmapiext.MasterConfiguration{} cmd := &cobra.Command{ Use: "selfhosting", Aliases: []string{"selfhosted"}, Short: "Make a kubeadm cluster self-hosted.", - Run: func(cmd *cobra.Command, args []string) { + RunE: subCmdRunE("selfhosting"), + } + cmd.AddCommand(getSelfhostingSubCommand()) + return cmd +} + +// getSelfhostingSubCommand returns sub commands for Selfhosting phase +func getSelfhostingSubCommand() *cobra.Command { + + cfg := &kubeadmapiext.MasterConfiguration{} + // Default values for the cobra help text + api.Scheme.Default(cfg) + + var cfgPath, kubeConfigFile, featureFlagsString string + + // Creates the UX Command + cmd := &cobra.Command{ + Use: "convert-from-staticpods", + Aliases: []string{"from-staticpods"}, + Short: "Converts a Static Pod-hosted control plane into a self-hosted one.", + Run: func(cmd *cobra.Command, args []string) { var err error if cfg.FeatureFlags, err = features.NewFeatureGate(&features.InitFeatureGates, featureFlagsString); err != nil { kubeadmutil.CheckErr(err) } - api.Scheme.Default(cfg) - internalcfg := &kubeadmapi.MasterConfiguration{} - api.Scheme.Convert(cfg, internalcfg, nil) + if err := validation.ValidateMixedArguments(cmd.Flags()); err != nil { + kubeadmutil.CheckErr(err) + } + + // This call returns the ready-to-use configuration based on the configuration file that might or might not exist and the default cfg populated by flags + internalcfg, err := configutil.ConfigFileAndDefaultsToInternalConfig(cfgPath, cfg) + kubeadmutil.CheckErr(err) + + // Gets the kubernetes client client, err := kubeconfigutil.ClientSetFromFile(kubeConfigFile) kubeadmutil.CheckErr(err) + // Converts the Static Pod-hosted control plane into a self-hosted one err = selfhosting.CreateSelfHostedControlPlane(internalcfg, client) kubeadmutil.CheckErr(err) }, } - cmd.Flags().StringVar(&kubeConfigFile, "kubeconfig", "/etc/kubernetes/admin.conf", "The KubeConfig file to use for talking to the cluster") + // Add flags to the command + // flags bound to the configuration object + cmd.Flags().StringVar(&cfg.CertificatesDir, "cert-dir", cfg.CertificatesDir, `The path where certificates are stored`) + cmd.Flags().StringVar(&cfgPath, "config", cfgPath, "Path to kubeadm config file (WARNING: Usage of a configuration file is experimental)") cmd.Flags().StringVar(&featureFlagsString, "feature-gates", featureFlagsString, "A set of key=value pairs that describe feature gates for various features."+ "Options are:\n"+strings.Join(features.KnownFeatures(&features.InitFeatureGates), "\n")) + // flags that are not bound to the configuration object + // Note: All flags that are not bound to the cfg object should be whitelisted in cmd/kubeadm/app/apis/kubeadm/validation/validation.go + cmd.Flags().StringVar(&kubeConfigFile, "kubeconfig", "/etc/kubernetes/admin.conf", "The KubeConfig file to use for talking to the cluster") + return cmd }