diff --git a/cmd/kubeadm/app/cmd/phases/BUILD b/cmd/kubeadm/app/cmd/phases/BUILD index 4d2d158ede2..d4cc7c6301d 100644 --- a/cmd/kubeadm/app/cmd/phases/BUILD +++ b/cmd/kubeadm/app/cmd/phases/BUILD @@ -49,6 +49,7 @@ go_library( "//pkg/api/legacyscheme:go_default_library", "//pkg/util/normalizer:go_default_library", "//vendor/github.com/spf13/cobra:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//vendor/k8s.io/client-go/kubernetes:go_default_library", "//vendor/k8s.io/utils/exec:go_default_library", ], diff --git a/cmd/kubeadm/app/cmd/phases/addons.go b/cmd/kubeadm/app/cmd/phases/addons.go index 098df6dfa41..19b1433f2d3 100644 --- a/cmd/kubeadm/app/cmd/phases/addons.go +++ b/cmd/kubeadm/app/cmd/phases/addons.go @@ -30,15 +30,39 @@ import ( configutil "k8s.io/kubernetes/cmd/kubeadm/app/util/config" kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig" "k8s.io/kubernetes/pkg/api/legacyscheme" + "k8s.io/kubernetes/pkg/util/normalizer" +) + +var ( + allAddonsLongDesc = normalizer.LongDesc(` + Installs the kube-dns and the kube-proxys addons components via the API server. + Please note that although the DNS server is deployed, it will not be scheduled until CNI is installed. + ` + cmdutil.AlphaDisclaimer) + + allAddonsExample = normalizer.Examples(` + # Installs the kube-dns and the kube-proxys addons components via the API server, + # functionally equivalent to what installed by kubeadm init. + + kubeadm alpha phase selfhosting from-staticpods + `) + + kubednsAddonsLongDesc = normalizer.LongDesc(` + Installs the kube-dns addon components via the API server. + Please note that although the DNS server is deployed, it will not be scheduled until CNI is installed. + ` + cmdutil.AlphaDisclaimer) + + kubeproxyAddonsLongDesc = normalizer.LongDesc(` + Installs the kube-proxy addon components via the API server. + ` + cmdutil.AlphaDisclaimer) ) // NewCmdAddon returns the addon Cobra command func NewCmdAddon() *cobra.Command { cmd := &cobra.Command{ - Use: "addon ", + Use: "addon", Aliases: []string{"addons"}, - Short: "Install an addon to a Kubernetes cluster.", - RunE: cmdutil.SubCmdRunE("addon"), + Short: "Installs required addons for passing Conformance tests", + Long: cmdutil.MacroCommandLongDescription, } cmd.AddCommand(getAddonsSubCommands()...) @@ -73,23 +97,29 @@ func getAddonsSubCommands() []*cobra.Command { var subCmds []*cobra.Command subCmdProperties := []struct { - use string - short string - cmdFunc func(cfg *kubeadmapi.MasterConfiguration, client clientset.Interface) error + use string + short string + long string + examples string + cmdFunc func(cfg *kubeadmapi.MasterConfiguration, client clientset.Interface) error }{ { - use: "all", - short: "Install all addons to a Kubernetes cluster.", - cmdFunc: EnsureAllAddons, + use: "all", + short: "Installs all addons to a Kubernetes cluster", + long: allAddonsLongDesc, + examples: allAddonsExample, + cmdFunc: EnsureAllAddons, }, { use: "kube-dns", - short: "Install the kube-dns addon to a Kubernetes cluster.", + short: "Installs the kube-dns addon to a Kubernetes cluster", + long: kubednsAddonsLongDesc, cmdFunc: dnsaddon.EnsureDNSAddon, }, { use: "kube-proxy", - short: "Install the kube-proxy addon to a Kubernetes cluster.", + short: "Installs the kube-proxy addon to a Kubernetes cluster", + long: kubeproxyAddonsLongDesc, cmdFunc: proxyaddon.EnsureProxyAddon, }, } @@ -97,26 +127,28 @@ func getAddonsSubCommands() []*cobra.Command { for _, properties := range subCmdProperties { // Creates the UX Command cmd := &cobra.Command{ - Use: properties.use, - Short: properties.short, - Run: runAddonsCmdFunc(properties.cmdFunc, cfg, &kubeConfigFile, &cfgPath), + Use: properties.use, + Short: properties.short, + Long: properties.long, + Example: properties.examples, + Run: runAddonsCmdFunc(properties.cmdFunc, cfg, &kubeConfigFile, &cfgPath), } // Add flags to the command cmd.Flags().StringVar(&kubeConfigFile, "kubeconfig", "/etc/kubernetes/admin.conf", "The KubeConfig file to use when talking to the cluster") cmd.Flags().StringVar(&cfgPath, "config", cfgPath, "Path to a kubeadm config file. WARNING: Usage of a configuration file is experimental!") - cmd.Flags().StringVar(&cfg.KubernetesVersion, "kubernetes-version", cfg.KubernetesVersion, `Choose a specific Kubernetes version for the control plane.`) - cmd.Flags().StringVar(&cfg.ImageRepository, "image-repository", cfg.ImageRepository, `Choose a container registry to pull control plane images from.`) + cmd.Flags().StringVar(&cfg.KubernetesVersion, "kubernetes-version", cfg.KubernetesVersion, `Choose a specific Kubernetes version for the control plane`) + cmd.Flags().StringVar(&cfg.ImageRepository, "image-repository", cfg.ImageRepository, `Choose a container registry to pull control plane images from`) if properties.use == "all" || properties.use == "kube-proxy" { - cmd.Flags().StringVar(&cfg.API.AdvertiseAddress, "apiserver-advertise-address", cfg.API.AdvertiseAddress, `The IP address the API Server will advertise it's listening on. Specify '0.0.0.0' to use the address of the default network interface.`) - cmd.Flags().Int32Var(&cfg.API.BindPort, "apiserver-bind-port", cfg.API.BindPort, `Port for the API Server to bind to.`) - cmd.Flags().StringVar(&cfg.Networking.PodSubnet, "pod-network-cidr", cfg.Networking.PodSubnet, `Specify range of IP addresses for the pod network. If set, the control plane will automatically allocate CIDRs for every node.`) + cmd.Flags().StringVar(&cfg.API.AdvertiseAddress, "apiserver-advertise-address", cfg.API.AdvertiseAddress, `The IP address or DNS name the API server is accessible on`) + cmd.Flags().Int32Var(&cfg.API.BindPort, "apiserver-bind-port", cfg.API.BindPort, `The port the API server is accessible on`) + cmd.Flags().StringVar(&cfg.Networking.PodSubnet, "pod-network-cidr", cfg.Networking.PodSubnet, `The range of IP addresses used for the Pod network`) } if properties.use == "all" || properties.use == "kube-dns" { - cmd.Flags().StringVar(&cfg.Networking.DNSDomain, "service-dns-domain", cfg.Networking.DNSDomain, `Use alternative domain for services, e.g. "myorg.internal.`) - cmd.Flags().StringVar(&cfg.Networking.ServiceSubnet, "service-cidr", cfg.Networking.ServiceSubnet, `Use alternative range of IP address for service VIPs`) + cmd.Flags().StringVar(&cfg.Networking.DNSDomain, "service-dns-domain", cfg.Networking.DNSDomain, `Alternative domain for services`) + cmd.Flags().StringVar(&cfg.Networking.ServiceSubnet, "service-cidr", cfg.Networking.ServiceSubnet, `The range of IP address used for service VIPs`) } subCmds = append(subCmds, cmd) } diff --git a/cmd/kubeadm/app/cmd/phases/certs.go b/cmd/kubeadm/app/cmd/phases/certs.go index 81ae6f8158b..6f37c6d20dd 100644 --- a/cmd/kubeadm/app/cmd/phases/certs.go +++ b/cmd/kubeadm/app/cmd/phases/certs.go @@ -17,16 +17,81 @@ limitations under the License. package phases import ( + "fmt" + "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" cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util" + kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" certsphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/certs" kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util" configutil "k8s.io/kubernetes/cmd/kubeadm/app/util/config" "k8s.io/kubernetes/pkg/api/legacyscheme" + "k8s.io/kubernetes/pkg/util/normalizer" +) + +var ( + allCertsLongDesc = normalizer.LongDesc(` + Generates a self-signed CA to provision identities for each component in the cluster (including nodes) + and client certificates to be used by various components. + + If a given certificate and private key pair both exist, kubeadm skips the generation step and + existing files will be used. + ` + cmdutil.AlphaDisclaimer) + + allCertsExample = normalizer.Examples(` + # Creates all PKI assets necessary to establish the control plane, + # functionally equivalent to what generated by kubeadm init. + kubeadm alpha phase certs all + + # Creates all PKI assets using options read from a configuration file. + kubeadm alpha phase certs all --config masterconfiguration.yaml + `) + + caCertLongDesc = fmt.Sprintf(normalizer.LongDesc(` + Generates the self-signed certificate authority and related key, and saves them into %s and %s files. + + If both files already exist, kubeadm skips the generation step and existing files will be used. + `+cmdutil.AlphaDisclaimer), kubeadmconstants.CACertName, kubeadmconstants.CAKeyName) + + apiServerCertLongDesc = fmt.Sprintf(normalizer.LongDesc(` + Generates the API server serving certificate and key and saves them into %s and %s files. + + The certificate includes default subject alternative names and additional sans eventually provided by the user; + default sans are: , , kubernetes, kubernetes.default, kubernetes.default.svc, + kubernetes.default.svc., (that is the .10 address in address space). + + If both files already exist, kubeadm skips the generation step and existing files will be used. + `+cmdutil.AlphaDisclaimer), kubeadmconstants.APIServerCertName, kubeadmconstants.APIServerKeyName) + + apiServerKubeletCertLongDesc = fmt.Sprintf(normalizer.LongDesc(` + Generates the client certificate for the API server to connect to the kubelet securely and the respective key, + and saves them into %s and %s files. + + If both files already exist, kubeadm skips the generation step and existing files will be used. + `+cmdutil.AlphaDisclaimer), kubeadmconstants.APIServerKubeletClientCertName, kubeadmconstants.APIServerKubeletClientKeyName) + + saKeyLongDesc = fmt.Sprintf(normalizer.LongDesc(` + Generates the private key for signing service account tokens along with its public key, and saves them into + %s and %s files. + + If both files already exist, kubeadm skips the generation step and existing files will be used. + `+cmdutil.AlphaDisclaimer), kubeadmconstants.ServiceAccountPrivateKeyName, kubeadmconstants.ServiceAccountPublicKeyName) + + frontProxyCaCertLongDesc = fmt.Sprintf(normalizer.LongDesc(` + Generates the front proxy CA certificate and key and saves them into %s and %s files. + + If both files already exist, kubeadm skips the generation step and existing files will be used. + `+cmdutil.AlphaDisclaimer), kubeadmconstants.FrontProxyCACertName, kubeadmconstants.FrontProxyCAKeyName) + + frontProxyClientCertLongDesc = fmt.Sprintf(normalizer.LongDesc(` + Generates the front proxy client certificate and key and saves them into %s and %s files. + + If both files already exist, kubeadm skips the generation step and existing files will be used. + `+cmdutil.AlphaDisclaimer), kubeadmconstants.FrontProxyClientCertName, kubeadmconstants.FrontProxyClientKeyName) ) // NewCmdCerts returns main command for certs phase @@ -34,8 +99,8 @@ func NewCmdCerts() *cobra.Command { cmd := &cobra.Command{ Use: "certs", Aliases: []string{"certificates"}, - Short: "Generate certificates for a Kubernetes cluster.", - RunE: cmdutil.SubCmdRunE("certs"), + Short: "Generates certificates for a Kubernetes cluster", + Long: cmdutil.MacroCommandLongDescription, } cmd.AddCommand(getCertsSubCommands("")...) @@ -61,43 +126,53 @@ func getCertsSubCommands(defaultKubernetesVersion string) []*cobra.Command { var subCmds []*cobra.Command subCmdProperties := []struct { - use string - short string - cmdFunc func(cfg *kubeadmapi.MasterConfiguration) error + use string + short string + long string + examples string + cmdFunc func(cfg *kubeadmapi.MasterConfiguration) error }{ { - use: "all", - short: "Generate all PKI assets necessary to establish the control plane", - cmdFunc: certsphase.CreatePKIAssets, + use: "all", + short: "Generates all PKI assets necessary to establish the control plane", + long: allCertsLongDesc, + examples: allCertsExample, + cmdFunc: certsphase.CreatePKIAssets, }, { use: "ca", - short: "Generate CA certificate and key for a Kubernetes cluster.", + short: "Generates self-signed CA to provision identities for each component in the cluster", + long: caCertLongDesc, cmdFunc: certsphase.CreateCACertAndKeyfiles, }, { use: "apiserver", - short: "Generate API Server serving certificate and key.", + short: "Generates API server serving certificate and key", + long: apiServerCertLongDesc, cmdFunc: certsphase.CreateAPIServerCertAndKeyFiles, }, { use: "apiserver-kubelet-client", - short: "Generate a client certificate for the API Server to connect to the kubelets securely.", + short: "Generates client certificate for the API server to connect to the kubelets securely", + long: apiServerKubeletCertLongDesc, cmdFunc: certsphase.CreateAPIServerKubeletClientCertAndKeyFiles, }, { use: "sa", - short: "Generate a private key for signing service account tokens along with its public key.", + short: "Generates a private key for signing service account tokens along with its public key", + long: saKeyLongDesc, cmdFunc: certsphase.CreateServiceAccountKeyAndPublicKeyFiles, }, { use: "front-proxy-ca", - short: "Generate front proxy CA certificate and key for a Kubernetes cluster.", + short: "Generates front proxy CA certificate and key for a Kubernetes cluster", + long: frontProxyCaCertLongDesc, cmdFunc: certsphase.CreateFrontProxyCACertAndKeyFiles, }, { use: "front-proxy-client", - short: "Generate front proxy CA client certificate and key for a Kubernetes cluster.", + short: "Generates front proxy CA client certificate and key for a Kubernetes cluster", + long: frontProxyClientCertLongDesc, cmdFunc: certsphase.CreateFrontProxyClientCertAndKeyFiles, }, } @@ -105,19 +180,21 @@ func getCertsSubCommands(defaultKubernetesVersion string) []*cobra.Command { for _, properties := range subCmdProperties { // Creates the UX Command cmd := &cobra.Command{ - Use: properties.use, - Short: properties.short, - Run: runCmdFunc(properties.cmdFunc, &cfgPath, cfg), + Use: properties.use, + Short: properties.short, + Long: properties.long, + Example: properties.examples, + Run: runCmdFunc(properties.cmdFunc, &cfgPath, cfg), } // Add flags to the command - cmd.Flags().StringVar(&cfgPath, "config", cfgPath, "Path to a kubeadm config file. WARNING: Usage of a configuration file is experimental!") - cmd.Flags().StringVar(&cfg.CertificatesDir, "cert-dir", cfg.CertificatesDir, "The path where to save and store the certificates.") + cmd.Flags().StringVar(&cfgPath, "config", cfgPath, "Path to kubeadm config file (WARNING: Usage of a configuration file is experimental)") + cmd.Flags().StringVar(&cfg.CertificatesDir, "cert-dir", cfg.CertificatesDir, "The path where to save the certificates") if properties.use == "all" || properties.use == "apiserver" { - cmd.Flags().StringVar(&cfg.Networking.DNSDomain, "service-dns-domain", cfg.Networking.DNSDomain, "Use alternative domain for services, e.g. \"myorg.internal\".") - cmd.Flags().StringVar(&cfg.Networking.ServiceSubnet, "service-cidr", cfg.Networking.ServiceSubnet, "Use alternative range of IP address for service VIPs.") - cmd.Flags().StringSliceVar(&cfg.APIServerCertSANs, "apiserver-cert-extra-sans", []string{}, "Optional extra Subject Alternative Names (SANs) to use for the API Server serving certificate. Can be both IP addresses and DNS names.") - cmd.Flags().StringVar(&cfg.API.AdvertiseAddress, "apiserver-advertise-address", cfg.API.AdvertiseAddress, "The IP address the API Server will advertise it is listening on. Specify '0.0.0.0' to use the address of the default network interface.") + cmd.Flags().StringVar(&cfg.Networking.DNSDomain, "service-dns-domain", cfg.Networking.DNSDomain, "Alternative domain for services, to use for the API server serving cert") + cmd.Flags().StringVar(&cfg.Networking.ServiceSubnet, "service-cidr", cfg.Networking.ServiceSubnet, "Alternative range of IP address for service VIPs, from which derives the internal API server VIP that will be added to the API Server serving cert") + cmd.Flags().StringSliceVar(&cfg.APIServerCertSANs, "apiserver-cert-extra-sans", []string{}, "Optional extra altnames to use for the API server serving cert. Can be both IP addresses and dns names") + cmd.Flags().StringVar(&cfg.API.AdvertiseAddress, "apiserver-advertise-address", cfg.API.AdvertiseAddress, "The IP address the API server is accessible on, to use for the API server serving cert") } subCmds = append(subCmds, cmd) diff --git a/cmd/kubeadm/app/cmd/phases/controlplane.go b/cmd/kubeadm/app/cmd/phases/controlplane.go index fd5f04ebac1..183c13981a8 100644 --- a/cmd/kubeadm/app/cmd/phases/controlplane.go +++ b/cmd/kubeadm/app/cmd/phases/controlplane.go @@ -17,6 +17,7 @@ limitations under the License. package phases import ( + "fmt" "strings" "github.com/spf13/cobra" @@ -31,14 +32,42 @@ import ( kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util" configutil "k8s.io/kubernetes/cmd/kubeadm/app/util/config" "k8s.io/kubernetes/pkg/api/legacyscheme" + "k8s.io/kubernetes/pkg/util/normalizer" +) + +var ( + allControlplaneLongDesc = normalizer.LongDesc(` + Generates all static Pod manifest files necessary to establish the control plane. + ` + cmdutil.AlphaDisclaimer) + + allControlplaneExample = normalizer.Examples(` + # Generates all static Pod manifest files for control plane components, + # functionally equivalent to what generated by kubeadm init. + kubeadm alpha phase controlplane all + + # Generates all static Pod manifest files using options read from a configuration file. + kubeadm alpha phase controlplane --config masterconfiguration.yaml + `) + + apiServerControlplaneLongDesc = fmt.Sprintf(normalizer.LongDesc(` + Generates the static Pod manifest file for the API server and saves it into %s file. + `+cmdutil.AlphaDisclaimer), kubeadmconstants.GetStaticPodFilepath(kubeadmconstants.KubeAPIServer, kubeadmconstants.GetStaticPodDirectory())) + + controllerManagerControlplaneLongDesc = fmt.Sprintf(normalizer.LongDesc(` + Generates the static Pod manifest file for the controller-manager and saves it into %s file. + `+cmdutil.AlphaDisclaimer), kubeadmconstants.GetStaticPodFilepath(kubeadmconstants.KubeControllerManager, kubeadmconstants.GetStaticPodDirectory())) + + schedulerControlplaneLongDesc = fmt.Sprintf(normalizer.LongDesc(` + Generates the static Pod manifest file for the scheduler and saves it into %s file. + `+cmdutil.AlphaDisclaimer), kubeadmconstants.GetStaticPodFilepath(kubeadmconstants.KubeScheduler, kubeadmconstants.GetStaticPodDirectory())) ) // NewCmdControlplane return main command for Controlplane phase func NewCmdControlplane() *cobra.Command { cmd := &cobra.Command{ Use: "controlplane", - Short: "Generate all static pod manifest files necessary to establish the control plane.", - RunE: cmdutil.SubCmdRunE("controlplane"), + Short: "Generates all static Pod manifest files necessary to establish the control plane", + Long: cmdutil.MacroCommandLongDescription, } manifestPath := kubeadmconstants.GetStaticPodDirectory() @@ -65,28 +94,35 @@ func getControlPlaneSubCommands(outDir, defaultKubernetesVersion string) []*cobr var subCmds []*cobra.Command subCmdProperties := []struct { - use string - short string - cmdFunc func(outDir string, cfg *kubeadmapi.MasterConfiguration) error + use string + short string + long string + examples string + cmdFunc func(outDir string, cfg *kubeadmapi.MasterConfiguration) error }{ { - use: "all", - short: "Generate all static pod manifest files necessary to establish the control plane.", - cmdFunc: controlplanephase.CreateInitStaticPodManifestFiles, + use: "all", + short: "Generates all static Pod manifest files necessary to establish the control plane", + long: allControlplaneLongDesc, + examples: allControlplaneExample, + cmdFunc: controlplanephase.CreateInitStaticPodManifestFiles, }, { use: "apiserver", - short: "Generate apiserver static pod manifest.", + short: "Generates the API server static Pod manifest.", + long: apiServerControlplaneLongDesc, cmdFunc: controlplanephase.CreateAPIServerStaticPodManifestFile, }, { use: "controller-manager", - short: "Generate controller-manager static pod manifest.", + short: "Generates the controller-manager static Pod manifest.", + long: controllerManagerControlplaneLongDesc, cmdFunc: controlplanephase.CreateControllerManagerStaticPodManifestFile, }, { use: "scheduler", - short: "Generate scheduler static pod manifest.", + short: "Generates the scheduler static Pod manifest.", + long: schedulerControlplaneLongDesc, cmdFunc: controlplanephase.CreateSchedulerStaticPodManifestFile, }, } @@ -94,28 +130,30 @@ func getControlPlaneSubCommands(outDir, defaultKubernetesVersion string) []*cobr for _, properties := range subCmdProperties { // Creates the UX Command cmd := &cobra.Command{ - Use: properties.use, - Short: properties.short, - Run: runCmdControlPlane(properties.cmdFunc, &outDir, &cfgPath, &featureGatesString, cfg), + Use: properties.use, + Short: properties.short, + Long: properties.long, + Example: properties.examples, + Run: runCmdControlPlane(properties.cmdFunc, &outDir, &cfgPath, &featureGatesString, cfg), } // Add flags to the command - cmd.Flags().StringVar(&cfg.CertificatesDir, "cert-dir", cfg.CertificatesDir, `The path where certificates are stored.`) - cmd.Flags().StringVar(&cfg.KubernetesVersion, "kubernetes-version", cfg.KubernetesVersion, `Choose a specific Kubernetes version for the control plane.`) + cmd.Flags().StringVar(&cfg.CertificatesDir, "cert-dir", cfg.CertificatesDir, `The path where certificates are stored`) + cmd.Flags().StringVar(&cfg.KubernetesVersion, "kubernetes-version", cfg.KubernetesVersion, `Choose a specific Kubernetes version for the control plane`) if properties.use == "all" || properties.use == "apiserver" { - cmd.Flags().StringVar(&cfg.API.AdvertiseAddress, "apiserver-advertise-address", cfg.API.AdvertiseAddress, "The IP address or DNS name the API Server is accessible on.") - cmd.Flags().Int32Var(&cfg.API.BindPort, "apiserver-bind-port", cfg.API.BindPort, "The port the API Server is accessible on.") - cmd.Flags().StringVar(&cfg.Networking.ServiceSubnet, "service-cidr", cfg.Networking.ServiceSubnet, "The range of IP address used for service VIPs.") + cmd.Flags().StringVar(&cfg.API.AdvertiseAddress, "apiserver-advertise-address", cfg.API.AdvertiseAddress, "The IP address or DNS name the API server is accessible on") + cmd.Flags().Int32Var(&cfg.API.BindPort, "apiserver-bind-port", cfg.API.BindPort, "The port the API server is accessible on") + cmd.Flags().StringVar(&cfg.Networking.ServiceSubnet, "service-cidr", cfg.Networking.ServiceSubnet, "The range of IP address used for service VIPs") cmd.Flags().StringVar(&featureGatesString, "feature-gates", featureGatesString, "A set of key=value pairs that describe feature gates for various features. "+ "Options are:\n"+strings.Join(features.KnownFeatures(&features.InitFeatureGates), "\n")) } if properties.use == "all" || properties.use == "controller-manager" { - cmd.Flags().StringVar(&cfg.Networking.PodSubnet, "pod-network-cidr", cfg.Networking.PodSubnet, "The range of IP addresses used for the pod network.") + cmd.Flags().StringVar(&cfg.Networking.PodSubnet, "pod-network-cidr", cfg.Networking.PodSubnet, "The range of IP addresses used for the Pod network") } - cmd.Flags().StringVar(&cfgPath, "config", cfgPath, "Path to a kubeadm config file. WARNING: Usage of a configuration file is experimental!") + cmd.Flags().StringVar(&cfgPath, "config", cfgPath, "Path to kubeadm config file (WARNING: Usage of a configuration file is experimental)") subCmds = append(subCmds, cmd) } diff --git a/cmd/kubeadm/app/cmd/phases/etcd.go b/cmd/kubeadm/app/cmd/phases/etcd.go index 9dab289c060..86c9d8dc234 100644 --- a/cmd/kubeadm/app/cmd/phases/etcd.go +++ b/cmd/kubeadm/app/cmd/phases/etcd.go @@ -17,6 +17,8 @@ limitations under the License. package phases import ( + "fmt" + "github.com/spf13/cobra" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" @@ -25,14 +27,30 @@ import ( kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" etcdphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/etcd" "k8s.io/kubernetes/pkg/api/legacyscheme" + "k8s.io/kubernetes/pkg/util/normalizer" +) + +var ( + etcdLocalLongDesc = fmt.Sprintf(normalizer.LongDesc(` + Generates the static Pod manifest file for a local, single-node etcd instance and saves it to %s file. + `+cmdutil.AlphaDisclaimer), kubeadmconstants.GetStaticPodFilepath(kubeadmconstants.Etcd, kubeadmconstants.GetStaticPodDirectory())) + + etcdLocalExample = normalizer.Examples(` + # Generates the static Pod manifest file for etcd, functionally + # equivalent to what generated by kubeadm init. + kubeadm alpha phase etcd local + + # Generates the static Pod manifest file for etcd. + kubeadm alpha phase etcd local --config masterconfiguration.yaml + `) ) // NewCmdEtcd return main command for Etcd phase func NewCmdEtcd() *cobra.Command { cmd := &cobra.Command{ Use: "etcd", - Short: "Generate static pod manifest file for etcd.", - RunE: cmdutil.SubCmdRunE("etcd"), + Short: "Generates static Pod manifest file for etcd.", + Long: cmdutil.MacroCommandLongDescription, } manifestPath := kubeadmconstants.GetStaticPodDirectory() @@ -59,20 +77,26 @@ func getEtcdSubCommands(outDir, defaultKubernetesVersion string) []*cobra.Comman var subCmds []*cobra.Command properties := struct { - use string - short string - cmdFunc func(outDir string, cfg *kubeadmapi.MasterConfiguration) error + use string + short string + long string + examples string + cmdFunc func(outDir string, cfg *kubeadmapi.MasterConfiguration) error }{ - use: "local", - short: "Generate static pod manifest file for a local, single-node etcd instance.", - cmdFunc: etcdphase.CreateLocalEtcdStaticPodManifestFile, + use: "local", + short: "Generates the static Pod manifest file for a local, single-node etcd instance", + long: etcdLocalLongDesc, + examples: etcdLocalExample, + cmdFunc: etcdphase.CreateLocalEtcdStaticPodManifestFile, } // Creates the UX Command cmd := &cobra.Command{ - Use: properties.use, - Short: properties.short, - Run: runCmdPhase(properties.cmdFunc, &outDir, &cfgPath, cfg), + Use: properties.use, + Short: properties.short, + Long: properties.long, + Example: properties.examples, + Run: runCmdPhase(properties.cmdFunc, &outDir, &cfgPath, cfg), } // Add flags to the command diff --git a/cmd/kubeadm/app/cmd/phases/kubeconfig.go b/cmd/kubeadm/app/cmd/phases/kubeconfig.go index ad287301395..2d707a42014 100644 --- a/cmd/kubeadm/app/cmd/phases/kubeconfig.go +++ b/cmd/kubeadm/app/cmd/phases/kubeconfig.go @@ -19,6 +19,7 @@ package phases import ( "fmt" "io" + "path/filepath" "github.com/spf13/cobra" @@ -28,14 +29,58 @@ import ( kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" kubeconfigphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig" "k8s.io/kubernetes/pkg/api/legacyscheme" + "k8s.io/kubernetes/pkg/util/normalizer" +) + +var ( + allKubeconfigLongDesc = normalizer.LongDesc(` + Generates all kubeconfig files necessary to establish the control plane and the admin kubeconfig file. + ` + cmdutil.AlphaDisclaimer) + + allKubeconfigExample = normalizer.Examples(` + # Generates all kubeconfig files, functionally equivalent to what generated + # by kubeadm init. + kubeadm alpha phase kubeconfig all + + # Generates all kubeconfig files using options read from a configuration file. + kubeadm alpha phase kubeconfig all --config masterconfiguration.yaml + `) + + adminKubeconfigLongDesc = fmt.Sprintf(normalizer.LongDesc(` + Generates the kubeconfig file for the admin and for kubeadm itself, and saves it to %s file. + `+cmdutil.AlphaDisclaimer), kubeadmconstants.AdminKubeConfigFileName) + + kubeletKubeconfigLongDesc = fmt.Sprintf(normalizer.LongDesc(` + Generates the kubeconfig file for the kubelet to use and saves it to %s file. + + Please note that this should *only* be used for bootstrapping purposes. After your control plane is up, + you should request all kubelet credentials from the CSR API. + `+cmdutil.AlphaDisclaimer), filepath.Join(kubeadmconstants.KubernetesDir, kubeadmconstants.KubeletKubeConfigFileName)) + + controllerManagerKubeconfigLongDesc = fmt.Sprintf(normalizer.LongDesc(` + Generates the kubeconfig file for the controller manager to use and saves it to %s file. + `+cmdutil.AlphaDisclaimer), filepath.Join(kubeadmconstants.KubernetesDir, kubeadmconstants.ControllerManagerKubeConfigFileName)) + + schedulerKubeconfigLongDesc = fmt.Sprintf(normalizer.LongDesc(` + Generates the kubeconfig file for the scheduler to use and saves it to %s file. + `+cmdutil.AlphaDisclaimer), filepath.Join(kubeadmconstants.KubernetesDir, kubeadmconstants.SchedulerKubeConfigFileName)) + + userKubeconfigLongDesc = normalizer.LongDesc(` + Outputs a kubeconfig file for an additional user. + ` + cmdutil.AlphaDisclaimer) + + userKubeconfigExample = normalizer.Examples(` + # Outputs a kubeconfig file for an additional user named foo + kubeadm alpha phase kubeconfig user --client-name=foo + `) ) // NewCmdKubeConfig return main command for kubeconfig phase func NewCmdKubeConfig(out io.Writer) *cobra.Command { cmd := &cobra.Command{ Use: "kubeconfig", - Short: "Generate all kubeconfig files necessary to establish the control plane and the admin kubeconfig file.", - RunE: cmdutil.SubCmdRunE("kubeconfig"), + Short: "Generates all kubeconfig files necessary to establish the control plane and the admin kubeconfig file", + Long: cmdutil.MacroCommandLongDescription, } cmd.AddCommand(getKubeConfigSubCommands(out, kubeadmconstants.KubernetesDir, "")...) @@ -61,41 +106,51 @@ func getKubeConfigSubCommands(out io.Writer, outDir, defaultKubernetesVersion st var subCmds []*cobra.Command subCmdProperties := []struct { - use string - short string - cmdFunc func(outDir string, cfg *kubeadmapi.MasterConfiguration) error + use string + short string + long string + examples string + cmdFunc func(outDir string, cfg *kubeadmapi.MasterConfiguration) error }{ { - use: "all", - short: "Generate all kubeconfig files necessary to establish the control plane and the admin kubeconfig file.", - cmdFunc: kubeconfigphase.CreateInitKubeConfigFiles, + use: "all", + short: "Generates all kubeconfig files necessary to establish the control plane and the admin kubeconfig file", + long: allKubeconfigLongDesc, + examples: allKubeconfigExample, + cmdFunc: kubeconfigphase.CreateInitKubeConfigFiles, }, { use: "admin", - short: "Generate a kubeconfig file for the administrator to use and for kubeadm itself.", + short: "Generates a kubeconfig file for the admin to use and for kubeadm itself", + long: adminKubeconfigLongDesc, cmdFunc: kubeconfigphase.CreateAdminKubeConfigFile, }, { use: "kubelet", - short: "Generate a kubeconfig file for the Kubelet to use. Please note that this should *only* be used for bootstrapping purposes! After your control plane is up, you should request all kubelet credentials from the CSR API.", + short: "Generates a kubeconfig file for the kubelet to use. Please note that this should be used *only* for bootstrapping purposes.", + long: kubeletKubeconfigLongDesc, cmdFunc: kubeconfigphase.CreateKubeletKubeConfigFile, }, { use: "controller-manager", - short: "Generate a kubeconfig file for the Controller Manager to use.", + short: "Generates a kubeconfig file for the controller manager to use", + long: controllerManagerKubeconfigLongDesc, cmdFunc: kubeconfigphase.CreateControllerManagerKubeConfigFile, }, { use: "scheduler", - short: "Generate a kubeconfig file for the Scheduler to use.", + short: "Generates a kubeconfig file for the scheduler to use", + long: schedulerKubeconfigLongDesc, cmdFunc: kubeconfigphase.CreateSchedulerKubeConfigFile, }, { - use: "user", - short: "Outputs a kubeconfig file for an additional user.", + use: "user", + short: "Outputs a kubeconfig file for an additional user", + long: userKubeconfigLongDesc, + examples: userKubeconfigExample, cmdFunc: func(outDir string, cfg *kubeadmapi.MasterConfiguration) error { if clientName == "" { - return fmt.Errorf("missing required argument client-name") + return fmt.Errorf("missing required argument --client-name") } // if the kubeconfig file for an additional user has to use a token, use it @@ -112,25 +167,27 @@ func getKubeConfigSubCommands(out io.Writer, outDir, defaultKubernetesVersion st for _, properties := range subCmdProperties { // Creates the UX Command cmd := &cobra.Command{ - Use: properties.use, - Short: properties.short, - Run: runCmdPhase(properties.cmdFunc, &outDir, &cfgPath, cfg), + Use: properties.use, + Short: properties.short, + Long: properties.long, + Example: properties.examples, + Run: runCmdPhase(properties.cmdFunc, &outDir, &cfgPath, cfg), } // Add flags to the command if properties.use != "user" { - cmd.Flags().StringVar(&cfgPath, "config", cfgPath, "Path to kubeadm config file. WARNING: Usage of a configuration file is experimental!") + cmd.Flags().StringVar(&cfgPath, "config", cfgPath, "Path to kubeadm config file (WARNING: Usage of a configuration file is experimental)") } - cmd.Flags().StringVar(&cfg.CertificatesDir, "cert-dir", cfg.CertificatesDir, "The path where certificates are stored.") - cmd.Flags().StringVar(&cfg.API.AdvertiseAddress, "apiserver-advertise-address", cfg.API.AdvertiseAddress, "The IP address or DNS name the API Server is accessible on.") - cmd.Flags().Int32Var(&cfg.API.BindPort, "apiserver-bind-port", cfg.API.BindPort, "The port the API Server is accessible on.") - cmd.Flags().StringVar(&outDir, "kubeconfig-dir", outDir, "The path where to save and store the kubeconfig file.") + cmd.Flags().StringVar(&cfg.CertificatesDir, "cert-dir", cfg.CertificatesDir, "The path where certificates are stored") + cmd.Flags().StringVar(&cfg.API.AdvertiseAddress, "apiserver-advertise-address", cfg.API.AdvertiseAddress, "The IP address the API server is accessible on") + cmd.Flags().Int32Var(&cfg.API.BindPort, "apiserver-bind-port", cfg.API.BindPort, "The port the API server is accessible on") + cmd.Flags().StringVar(&outDir, "kubeconfig-dir", outDir, "The port where to save the kubeconfig file") if properties.use == "all" || properties.use == "kubelet" { - cmd.Flags().StringVar(&cfg.NodeName, "node-name", cfg.NodeName, `The node name that the kubelet client cert should use.`) + cmd.Flags().StringVar(&cfg.NodeName, "node-name", cfg.NodeName, `The node name that should be used for the kubelet client certificate`) } if properties.use == "user" { - cmd.Flags().StringVar(&token, "token", token, "The token that should be used as the authentication mechanism for this kubeconfig.") - cmd.Flags().StringVar(&clientName, "client-name", clientName, "The name of the KubeConfig user that will be created. Will also be used as the CN if client certs are created.") + cmd.Flags().StringVar(&token, "token", token, "The token that should be used as the authentication mechanism for this kubeconfig (instead of client certificates)") + cmd.Flags().StringVar(&clientName, "client-name", clientName, "The name of user. It will be used as the CN if client certificates are created") } subCmds = append(subCmds, cmd) diff --git a/cmd/kubeadm/app/cmd/phases/phase.go b/cmd/kubeadm/app/cmd/phases/phase.go index 276e37ba6d4..2f5a42588fb 100644 --- a/cmd/kubeadm/app/cmd/phases/phase.go +++ b/cmd/kubeadm/app/cmd/phases/phase.go @@ -28,7 +28,7 @@ func NewCmdPhase(out io.Writer) *cobra.Command { cmd := &cobra.Command{ Use: "phase", Short: "Invoke subsets of kubeadm functions separately for a manual install.", - RunE: cmdutil.SubCmdRunE("phase"), + Long: cmdutil.MacroCommandLongDescription, } cmd.AddCommand(NewCmdAddon()) diff --git a/cmd/kubeadm/app/cmd/phases/selfhosting.go b/cmd/kubeadm/app/cmd/phases/selfhosting.go index 31594fc4a85..b9200ca57e9 100644 --- a/cmd/kubeadm/app/cmd/phases/selfhosting.go +++ b/cmd/kubeadm/app/cmd/phases/selfhosting.go @@ -34,15 +34,33 @@ import ( configutil "k8s.io/kubernetes/cmd/kubeadm/app/util/config" kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig" "k8s.io/kubernetes/pkg/api/legacyscheme" + "k8s.io/kubernetes/pkg/util/normalizer" +) + +var ( + selfhostingLongDesc = normalizer.LongDesc(` + Converts static Pod files for control plane components into self-hosted DaemonSets configured via the Kubernetes API. + + See the documentation for self-hosting limitations. + + ` + cmdutil.AlphaDisclaimer) + + selfhostingExample = normalizer.Examples(` + # Converts a static Pod-hosted control plane into a self-hosted one, + # functionally equivalent to what generated by kubeadm init executed + # with --feature-gates=SelfHosting=true. + + kubeadm alpha phase selfhosting convert-from-staticpods + `) ) // NewCmdSelfhosting returns the self-hosting Cobra command func NewCmdSelfhosting() *cobra.Command { cmd := &cobra.Command{ Use: "selfhosting", - Aliases: []string{"selfhosted"}, - Short: "Make a kubeadm cluster self-hosted.", - RunE: cmdutil.SubCmdRunE("selfhosting"), + Aliases: []string{"selfhosted", "self-hosting"}, + Short: "Makes a kubeadm cluster self-hosted", + Long: cmdutil.MacroCommandLongDescription, } cmd.AddCommand(getSelfhostingSubCommand()) @@ -62,7 +80,9 @@ func getSelfhostingSubCommand() *cobra.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.", + Short: "Converts a static Pod-hosted control plane into a self-hosted one", + Long: selfhostingLongDesc, + Example: selfhostingExample, Run: func(cmd *cobra.Command, args []string) { var err error if cfg.FeatureGates, err = features.NewFeatureGate(&features.InitFeatureGates, featureGatesString); err != nil { @@ -90,14 +110,14 @@ func getSelfhostingSubCommand() *cobra.Command { // 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(&cfg.CertificatesDir, "cert-dir", cfg.CertificatesDir, `The path where certificates are stored`) cmd.Flags().StringVar(&cfgPath, "config", cfgPath, "Path to a kubeadm config file. WARNING: Usage of a configuration file is experimental!") - cmd.Flags().StringVar(&featureGatesString, "feature-gates", featureGatesString, "A set of key=value pairs that describe feature gates for various features."+ + cmd.Flags().StringVar(&featureGatesString, "feature-gates", featureGatesString, "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 when talking to the cluster.") + cmd.Flags().StringVar(&kubeConfigFile, "kubeconfig", "/etc/kubernetes/admin.conf", "The KubeConfig file to use when talking to the cluster") return cmd } diff --git a/cmd/kubeadm/app/cmd/phases/uploadconfig.go b/cmd/kubeadm/app/cmd/phases/uploadconfig.go index 99e7ae2563f..ec11c2f3380 100644 --- a/cmd/kubeadm/app/cmd/phases/uploadconfig.go +++ b/cmd/kubeadm/app/cmd/phases/uploadconfig.go @@ -21,11 +21,29 @@ import ( "github.com/spf13/cobra" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" kubeadmapiext "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha1" + cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util" + kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" "k8s.io/kubernetes/cmd/kubeadm/app/phases/uploadconfig" 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/util/normalizer" +) + +var ( + uploadConfigLongDesc = fmt.Sprintf(normalizer.LongDesc(` + Uploads the kubeadm init configuration of your cluster to a ConfigMap called %s in the %s namespace. + This enables correct configuration of system components and a seamless user experience when upgrading. + + Alternatively, you can use kubeadm config. + `+cmdutil.AlphaDisclaimer), kubeadmconstants.MasterConfigurationConfigMap, metav1.NamespaceSystem) + + uploadConfigExample = normalizer.Examples(` + # uploads the configuration of your cluster + kubeadm alpha phase upload-config --config=myConfig.yaml + `) ) // NewCmdUploadConfig returns the Cobra command for running the uploadconfig phase @@ -33,7 +51,9 @@ func NewCmdUploadConfig() *cobra.Command { var cfgPath, kubeConfigFile string cmd := &cobra.Command{ Use: "upload-config", - Short: "Upload the currently used configuration for kubeadm to a ConfigMap in the cluster for future use in reconfiguration and upgrades of the cluster.", + Short: "Uploads the currently used configuration for kubeadm to a ConfigMap", + Long: uploadConfigLongDesc, + Example: uploadConfigExample, Aliases: []string{"uploadconfig"}, Run: func(_ *cobra.Command, args []string) { if len(cfgPath) == 0 {