From 60b789b1c7488da4772ad300c8067b0d5b83e021 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20K=C3=A4ldstr=C3=B6m?= Date: Fri, 17 Feb 2017 21:36:58 +0200 Subject: [PATCH] kubeadm: Move {admin,kubelet}.conf out as constants and make a separate util package for kubeconfig logic --- cmd/kubeadm/app/cmd/BUILD | 3 +- cmd/kubeadm/app/cmd/init.go | 2 +- cmd/kubeadm/app/cmd/join.go | 6 +- cmd/kubeadm/app/cmd/reset.go | 8 +- cmd/kubeadm/app/cmd/reset_test.go | 20 ++-- cmd/kubeadm/app/cmd/token.go | 9 +- cmd/kubeadm/app/constants/constants.go | 3 + cmd/kubeadm/app/master/BUILD | 2 +- cmd/kubeadm/app/master/apiclient.go | 21 +--- cmd/kubeadm/app/node/BUILD | 2 +- cmd/kubeadm/app/node/bootstrap.go | 4 +- cmd/kubeadm/app/phases/kubeconfig/BUILD | 10 +- .../app/phases/kubeconfig/kubeconfig.go | 99 ++--------------- cmd/kubeadm/app/preflight/BUILD | 1 - cmd/kubeadm/app/preflight/checks.go | 3 +- cmd/kubeadm/app/util/BUILD | 1 + cmd/kubeadm/app/util/kubeconfig/BUILD | 41 +++++++ cmd/kubeadm/app/util/kubeconfig/kubeconfig.go | 101 ++++++++++++++++++ .../kubeconfig/kubeconfig_test.go | 22 ++-- federation/pkg/kubefed/init/BUILD | 2 +- federation/pkg/kubefed/init/init.go | 4 +- hack/.linted_packages | 1 + 22 files changed, 204 insertions(+), 161 deletions(-) create mode 100644 cmd/kubeadm/app/util/kubeconfig/BUILD create mode 100644 cmd/kubeadm/app/util/kubeconfig/kubeconfig.go rename cmd/kubeadm/app/{phases => util}/kubeconfig/kubeconfig_test.go (86%) diff --git a/cmd/kubeadm/app/cmd/BUILD b/cmd/kubeadm/app/cmd/BUILD index 74858f0f8c..b41ce59177 100644 --- a/cmd/kubeadm/app/cmd/BUILD +++ b/cmd/kubeadm/app/cmd/BUILD @@ -36,6 +36,7 @@ go_library( "//cmd/kubeadm/app/phases/token:go_default_library", "//cmd/kubeadm/app/preflight:go_default_library", "//cmd/kubeadm/app/util:go_default_library", + "//cmd/kubeadm/app/util/kubeconfig:go_default_library", "//cmd/kubeadm/app/util/token:go_default_library", "//pkg/bootstrap/api:go_default_library", "//pkg/kubectl:go_default_library", @@ -64,7 +65,7 @@ go_test( library = ":go_default_library", tags = ["automanaged"], deps = [ - "//cmd/kubeadm/app/phases/kubeconfig:go_default_library", + "//cmd/kubeadm/app/constants:go_default_library", "//cmd/kubeadm/app/preflight:go_default_library", ], ) diff --git a/cmd/kubeadm/app/cmd/init.go b/cmd/kubeadm/app/cmd/init.go index b709c80874..5ee92b2d26 100644 --- a/cmd/kubeadm/app/cmd/init.go +++ b/cmd/kubeadm/app/cmd/init.go @@ -218,7 +218,7 @@ func (i *Init) Run(out io.Writer) error { return err } - client, err := kubemaster.CreateClientAndWaitForAPI(path.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, kubeconfigphase.AdminKubeConfigFileName)) + client, err := kubemaster.CreateClientAndWaitForAPI(path.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, kubeadmconstants.AdminKubeConfigFileName)) if err != nil { return err } diff --git a/cmd/kubeadm/app/cmd/join.go b/cmd/kubeadm/app/cmd/join.go index 2c29083269..f8ed3294ae 100644 --- a/cmd/kubeadm/app/cmd/join.go +++ b/cmd/kubeadm/app/cmd/join.go @@ -34,9 +34,9 @@ import ( kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" "k8s.io/kubernetes/cmd/kubeadm/app/discovery" kubenode "k8s.io/kubernetes/cmd/kubeadm/app/node" - kubeconfigphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig" "k8s.io/kubernetes/cmd/kubeadm/app/preflight" kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util" + kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig" ) var ( @@ -139,8 +139,8 @@ func (j *Join) Run(out io.Writer) error { return err } - kubeconfigFile := filepath.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, kubeconfigphase.KubeletKubeConfigFileName) - if err := kubeconfigphase.WriteKubeconfigToDisk(kubeconfigFile, cfg); err != nil { + kubeconfigFile := filepath.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, kubeadmconstants.KubeletKubeConfigFileName) + if err := kubeconfigutil.WriteToDisk(kubeconfigFile, cfg); err != nil { return err } diff --git a/cmd/kubeadm/app/cmd/reset.go b/cmd/kubeadm/app/cmd/reset.go index c47a2f71cf..4df78e00d7 100644 --- a/cmd/kubeadm/app/cmd/reset.go +++ b/cmd/kubeadm/app/cmd/reset.go @@ -27,7 +27,7 @@ import ( "github.com/spf13/cobra" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" - "k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig" + kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" "k8s.io/kubernetes/cmd/kubeadm/app/preflight" kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util" "k8s.io/kubernetes/pkg/util/initsystem" @@ -150,7 +150,7 @@ func drainAndRemoveNode(removeNode bool) error { hostname = strings.ToLower(hostname) // TODO: Use the "native" k8s client for this once we're confident the versioned is working - kubeConfigPath := filepath.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, kubeconfig.KubeletKubeConfigFileName) + kubeConfigPath := filepath.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, kubeadmconstants.KubeletKubeConfigFileName) getNodesCmd := fmt.Sprintf("kubectl --kubeconfig %s get nodes | grep %s", kubeConfigPath, hostname) output, err := exec.Command("sh", "-c", getNodesCmd).Output() @@ -221,8 +221,8 @@ func resetConfigDir(configPathDir, pkiPathDir string) { } filesToClean := []string{ - filepath.Join(configPathDir, kubeconfig.AdminKubeConfigFileName), - filepath.Join(configPathDir, kubeconfig.KubeletKubeConfigFileName), + filepath.Join(configPathDir, kubeadmconstants.AdminKubeConfigFileName), + filepath.Join(configPathDir, kubeadmconstants.KubeletKubeConfigFileName), } fmt.Printf("[reset] Deleting files: %v\n", filesToClean) for _, path := range filesToClean { diff --git a/cmd/kubeadm/app/cmd/reset_test.go b/cmd/kubeadm/app/cmd/reset_test.go index e7d3c325b9..92b59b5193 100644 --- a/cmd/kubeadm/app/cmd/reset_test.go +++ b/cmd/kubeadm/app/cmd/reset_test.go @@ -22,7 +22,7 @@ import ( "path/filepath" "testing" - "k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig" + kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" "k8s.io/kubernetes/cmd/kubeadm/app/preflight" ) @@ -64,8 +64,8 @@ func TestConfigDirCleaner(t *testing.T) { "manifests/etcd.yaml", "manifests/kube-apiserver.yaml", "pki/ca.pem", - kubeconfig.AdminKubeConfigFileName, - kubeconfig.KubeletKubeConfigFileName, + kubeadmconstants.AdminKubeConfigFileName, + kubeadmconstants.KubeletKubeConfigFileName, }, verifyExists: []string{ "manifests", @@ -78,7 +78,7 @@ func TestConfigDirCleaner(t *testing.T) { }, setupFiles: []string{ "pki/ca.pem", - kubeconfig.KubeletKubeConfigFileName, + kubeadmconstants.KubeletKubeConfigFileName, }, verifyExists: []string{ "pki", @@ -96,8 +96,8 @@ func TestConfigDirCleaner(t *testing.T) { "manifests/etcd.yaml", "manifests/kube-apiserver.yaml", "pki/ca.pem", - kubeconfig.AdminKubeConfigFileName, - kubeconfig.KubeletKubeConfigFileName, + kubeadmconstants.AdminKubeConfigFileName, + kubeadmconstants.KubeletKubeConfigFileName, "cloud-config", }, verifyExists: []string{ @@ -116,8 +116,8 @@ func TestConfigDirCleaner(t *testing.T) { "manifests/etcd.yaml", "manifests/kube-apiserver.yaml", "pki/ca.pem", - kubeconfig.AdminKubeConfigFileName, - kubeconfig.KubeletKubeConfigFileName, + kubeadmconstants.AdminKubeConfigFileName, + kubeadmconstants.KubeletKubeConfigFileName, ".cloud-config", ".mydir/.myfile", }, @@ -167,8 +167,8 @@ func TestConfigDirCleaner(t *testing.T) { // Verify the files we cleanup implicitly in every test: assertExists(t, tmpDir) - assertNotExists(t, filepath.Join(tmpDir, kubeconfig.AdminKubeConfigFileName)) - assertNotExists(t, filepath.Join(tmpDir, kubeconfig.KubeletKubeConfigFileName)) + assertNotExists(t, filepath.Join(tmpDir, kubeadmconstants.AdminKubeConfigFileName)) + assertNotExists(t, filepath.Join(tmpDir, kubeadmconstants.KubeletKubeConfigFileName)) assertDirEmpty(t, filepath.Join(tmpDir, "manifests")) assertDirEmpty(t, filepath.Join(tmpDir, "pki")) diff --git a/cmd/kubeadm/app/cmd/token.go b/cmd/kubeadm/app/cmd/token.go index c83ef076ae..69632d32d2 100644 --- a/cmd/kubeadm/app/cmd/token.go +++ b/cmd/kubeadm/app/cmd/token.go @@ -32,10 +32,9 @@ import ( "k8s.io/client-go/pkg/api" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" - kubemaster "k8s.io/kubernetes/cmd/kubeadm/app/master" - "k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig" tokenphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/token" kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util" + kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig" tokenutil "k8s.io/kubernetes/cmd/kubeadm/app/util/token" bootstrapapi "k8s.io/kubernetes/pkg/bootstrap/api" "k8s.io/kubernetes/pkg/kubectl" @@ -131,7 +130,7 @@ func NewCmdTokenGenerate(out io.Writer) *cobra.Command { // RunCreateToken generates a new bootstrap token and stores it as a secret on the server. func RunCreateToken(out io.Writer, cmd *cobra.Command, tokenDuration time.Duration, token string) error { - client, err := kubemaster.CreateClientFromFile(path.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, kubeconfig.AdminKubeConfigFileName)) + client, err := kubeconfigutil.ClientSetFromFile(path.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, kubeadmconstants.AdminKubeConfigFileName)) if err != nil { return err } @@ -164,7 +163,7 @@ func RunGenerateToken(out io.Writer) error { // RunListTokens lists details on all existing bootstrap tokens on the server. func RunListTokens(out io.Writer, errW io.Writer, cmd *cobra.Command) error { - client, err := kubemaster.CreateClientFromFile(path.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, kubeconfig.AdminKubeConfigFileName)) + client, err := kubeconfigutil.ClientSetFromFile(path.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, kubeadmconstants.AdminKubeConfigFileName)) if err != nil { return err } @@ -223,7 +222,7 @@ func RunDeleteToken(out io.Writer, cmd *cobra.Command, tokenId string) error { return err } - client, err := kubemaster.CreateClientFromFile(path.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, kubeconfig.AdminKubeConfigFileName)) + client, err := kubeconfigutil.ClientSetFromFile(path.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, kubeadmconstants.AdminKubeConfigFileName)) if err != nil { return err } diff --git a/cmd/kubeadm/app/constants/constants.go b/cmd/kubeadm/app/constants/constants.go index 7c5b3884f8..c3ea4a3a1a 100644 --- a/cmd/kubeadm/app/constants/constants.go +++ b/cmd/kubeadm/app/constants/constants.go @@ -46,6 +46,9 @@ const ( FrontProxyClientCertName = "front-proxy-client.crt" FrontProxyClientKeyName = "front-proxy-client.key" + AdminKubeConfigFileName = "admin.conf" + KubeletKubeConfigFileName = "kubelet.conf" + // TODO: These constants should actually come from pkg/kubeapiserver/authorizer, but we can't vendor that package in now // because of all the other sub-packages that would get vendored. To fix this, a pkg/kubeapiserver/authorizer/modes package // or similar should exist that only has these constants; then we can vendor it. diff --git a/cmd/kubeadm/app/master/BUILD b/cmd/kubeadm/app/master/BUILD index fb4bf94eff..3a952a67cd 100644 --- a/cmd/kubeadm/app/master/BUILD +++ b/cmd/kubeadm/app/master/BUILD @@ -23,6 +23,7 @@ go_library( "//cmd/kubeadm/app/constants:go_default_library", "//cmd/kubeadm/app/images:go_default_library", "//cmd/kubeadm/app/util:go_default_library", + "//cmd/kubeadm/app/util/kubeconfig:go_default_library", "//pkg/kubectl/cmd/util:go_default_library", "//vendor:github.com/ghodss/yaml", "//vendor:k8s.io/apimachinery/pkg/api/errors", @@ -35,7 +36,6 @@ go_library( "//vendor:k8s.io/client-go/pkg/api", "//vendor:k8s.io/client-go/pkg/api/v1", "//vendor:k8s.io/client-go/pkg/apis/extensions/v1beta1", - "//vendor:k8s.io/client-go/tools/clientcmd", "//vendor:k8s.io/client-go/util/cert", ], ) diff --git a/cmd/kubeadm/app/master/apiclient.go b/cmd/kubeadm/app/master/apiclient.go index aaaf6dfd3b..dc9d0cd238 100644 --- a/cmd/kubeadm/app/master/apiclient.go +++ b/cmd/kubeadm/app/master/apiclient.go @@ -29,31 +29,14 @@ import ( "k8s.io/client-go/pkg/api" "k8s.io/client-go/pkg/api/v1" extensions "k8s.io/client-go/pkg/apis/extensions/v1beta1" - "k8s.io/client-go/tools/clientcmd" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util" + kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig" ) -func CreateClientFromFile(path string) (*clientset.Clientset, error) { - adminKubeconfig, err := clientcmd.LoadFromFile(path) - if err != nil { - return nil, fmt.Errorf("failed to load admin kubeconfig [%v]", err) - } - adminClientConfig, err := clientcmd.NewDefaultClientConfig(*adminKubeconfig, &clientcmd.ConfigOverrides{}).ClientConfig() - if err != nil { - return nil, fmt.Errorf("failed to create API client configuration [%v]", err) - } - - client, err := clientset.NewForConfig(adminClientConfig) - if err != nil { - return nil, fmt.Errorf("failed to create API client [%v]", err) - } - return client, nil -} - func CreateClientAndWaitForAPI(file string) (*clientset.Clientset, error) { - client, err := CreateClientFromFile(file) + client, err := kubeconfigutil.ClientSetFromFile(file) if err != nil { return nil, err } diff --git a/cmd/kubeadm/app/node/BUILD b/cmd/kubeadm/app/node/BUILD index 407f71f893..6268a30c19 100644 --- a/cmd/kubeadm/app/node/BUILD +++ b/cmd/kubeadm/app/node/BUILD @@ -18,7 +18,7 @@ go_library( tags = ["automanaged"], deps = [ "//cmd/kubeadm/app/apis/kubeadm:go_default_library", - "//cmd/kubeadm/app/phases/kubeconfig:go_default_library", + "//cmd/kubeadm/app/util/kubeconfig:go_default_library", "//cmd/kubeadm/app/util/token:go_default_library", "//pkg/kubelet/util/csr:go_default_library", "//vendor:github.com/square/go-jose", diff --git a/cmd/kubeadm/app/node/bootstrap.go b/cmd/kubeadm/app/node/bootstrap.go index 013a9edc87..11551e4cca 100644 --- a/cmd/kubeadm/app/node/bootstrap.go +++ b/cmd/kubeadm/app/node/bootstrap.go @@ -29,7 +29,7 @@ import ( "k8s.io/client-go/tools/clientcmd" clientcmdapi "k8s.io/client-go/tools/clientcmd/api" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" - kubeconfigphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig" + kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig" tokenutil "k8s.io/kubernetes/cmd/kubeadm/app/util/token" ) @@ -98,7 +98,7 @@ func EstablishMasterConnection(c *kubeadmapi.TokenDiscovery, clusterInfo *kubead // creates a set of clients for this endpoint func createClients(caCert []byte, endpoint, token string, nodeName types.NodeName) (*apiClient, error) { - clientConfig := kubeconfigphase.MakeClientConfigWithToken( + clientConfig := kubeconfigutil.CreateWithToken( endpoint, "kubernetes", fmt.Sprintf("kubelet-%s", nodeName), diff --git a/cmd/kubeadm/app/phases/kubeconfig/BUILD b/cmd/kubeadm/app/phases/kubeconfig/BUILD index ae0c3fdc56..60b887d9a4 100644 --- a/cmd/kubeadm/app/phases/kubeconfig/BUILD +++ b/cmd/kubeadm/app/phases/kubeconfig/BUILD @@ -5,15 +5,6 @@ licenses(["notice"]) load( "@io_bazel_rules_go//go:def.bzl", "go_library", - "go_test", -) - -go_test( - name = "go_default_test", - srcs = ["kubeconfig_test.go"], - library = ":go_default_library", - tags = ["automanaged"], - deps = ["//cmd/kubeadm/app/apis/kubeadm:go_default_library"], ) go_library( @@ -26,6 +17,7 @@ go_library( deps = [ "//cmd/kubeadm/app/constants:go_default_library", "//cmd/kubeadm/app/phases/certs/pkiutil:go_default_library", + "//cmd/kubeadm/app/util/kubeconfig:go_default_library", "//vendor:k8s.io/client-go/tools/clientcmd", "//vendor:k8s.io/client-go/tools/clientcmd/api", "//vendor:k8s.io/client-go/util/cert", diff --git a/cmd/kubeadm/app/phases/kubeconfig/kubeconfig.go b/cmd/kubeadm/app/phases/kubeconfig/kubeconfig.go index 0a9b1279b8..5c2caac16a 100644 --- a/cmd/kubeadm/app/phases/kubeconfig/kubeconfig.go +++ b/cmd/kubeadm/app/phases/kubeconfig/kubeconfig.go @@ -21,7 +21,6 @@ import ( "crypto/rsa" "crypto/x509" "fmt" - "io/ioutil" "os" "path/filepath" @@ -30,15 +29,7 @@ import ( certutil "k8s.io/client-go/util/cert" kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" "k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/pkiutil" -) - -const ( - KubernetesDirPermissions = 0700 - KubeConfigFilePermissions = 0600 - AdminKubeConfigFileName = "admin.conf" - AdminKubeConfigClientName = "kubernetes-admin" - KubeletKubeConfigFileName = "kubelet.conf" - KubeletKubeConfigClientName = "kubelet" + kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig" ) // TODO: Make an integration test for this function that runs after the certificates phase @@ -56,36 +47,36 @@ func CreateAdminAndKubeletKubeConfig(masterEndpoint, pkiDir, outDir string) erro // Try to load ca.crt and ca.key from the PKI directory caCert, caKey, err := pkiutil.TryLoadCertAndKeyFromDisk(pkiDir, kubeadmconstants.CACertAndKeyBaseName) - if err != nil || caCert == nil || caKey == nil { + if err != nil { return fmt.Errorf("couldn't create a kubeconfig; the CA files couldn't be loaded: %v", err) } // User admin should have full access to the cluster // TODO: Add test case that make sure this cert has the x509.ExtKeyUsageClientAuth flag adminCertConfig := certutil.Config{ - CommonName: AdminKubeConfigClientName, + CommonName: "kubernetes-admin", Organization: []string{"system:masters"}, Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth}, } - adminKubeConfigFilePath := filepath.Join(outDir, AdminKubeConfigFileName) + adminKubeConfigFilePath := filepath.Join(outDir, kubeadmconstants.AdminKubeConfigFileName) if err := createKubeConfigFileForClient(masterEndpoint, adminKubeConfigFilePath, adminCertConfig, caCert, caKey); err != nil { - return fmt.Errorf("couldn't create config for %s: %v", AdminKubeConfigClientName, err) + return fmt.Errorf("couldn't create config for the admin: %v", err) } // TODO: The kubelet should have limited access to the cluster. Right now, this gives kubelet basically root access // and we do need that in the bootstrap phase, but we should swap it out after the control plane is up // TODO: Add test case that make sure this cert has the x509.ExtKeyUsageClientAuth flag kubeletCertConfig := certutil.Config{ - CommonName: KubeletKubeConfigClientName, + CommonName: "kubelet", Organization: []string{"system:nodes"}, Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth}, } - kubeletKubeConfigFilePath := filepath.Join(outDir, KubeletKubeConfigFileName) + kubeletKubeConfigFilePath := filepath.Join(outDir, kubeadmconstants.KubeletKubeConfigFileName) if err := createKubeConfigFileForClient(masterEndpoint, kubeletKubeConfigFilePath, kubeletCertConfig, caCert, caKey); err != nil { - return fmt.Errorf("couldn't create a kubeconfig file for %s: %v", KubeletKubeConfigClientName, err) + return fmt.Errorf("couldn't create a kubeconfig file for the kubelet: %v", err) } - // TODO make credentials for the controller-manager, scheduler and kube-proxy + // TODO make credentials for the controller-manager and scheduler return nil } @@ -95,7 +86,7 @@ func createKubeConfigFileForClient(masterEndpoint, kubeConfigFilePath string, co return fmt.Errorf("failure while creating %s client certificate [%v]", config.CommonName, err) } - kubeconfig := MakeClientConfigWithCerts( + kubeconfig := kubeconfigutil.CreateWithCerts( masterEndpoint, "kubernetes", config.CommonName, @@ -108,30 +99,6 @@ func createKubeConfigFileForClient(masterEndpoint, kubeConfigFilePath string, co return writeKubeconfigToDiskIfNotExists(kubeConfigFilePath, kubeconfig) } -func WriteKubeconfigToDisk(filename string, kubeconfig *clientcmdapi.Config) error { - // Convert the KubeConfig object to a byte array - content, err := clientcmd.Write(*kubeconfig) - if err != nil { - return err - } - - // Create the directory if it does not exist - dir := filepath.Dir(filename) - if _, err := os.Stat(dir); os.IsNotExist(err) { - if err = os.MkdirAll(dir, KubernetesDirPermissions); err != nil { - return err - } - } - - // No such kubeconfig file exists; write that kubeconfig down to disk then - if err := ioutil.WriteFile(filename, content, KubeConfigFilePermissions); err != nil { - return err - } - - fmt.Printf("[kubeconfig] Wrote KubeConfig file to disk: %q\n", filename) - return nil -} - // writeKubeconfigToDiskIfNotExists saves the KubeConfig struct to disk if there isn't any file at the given path // If there already is a KubeConfig file at the given path; kubeadm tries to load it and check if the values in the // existing and the expected config equals. If they do; kubeadm will just skip writing the file as it's up-to-date, @@ -139,7 +106,7 @@ func WriteKubeconfigToDisk(filename string, kubeconfig *clientcmdapi.Config) err func writeKubeconfigToDiskIfNotExists(filename string, expectedConfig *clientcmdapi.Config) error { // Check if the file exist, and if it doesn't, just write it to disk if _, err := os.Stat(filename); os.IsNotExist(err) { - return WriteKubeconfigToDisk(filename, expectedConfig) + return kubeconfigutil.WriteToDisk(filename, expectedConfig) } // The kubeconfig already exists, let's check if it has got the same CA and server URL @@ -168,47 +135,3 @@ func writeKubeconfigToDiskIfNotExists(filename string, expectedConfig *clientcmd return nil } - -func createBasicClientConfig(serverURL string, clusterName string, userName string, caCert []byte) *clientcmdapi.Config { - config := clientcmdapi.NewConfig() - - // Make a new cluster, specify the endpoint we'd like to talk to and the ca cert we're gonna use - cluster := clientcmdapi.NewCluster() - cluster.Server = serverURL - cluster.CertificateAuthorityData = caCert - - // Specify a context where we're using that cluster and the username as the auth information - contextName := fmt.Sprintf("%s@%s", userName, clusterName) - context := clientcmdapi.NewContext() - context.Cluster = clusterName - context.AuthInfo = userName - - // Lastly, apply the created objects above to the config - config.Clusters[clusterName] = cluster - config.Contexts[contextName] = context - config.CurrentContext = contextName - return config -} - -// Creates a clientcmdapi.Config object with access to the API server with client certificates -func MakeClientConfigWithCerts(serverURL, clusterName, userName string, caCert []byte, clientKey []byte, clientCert []byte) *clientcmdapi.Config { - config := createBasicClientConfig(serverURL, clusterName, userName, caCert) - - authInfo := clientcmdapi.NewAuthInfo() - authInfo.ClientKeyData = clientKey - authInfo.ClientCertificateData = clientCert - - config.AuthInfos[userName] = authInfo - return config -} - -// Creates a clientcmdapi.Config object with access to the API server with a token -func MakeClientConfigWithToken(serverURL, clusterName, userName string, caCert []byte, token string) *clientcmdapi.Config { - config := createBasicClientConfig(serverURL, clusterName, userName, caCert) - - authInfo := clientcmdapi.NewAuthInfo() - authInfo.Token = token - - config.AuthInfos[userName] = authInfo - return config -} diff --git a/cmd/kubeadm/app/preflight/BUILD b/cmd/kubeadm/app/preflight/BUILD index 9db917d2b1..d967b98999 100644 --- a/cmd/kubeadm/app/preflight/BUILD +++ b/cmd/kubeadm/app/preflight/BUILD @@ -15,7 +15,6 @@ go_library( deps = [ "//cmd/kubeadm/app/apis/kubeadm:go_default_library", "//cmd/kubeadm/app/constants:go_default_library", - "//cmd/kubeadm/app/phases/kubeconfig:go_default_library", "//pkg/api/validation:go_default_library", "//pkg/util/initsystem:go_default_library", "//pkg/util/node:go_default_library", diff --git a/cmd/kubeadm/app/preflight/checks.go b/cmd/kubeadm/app/preflight/checks.go index 93446fc851..d94b752f0c 100644 --- a/cmd/kubeadm/app/preflight/checks.go +++ b/cmd/kubeadm/app/preflight/checks.go @@ -30,7 +30,6 @@ import ( utilerrors "k8s.io/apimachinery/pkg/util/errors" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" - "k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig" "k8s.io/kubernetes/pkg/api/validation" "k8s.io/kubernetes/pkg/util/initsystem" "k8s.io/kubernetes/pkg/util/node" @@ -386,7 +385,7 @@ func RunJoinNodeChecks(cfg *kubeadmapi.NodeConfiguration) error { DirAvailableCheck{Path: filepath.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, "manifests")}, DirAvailableCheck{Path: "/var/lib/kubelet"}, FileAvailableCheck{Path: filepath.Join(kubeadmapi.GlobalEnvParams.HostPKIPath, kubeadmconstants.CACertName)}, - FileAvailableCheck{Path: filepath.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, kubeconfig.KubeletKubeConfigFileName)}, + FileAvailableCheck{Path: filepath.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, kubeadmconstants.KubeletKubeConfigFileName)}, FileContentCheck{Path: bridgenf, Content: []byte{'1'}}, InPathCheck{executable: "ip", mandatory: true}, InPathCheck{executable: "iptables", mandatory: true}, diff --git a/cmd/kubeadm/app/util/BUILD b/cmd/kubeadm/app/util/BUILD index 21cd36b409..1b2a4d7802 100644 --- a/cmd/kubeadm/app/util/BUILD +++ b/cmd/kubeadm/app/util/BUILD @@ -42,6 +42,7 @@ filegroup( name = "all-srcs", srcs = [ ":package-srcs", + "//cmd/kubeadm/app/util/kubeconfig:all-srcs", "//cmd/kubeadm/app/util/token:all-srcs", ], tags = ["automanaged"], diff --git a/cmd/kubeadm/app/util/kubeconfig/BUILD b/cmd/kubeadm/app/util/kubeconfig/BUILD new file mode 100644 index 0000000000..9d7d03b855 --- /dev/null +++ b/cmd/kubeadm/app/util/kubeconfig/BUILD @@ -0,0 +1,41 @@ +package(default_visibility = ["//visibility:public"]) + +licenses(["notice"]) + +load( + "@io_bazel_rules_go//go:def.bzl", + "go_library", + "go_test", +) + +go_test( + name = "go_default_test", + srcs = ["kubeconfig_test.go"], + library = ":go_default_library", + tags = ["automanaged"], + deps = ["//cmd/kubeadm/app/apis/kubeadm:go_default_library"], +) + +go_library( + name = "go_default_library", + srcs = ["kubeconfig.go"], + tags = ["automanaged"], + deps = [ + "//vendor:k8s.io/client-go/kubernetes", + "//vendor:k8s.io/client-go/tools/clientcmd", + "//vendor:k8s.io/client-go/tools/clientcmd/api", + ], +) + +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/util/kubeconfig/kubeconfig.go b/cmd/kubeadm/app/util/kubeconfig/kubeconfig.go new file mode 100644 index 0000000000..6724f60e51 --- /dev/null +++ b/cmd/kubeadm/app/util/kubeconfig/kubeconfig.go @@ -0,0 +1,101 @@ +/* +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 kubeconfig + +import ( + "fmt" + + clientset "k8s.io/client-go/kubernetes" + "k8s.io/client-go/tools/clientcmd" + clientcmdapi "k8s.io/client-go/tools/clientcmd/api" +) + +// CreateBasic creates a basic, general KubeConfig object that then can be extended +func CreateBasic(serverURL string, clusterName string, userName string, caCert []byte) *clientcmdapi.Config { + // Use the cluster and the username as the context name + contextName := fmt.Sprintf("%s@%s", userName, clusterName) + + return &clientcmdapi.Config{ + Clusters: map[string]*clientcmdapi.Cluster{ + clusterName: { + Server: serverURL, + CertificateAuthorityData: caCert, + }, + }, + Contexts: map[string]*clientcmdapi.Context{ + contextName: { + Cluster: clusterName, + AuthInfo: userName, + }, + }, + AuthInfos: map[string]*clientcmdapi.AuthInfo{}, + CurrentContext: contextName, + } +} + +// CreateWithCerts creates a KubeConfig object with access to the API server with client certificates +func CreateWithCerts(serverURL, clusterName, userName string, caCert []byte, clientKey []byte, clientCert []byte) *clientcmdapi.Config { + config := CreateBasic(serverURL, clusterName, userName, caCert) + config.AuthInfos[userName] = &clientcmdapi.AuthInfo{ + ClientKeyData: clientKey, + ClientCertificateData: clientCert, + } + return config +} + +// CreateWithToken creates a KubeConfig object with access to the API server with a token +func CreateWithToken(serverURL, clusterName, userName string, caCert []byte, token string) *clientcmdapi.Config { + config := CreateBasic(serverURL, clusterName, userName, caCert) + config.AuthInfos[userName] = &clientcmdapi.AuthInfo{ + Token: token, + } + return config +} + +// ClientSetFromFile returns a ready-to-use client from a KubeConfig file +func ClientSetFromFile(path string) (*clientset.Clientset, error) { + config, err := clientcmd.LoadFromFile(path) + if err != nil { + return nil, fmt.Errorf("failed to load admin kubeconfig [%v]", err) + } + return KubeConfigToClientSet(config) +} + +// KubeConfigToClientSet converts a KubeConfig object to a client +func KubeConfigToClientSet(config *clientcmdapi.Config) (*clientset.Clientset, error) { + clientConfig, err := clientcmd.NewDefaultClientConfig(*config, &clientcmd.ConfigOverrides{}).ClientConfig() + if err != nil { + return nil, fmt.Errorf("failed to create API client configuration from kubeconfig: %v", err) + } + + client, err := clientset.NewForConfig(clientConfig) + if err != nil { + return nil, fmt.Errorf("failed to create API client: %v", err) + } + return client, nil +} + +// WriteToDisk writes a KubeConfig object down to disk with mode 0600 +func WriteToDisk(filename string, kubeconfig *clientcmdapi.Config) error { + err := clientcmd.WriteToFile(*kubeconfig, filename) + if err != nil { + return err + } + + fmt.Printf("[kubeconfig] Wrote KubeConfig file to disk: %q\n", filename) + return nil +} diff --git a/cmd/kubeadm/app/phases/kubeconfig/kubeconfig_test.go b/cmd/kubeadm/app/util/kubeconfig/kubeconfig_test.go similarity index 86% rename from cmd/kubeadm/app/phases/kubeconfig/kubeconfig_test.go rename to cmd/kubeadm/app/util/kubeconfig/kubeconfig_test.go index 170d90416b..96f3a45460 100644 --- a/cmd/kubeadm/app/phases/kubeconfig/kubeconfig_test.go +++ b/cmd/kubeadm/app/util/kubeconfig/kubeconfig_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors. +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. @@ -82,7 +82,7 @@ type configClientWithToken struct { token string } -func TestMakeClientConfigWithCerts(t *testing.T) { +func TestCreateWithCerts(t *testing.T) { var createBasicTest = []struct { cc configClient ccWithCerts configClientWithCerts @@ -92,7 +92,7 @@ func TestMakeClientConfigWithCerts(t *testing.T) { {configClient{clusterName: "kubernetes"}, configClientWithCerts{}, ""}, } for _, rt := range createBasicTest { - cwc := MakeClientConfigWithCerts( + cwc := CreateWithCerts( rt.cc.serverURL, rt.cc.clusterName, rt.cc.userName, @@ -102,7 +102,7 @@ func TestMakeClientConfigWithCerts(t *testing.T) { ) if cwc.Kind != rt.expected { t.Errorf( - "failed MakeClientConfigWithCerts:\n\texpected: %s\n\t actual: %s", + "failed CreateWithCerts:\n\texpected: %s\n\t actual: %s", rt.expected, cwc.Kind, ) @@ -110,7 +110,7 @@ func TestMakeClientConfigWithCerts(t *testing.T) { } } -func TestMakeClientConfigWithToken(t *testing.T) { +func TestCreateWithToken(t *testing.T) { var createBasicTest = []struct { cc configClient ccWithToken configClientWithToken @@ -120,7 +120,7 @@ func TestMakeClientConfigWithToken(t *testing.T) { {configClient{clusterName: "kubernetes"}, configClientWithToken{}, ""}, } for _, rt := range createBasicTest { - cwc := MakeClientConfigWithToken( + cwc := CreateWithToken( rt.cc.serverURL, rt.cc.clusterName, rt.cc.userName, @@ -129,7 +129,7 @@ func TestMakeClientConfigWithToken(t *testing.T) { ) if cwc.Kind != rt.expected { t.Errorf( - "failed MakeClientConfigWithCerts:\n\texpected: %s\n\t actual: %s", + "failed CreateWithToken:\n\texpected: %s\n\t actual: %s", rt.expected, cwc.Kind, ) @@ -161,7 +161,7 @@ func TestWriteKubeconfigToDisk(t *testing.T) { {"test2", configClient{clusterName: "kubernetes", userName: "user2", serverURL: "localhost:8080"}, configClientWithToken{token: "cba"}, nil, []byte(configOut2)}, } for _, rt := range writeConfig { - c := MakeClientConfigWithToken( + c := CreateWithToken( rt.cc.serverURL, rt.cc.clusterName, rt.cc.userName, @@ -169,10 +169,10 @@ func TestWriteKubeconfigToDisk(t *testing.T) { rt.ccWithToken.token, ) configPath := filepath.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, fmt.Sprintf("%s.conf", rt.name)) - err := WriteKubeconfigToDisk(configPath, c) + err := WriteToDisk(configPath, c) if err != rt.expected { t.Errorf( - "failed WriteKubeconfigToDisk with an error:\n\texpected: %s\n\t actual: %s", + "failed WriteToDisk with an error:\n\texpected: %s\n\t actual: %s", rt.expected, err, ) @@ -180,7 +180,7 @@ func TestWriteKubeconfigToDisk(t *testing.T) { newFile, _ := ioutil.ReadFile(configPath) if !bytes.Equal(newFile, rt.file) { t.Errorf( - "failed WriteKubeconfigToDisk config write:\n\texpected: %s\n\t actual: %s", + "failed WriteToDisk config write:\n\texpected: %s\n\t actual: %s", rt.file, newFile, ) diff --git a/federation/pkg/kubefed/init/BUILD b/federation/pkg/kubefed/init/BUILD index 96938a8d7f..8606b56fc2 100644 --- a/federation/pkg/kubefed/init/BUILD +++ b/federation/pkg/kubefed/init/BUILD @@ -13,7 +13,7 @@ go_library( srcs = ["init.go"], tags = ["automanaged"], deps = [ - "//cmd/kubeadm/app/phases/kubeconfig:go_default_library", + "//cmd/kubeadm/app/util/kubeconfig:go_default_library", "//federation/pkg/kubefed/util:go_default_library", "//pkg/api:go_default_library", "//pkg/api/v1:go_default_library", diff --git a/federation/pkg/kubefed/init/init.go b/federation/pkg/kubefed/init/init.go index 67e3ae38e0..d54769cae6 100644 --- a/federation/pkg/kubefed/init/init.go +++ b/federation/pkg/kubefed/init/init.go @@ -46,7 +46,7 @@ import ( clientcmdapi "k8s.io/client-go/tools/clientcmd/api" certutil "k8s.io/client-go/util/cert" triple "k8s.io/client-go/util/cert/triple" - kubeadmkubeconfigphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig" + kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig" "k8s.io/kubernetes/federation/pkg/kubefed/util" "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/v1" @@ -513,7 +513,7 @@ func createAPIServerCredentialsSecret(clientset *client.Clientset, namespace, cr } func createControllerManagerKubeconfigSecret(clientset *client.Clientset, namespace, name, svcName, kubeconfigName string, entKeyPairs *entityKeyPairs, dryRun bool) (*api.Secret, error) { - config := kubeadmkubeconfigphase.MakeClientConfigWithCerts( + config := kubeconfigutil.CreateWithCerts( fmt.Sprintf("https://%s", svcName), name, ControllerManagerUser, diff --git a/hack/.linted_packages b/hack/.linted_packages index 11847a3178..53d8b4c353 100644 --- a/hack/.linted_packages +++ b/hack/.linted_packages @@ -19,6 +19,7 @@ cmd/kubeadm cmd/kubeadm/app/apis/kubeadm/install cmd/kubeadm/app/phases/apiconfig cmd/kubeadm/app/phases/certs +cmd/kubeadm/app/phases/kubeconfig cmd/kubectl cmd/kubelet cmd/libs/go2idl/client-gen