From ef31616e45271b2ec8437670e39dda9b18c6d75b Mon Sep 17 00:00:00 2001 From: "Timothy St. Clair" Date: Wed, 6 Mar 2019 14:07:15 -0600 Subject: [PATCH] Revert "Merge pull request #74628 from hpandeycodeit/alpha_kubeconf" This reverts commit 7053e43b2e413952fe46f0e9e2afa37b322225a0, reversing changes made to d58ff3bfc0743320d66ee7778bcf08bf4b1d8038. --- cmd/kubeadm/app/cmd/alpha/BUILD | 9 +- cmd/kubeadm/app/cmd/alpha/alpha.go | 1 + cmd/kubeadm/app/cmd/alpha/kubeconfig.go | 106 ++++++++++++++++++ cmd/kubeadm/app/cmd/alpha/kubeconfig_test.go | 109 +++++++++++++++++++ 4 files changed, 224 insertions(+), 1 deletion(-) create mode 100644 cmd/kubeadm/app/cmd/alpha/kubeconfig.go create mode 100644 cmd/kubeadm/app/cmd/alpha/kubeconfig_test.go diff --git a/cmd/kubeadm/app/cmd/alpha/BUILD b/cmd/kubeadm/app/cmd/alpha/BUILD index 5178a1a0d93..776580934b9 100644 --- a/cmd/kubeadm/app/cmd/alpha/BUILD +++ b/cmd/kubeadm/app/cmd/alpha/BUILD @@ -5,6 +5,7 @@ go_library( srcs = [ "alpha.go", "certs.go", + "kubeconfig.go", "kubelet.go", "selfhosting.go", ], @@ -21,6 +22,7 @@ go_library( "//cmd/kubeadm/app/features:go_default_library", "//cmd/kubeadm/app/phases/certs:go_default_library", "//cmd/kubeadm/app/phases/certs/renewal:go_default_library", + "//cmd/kubeadm/app/phases/kubeconfig:go_default_library", "//cmd/kubeadm/app/phases/kubelet:go_default_library", "//cmd/kubeadm/app/phases/selfhosting:go_default_library", "//cmd/kubeadm/app/preflight:go_default_library", @@ -52,7 +54,10 @@ filegroup( go_test( name = "go_default_test", - srcs = ["certs_test.go"], + srcs = [ + "certs_test.go", + "kubeconfig_test.go", + ], embed = [":go_default_library"], deps = [ "//cmd/kubeadm/app/constants:go_default_library", @@ -61,6 +66,8 @@ go_test( "//cmd/kubeadm/app/util/pkiutil:go_default_library", "//cmd/kubeadm/test:go_default_library", "//cmd/kubeadm/test/cmd:go_default_library", + "//cmd/kubeadm/test/kubeconfig:go_default_library", + "//staging/src/k8s.io/client-go/tools/clientcmd:go_default_library", "//vendor/github.com/spf13/cobra:go_default_library", ], ) diff --git a/cmd/kubeadm/app/cmd/alpha/alpha.go b/cmd/kubeadm/app/cmd/alpha/alpha.go index 4089caf79ff..f48d07ddcd9 100644 --- a/cmd/kubeadm/app/cmd/alpha/alpha.go +++ b/cmd/kubeadm/app/cmd/alpha/alpha.go @@ -32,6 +32,7 @@ func NewCmdAlpha(in io.Reader, out io.Writer) *cobra.Command { cmd.AddCommand(newCmdCertsUtility()) cmd.AddCommand(newCmdKubeletUtility()) + cmd.AddCommand(newCmdKubeConfigUtility(out)) cmd.AddCommand(NewCmdSelfhosting(in)) // TODO: This command should be removed as soon as the kubeadm init phase refactoring is completed. diff --git a/cmd/kubeadm/app/cmd/alpha/kubeconfig.go b/cmd/kubeadm/app/cmd/alpha/kubeconfig.go new file mode 100644 index 00000000000..6d28a2d5387 --- /dev/null +++ b/cmd/kubeadm/app/cmd/alpha/kubeconfig.go @@ -0,0 +1,106 @@ +/* +Copyright 2018 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 alpha + +import ( + "io" + + "github.com/pkg/errors" + "github.com/spf13/cobra" + kubeadmscheme "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/scheme" + kubeadmapiv1beta1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta1" + cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util" + kubeconfigphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig" + kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util" + configutil "k8s.io/kubernetes/cmd/kubeadm/app/util/config" + "k8s.io/kubernetes/pkg/util/normalizer" +) + +var ( + kubeconfigLongDesc = normalizer.LongDesc(` + Kubeconfig file utilities. + ` + cmdutil.AlphaDisclaimer) + + 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 kubeconfig user --client-name=foo + `) +) + +// newCmdKubeConfigUtility returns main command for kubeconfig phase +func newCmdKubeConfigUtility(out io.Writer) *cobra.Command { + cmd := &cobra.Command{ + Use: "kubeconfig", + Short: "Kubeconfig file utilities", + Long: kubeconfigLongDesc, + } + + cmd.AddCommand(newCmdUserKubeConfig(out)) + return cmd +} + +// newCmdUserKubeConfig returns sub commands for kubeconfig phase +func newCmdUserKubeConfig(out io.Writer) *cobra.Command { + + cfg := &kubeadmapiv1beta1.InitConfiguration{} + + // Default values for the cobra help text + kubeadmscheme.Scheme.Default(cfg) + + var token, clientName string + var organizations []string + + // Creates the UX Command + cmd := &cobra.Command{ + Use: "user", + Short: "Outputs a kubeconfig file for an additional user", + Long: userKubeconfigLongDesc, + Example: userKubeconfigExample, + Run: func(cmd *cobra.Command, args []string) { + if clientName == "" { + kubeadmutil.CheckErr(errors.New("missing required argument --client-name")) + } + + // This call returns the ready-to-use configuration based on the default cfg populated by flags + internalcfg, err := configutil.DefaultedInitConfiguration(cfg) + kubeadmutil.CheckErr(err) + + // if the kubeconfig file for an additional user has to use a token, use it + if token != "" { + kubeadmutil.CheckErr(kubeconfigphase.WriteKubeConfigWithToken(out, internalcfg, clientName, token)) + return + } + + // Otherwise, write a kubeconfig file with a generate client cert + kubeadmutil.CheckErr(kubeconfigphase.WriteKubeConfigWithClientCert(out, internalcfg, clientName, organizations)) + }, + } + + // Add flags to the command + cmd.Flags().StringVar(&cfg.CertificatesDir, "cert-dir", cfg.CertificatesDir, "The path where certificates are stored") + cmd.Flags().StringVar(&cfg.LocalAPIEndpoint.AdvertiseAddress, "apiserver-advertise-address", cfg.LocalAPIEndpoint.AdvertiseAddress, "The IP address the API server is accessible on") + cmd.Flags().Int32Var(&cfg.LocalAPIEndpoint.BindPort, "apiserver-bind-port", cfg.LocalAPIEndpoint.BindPort, "The port the API server is accessible on") + 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") + cmd.Flags().StringSliceVar(&organizations, "org", organizations, "The orgnizations of the client certificate. It will be used as the O if client certificates are created") + + return cmd +} diff --git a/cmd/kubeadm/app/cmd/alpha/kubeconfig_test.go b/cmd/kubeadm/app/cmd/alpha/kubeconfig_test.go new file mode 100644 index 00000000000..e2711b4453c --- /dev/null +++ b/cmd/kubeadm/app/cmd/alpha/kubeconfig_test.go @@ -0,0 +1,109 @@ +/* +Copyright 2018 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 alpha + +import ( + "bytes" + "fmt" + "os" + "testing" + + "k8s.io/client-go/tools/clientcmd" + kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" + "k8s.io/kubernetes/cmd/kubeadm/app/util/pkiutil" + testutil "k8s.io/kubernetes/cmd/kubeadm/test" + kubeconfigtestutil "k8s.io/kubernetes/cmd/kubeadm/test/kubeconfig" +) + +func TestKubeConfigSubCommandsThatWritesToOut(t *testing.T) { + + // Temporary folders for the test case + tmpdir := testutil.SetupTempDir(t) + defer os.RemoveAll(tmpdir) + + // Adds a pki folder with a ca cert to the temp folder + pkidir := testutil.SetupPkiDirWithCertificateAuthorithy(t, tmpdir) + + // Retrieves ca cert for assertions + caCert, _, err := pkiutil.TryLoadCertAndKeyFromDisk(pkidir, kubeadmconstants.CACertAndKeyBaseName) + if err != nil { + t.Fatalf("couldn't retrieve ca cert: %v", err) + } + + commonFlags := []string{ + "--apiserver-advertise-address=1.2.3.4", + "--apiserver-bind-port=1234", + "--client-name=myUser", + fmt.Sprintf("--cert-dir=%s", pkidir), + } + + var tests = []struct { + name string + command string + withClientCert bool + withToken bool + additionalFlags []string + }{ + { + name: "user subCommand withClientCert", + command: "user", + withClientCert: true, + }, + { + name: "user subCommand withToken", + withToken: true, + command: "user", + additionalFlags: []string{"--token=123456"}, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + buf := new(bytes.Buffer) + + // Get subcommands working in the temporary directory + cmd := newCmdUserKubeConfig(buf) + + // Execute the subcommand + allFlags := append(commonFlags, test.additionalFlags...) + cmd.SetArgs(allFlags) + if err := cmd.Execute(); err != nil { + t.Fatal("Could not execute subcommand") + } + + // reads kubeconfig written to stdout + config, err := clientcmd.Load(buf.Bytes()) + if err != nil { + t.Errorf("couldn't read kubeconfig file from buffer: %v", err) + return + } + + // checks that CLI flags are properly propagated + kubeconfigtestutil.AssertKubeConfigCurrentCluster(t, config, "https://1.2.3.4:1234", caCert) + + if test.withClientCert { + // checks that kubeconfig files have expected client cert + kubeconfigtestutil.AssertKubeConfigCurrentAuthInfoWithClientCert(t, config, caCert, "myUser") + } + + if test.withToken { + // checks that kubeconfig files have expected token + kubeconfigtestutil.AssertKubeConfigCurrentAuthInfoWithToken(t, config, "myUser", "123456") + } + }) + } +}