From 69c24afc20cfaf56f9a6ee6249c83ce6746ed9c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20K=C3=A4ldstr=C3=B6m?= Date: Thu, 23 Feb 2017 21:28:18 +0200 Subject: [PATCH] kubeadm: Add a 'kubeadm alpha phase kubeconfig command' --- cmd/kubeadm/app/cmd/BUILD | 6 +- cmd/kubeadm/app/cmd/cmd.go | 2 + cmd/kubeadm/app/cmd/init.go | 2 +- cmd/kubeadm/app/cmd/phases/BUILD | 36 +++++++ cmd/kubeadm/app/cmd/phases/kubeconfig.go | 119 +++++++++++++++++++++++ cmd/kubeadm/app/cmd/phases/phase.go | 49 ++++++++++ cmd/kubeadm/app/cmd/reset.go | 2 + hack/verify-flags/known-flags.txt | 1 + 8 files changed, 215 insertions(+), 2 deletions(-) create mode 100644 cmd/kubeadm/app/cmd/phases/BUILD create mode 100644 cmd/kubeadm/app/cmd/phases/kubeconfig.go create mode 100644 cmd/kubeadm/app/cmd/phases/phase.go diff --git a/cmd/kubeadm/app/cmd/BUILD b/cmd/kubeadm/app/cmd/BUILD index 83d8e2b9db4..34aea5b7357 100644 --- a/cmd/kubeadm/app/cmd/BUILD +++ b/cmd/kubeadm/app/cmd/BUILD @@ -24,6 +24,7 @@ go_library( "//cmd/kubeadm/app/apis/kubeadm:go_default_library", "//cmd/kubeadm/app/apis/kubeadm/v1alpha1:go_default_library", "//cmd/kubeadm/app/apis/kubeadm/validation:go_default_library", + "//cmd/kubeadm/app/cmd/phases:go_default_library", "//cmd/kubeadm/app/constants:go_default_library", "//cmd/kubeadm/app/discovery:go_default_library", "//cmd/kubeadm/app/master:go_default_library", @@ -78,6 +79,9 @@ filegroup( filegroup( name = "all-srcs", - srcs = [":package-srcs"], + srcs = [ + ":package-srcs", + "//cmd/kubeadm/app/cmd/phases:all-srcs", + ], tags = ["automanaged"], ) diff --git a/cmd/kubeadm/app/cmd/cmd.go b/cmd/kubeadm/app/cmd/cmd.go index acc753c371b..65e07b7f576 100644 --- a/cmd/kubeadm/app/cmd/cmd.go +++ b/cmd/kubeadm/app/cmd/cmd.go @@ -23,6 +23,7 @@ import ( "github.com/spf13/cobra" "k8s.io/apiserver/pkg/util/flag" + "k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" ) @@ -88,6 +89,7 @@ func NewKubeadmCommand(f cmdutil.Factory, in io.Reader, out, err io.Writer) *cob Short: "Experimental sub-commands not yet fully functional.", } experimentalCmd.AddCommand(NewCmdToken(out, err)) + experimentalCmd.AddCommand(phases.NewCmdPhase(out)) cmds.AddCommand(experimentalCmd) return cmds diff --git a/cmd/kubeadm/app/cmd/init.go b/cmd/kubeadm/app/cmd/init.go index 1da11c70cad..2bd0ff12127 100644 --- a/cmd/kubeadm/app/cmd/init.go +++ b/cmd/kubeadm/app/cmd/init.go @@ -197,7 +197,7 @@ func (i *Init) Run(out io.Writer) error { // so we'll pick the first one, there is much of chance to have an empty // slice by the time this gets called masterEndpoint := fmt.Sprintf("https://%s:%d", i.cfg.API.AdvertiseAddresses[0], i.cfg.API.Port) - err = kubeconfigphase.CreateAdminAndKubeletKubeConfig(masterEndpoint, kubeadmapi.GlobalEnvParams.HostPKIPath, kubeadmapi.GlobalEnvParams.KubernetesDir) + err = kubeconfigphase.CreateInitKubeConfigFiles(masterEndpoint, kubeadmapi.GlobalEnvParams.HostPKIPath, kubeadmapi.GlobalEnvParams.KubernetesDir) if err != nil { return err } diff --git a/cmd/kubeadm/app/cmd/phases/BUILD b/cmd/kubeadm/app/cmd/phases/BUILD new file mode 100644 index 00000000000..21bdfd8e5d5 --- /dev/null +++ b/cmd/kubeadm/app/cmd/phases/BUILD @@ -0,0 +1,36 @@ +package(default_visibility = ["//visibility:public"]) + +licenses(["notice"]) + +load( + "@io_bazel_rules_go//go:def.bzl", + "go_library", +) + +go_library( + name = "go_default_library", + srcs = [ + "kubeconfig.go", + "phase.go", + ], + tags = ["automanaged"], + deps = [ + "//cmd/kubeadm/app/constants:go_default_library", + "//cmd/kubeadm/app/phases/kubeconfig:go_default_library", + "//cmd/kubeadm/app/util:go_default_library", + "//vendor:github.com/spf13/cobra", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], +) diff --git a/cmd/kubeadm/app/cmd/phases/kubeconfig.go b/cmd/kubeadm/app/cmd/phases/kubeconfig.go new file mode 100644 index 00000000000..af38df0c449 --- /dev/null +++ b/cmd/kubeadm/app/cmd/phases/kubeconfig.go @@ -0,0 +1,119 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package phases + +import ( + "fmt" + "io" + + "github.com/spf13/cobra" + + kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" + kubeconfigphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig" + kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util" +) + +func NewCmdKubeConfig(out io.Writer) *cobra.Command { + cmd := &cobra.Command{ + Use: "kubeconfig", + Short: "Create KubeConfig files from given credentials.", + RunE: subCmdRunE("kubeconfig"), + } + + cmd.AddCommand(NewCmdToken(out)) + cmd.AddCommand(NewCmdClientCerts(out)) + return cmd +} + +func NewCmdToken(out io.Writer) *cobra.Command { + config := &kubeconfigphase.KubeConfigProperties{ + MakeClientCerts: false, + } + cmd := &cobra.Command{ + Use: "token", + Short: "Output a valid KubeConfig file to STDOUT with a token as the authentication method.", + Run: func(cmd *cobra.Command, args []string) { + err := RunCreateWithToken(out, config) + kubeadmutil.CheckErr(err) + }, + } + addCommonFlags(cmd, config) + cmd.Flags().StringVar(&config.Token, "token", "", "The path to the directory where the certificates are.") + return cmd +} + +func NewCmdClientCerts(out io.Writer) *cobra.Command { + config := &kubeconfigphase.KubeConfigProperties{ + MakeClientCerts: true, + } + cmd := &cobra.Command{ + Use: "client-certs", + Short: "Output a valid KubeConfig file to STDOUT with a client certificates as the authentication method.", + Run: func(cmd *cobra.Command, args []string) { + err := RunCreateWithClientCerts(out, config) + kubeadmutil.CheckErr(err) + }, + } + addCommonFlags(cmd, config) + cmd.Flags().StringSliceVar(&config.Organization, "organization", []string{}, "The organization (group) the certificate should be in.") + return cmd +} + +func addCommonFlags(cmd *cobra.Command, config *kubeconfigphase.KubeConfigProperties) { + cmd.Flags().StringVar(&config.CertDir, "cert-dir", kubeadmconstants.DefaultCertDir, "The path to the directory where the certificates are.") + cmd.Flags().StringVar(&config.ClientName, "client-name", "", "The name of the client for which the KubeConfig file will be generated.") + cmd.Flags().StringVar(&config.APIServer, "server", "", "The location of the api server.") +} + +func validateCommonFlags(config *kubeconfigphase.KubeConfigProperties) error { + if len(config.ClientName) == 0 { + return fmt.Errorf("The --client-name flag is required") + } + if len(config.APIServer) == 0 { + return fmt.Errorf("The --server flag is required") + } + return nil +} + +// RunCreateWithToken generates a kubeconfig file from with a token as the authentication mechanism +func RunCreateWithToken(out io.Writer, config *kubeconfigphase.KubeConfigProperties) error { + if len(config.Token) == 0 { + return fmt.Errorf("The --token flag is required") + } + if err := validateCommonFlags(config); err != nil { + return err + } + kubeConfigBytes, err := kubeconfigphase.GetKubeConfigBytesFromSpec(*config) + if err != nil { + return err + } + fmt.Fprintln(out, string(kubeConfigBytes)) + return nil +} + +// RunCreateWithClientCerts generates a kubeconfig file from with client certs as the authentication mechanism +func RunCreateWithClientCerts(out io.Writer, config *kubeconfigphase.KubeConfigProperties) error { + if err := validateCommonFlags(config); err != nil { + return err + } + kubeConfigBytes, err := kubeconfigphase.GetKubeConfigBytesFromSpec(*config) + if err != nil { + return err + } + fmt.Fprintln(out, string(kubeConfigBytes)) + return nil +} diff --git a/cmd/kubeadm/app/cmd/phases/phase.go b/cmd/kubeadm/app/cmd/phases/phase.go new file mode 100644 index 00000000000..2ef206a1a95 --- /dev/null +++ b/cmd/kubeadm/app/cmd/phases/phase.go @@ -0,0 +1,49 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package phases + +import ( + "fmt" + "io" + + "github.com/spf13/cobra" +) + +func NewCmdPhase(out io.Writer) *cobra.Command { + cmd := &cobra.Command{ + Use: "phase", + Short: "Invoke subsets of kubeadm functions separately for a manual install.", + RunE: subCmdRunE("phase"), + } + cmd.AddCommand(NewCmdKubeConfig(out)) + return cmd +} + +// subCmdRunE returns a function that handles a case where a subcommand must be specified +// Without this callback, if a user runs just the command without a subcommand, +// or with an invalid subcommand, cobra will print usage information, but still exit cleanly. +// We want to return an error code in these cases so that the +// user knows that their command was invalid. +func subCmdRunE(name string) func(*cobra.Command, []string) error { + return func(_ *cobra.Command, args []string) error { + if len(args) < 1 { + return fmt.Errorf("missing subcommand; %q is not meant to be run on its own", name) + } else { + return fmt.Errorf("invalid subcommand: %q", args[0]) + } + } +} diff --git a/cmd/kubeadm/app/cmd/reset.go b/cmd/kubeadm/app/cmd/reset.go index 4df78e00d74..3721af2f18b 100644 --- a/cmd/kubeadm/app/cmd/reset.go +++ b/cmd/kubeadm/app/cmd/reset.go @@ -223,6 +223,8 @@ func resetConfigDir(configPathDir, pkiPathDir string) { filesToClean := []string{ filepath.Join(configPathDir, kubeadmconstants.AdminKubeConfigFileName), filepath.Join(configPathDir, kubeadmconstants.KubeletKubeConfigFileName), + filepath.Join(configPathDir, kubeadmconstants.ControllerManagerKubeConfigFileName), + filepath.Join(configPathDir, kubeadmconstants.SchedulerKubeConfigFileName), } fmt.Printf("[reset] Deleting files: %v\n", filesToClean) for _, path := range filesToClean { diff --git a/hack/verify-flags/known-flags.txt b/hack/verify-flags/known-flags.txt index 1a18d7dd9aa..4d4f40ef9fe 100644 --- a/hack/verify-flags/known-flags.txt +++ b/hack/verify-flags/known-flags.txt @@ -72,6 +72,7 @@ cleanup-iptables client-ca-file client-certificate client-key +client-name clientset-api-path clientset-name clientset-only