Skip to content

Commit

Permalink
Merge pull request #94879 from knight42/refactor/kubeadm-alpha-kubeco…
Browse files Browse the repository at this point in the history
…nfig

kubeadm: make "alpha kubeconfig user" accept --config
  • Loading branch information
k8s-ci-robot committed Sep 22, 2020
2 parents b03a4ac + 36eb74a commit 9f32854
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 44 deletions.
2 changes: 2 additions & 0 deletions cmd/kubeadm/app/cmd/alpha/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,12 @@ go_test(
"//cmd/kubeadm/test:go_default_library",
"//cmd/kubeadm/test/cmd:go_default_library",
"//cmd/kubeadm/test/kubeconfig:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/client-go/tools/clientcmd:go_default_library",
"//vendor/github.com/spf13/cobra:go_default_library",
"//vendor/github.com/spf13/pflag:go_default_library",
"//vendor/github.com/stretchr/testify/assert:go_default_library",
"//vendor/github.com/stretchr/testify/require:go_default_library",
"//vendor/sigs.k8s.io/yaml:go_default_library",
],
)
37 changes: 13 additions & 24 deletions cmd/kubeadm/app/cmd/alpha/kubeconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,8 @@ package alpha
import (
"io"

"github.com/pkg/errors"
"github.com/spf13/cobra"
kubeadmscheme "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/scheme"

kubeadmapiv1beta2 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta2"
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util"
Expand All @@ -39,8 +38,8 @@ var (
` + cmdutil.AlphaDisclaimer)

userKubeconfigExample = cmdutil.Examples(`
# Output a kubeconfig file for an additional user named foo
kubeadm alpha kubeconfig user --client-name=foo
# Output a kubeconfig file for an additional user named foo using a kubeadm config file bar
kubeadm alpha kubeconfig user --client-name=foo --config=bar
`)
)

Expand All @@ -62,12 +61,10 @@ func newCmdUserKubeConfig(out io.Writer) *cobra.Command {
initCfg := &kubeadmapiv1beta2.InitConfiguration{}
clusterCfg := &kubeadmapiv1beta2.ClusterConfiguration{}

// Default values for the cobra help text
kubeadmscheme.Scheme.Default(initCfg)
kubeadmscheme.Scheme.Default(clusterCfg)

var token, clientName string
var organizations []string
var (
token, clientName, cfgPath string
organizations []string
)

// Creates the UX Command
cmd := &cobra.Command{
Expand All @@ -76,39 +73,31 @@ func newCmdUserKubeConfig(out io.Writer) *cobra.Command {
Long: userKubeconfigLongDesc,
Example: userKubeconfigExample,
RunE: func(cmd *cobra.Command, args []string) error {
if clientName == "" {
return errors.New("missing required argument --client-name")
}

// This call returns the ready-to-use configuration based on the defaults populated by flags
internalcfg, err := configutil.DefaultedInitConfiguration(initCfg, clusterCfg)
internalCfg, err := configutil.LoadOrDefaultInitConfiguration(cfgPath, initCfg, clusterCfg)
if err != nil {
return err
}

// if the kubeconfig file for an additional user has to use a token, use it
if token != "" {
return kubeconfigphase.WriteKubeConfigWithToken(out, internalcfg, clientName, token)
return kubeconfigphase.WriteKubeConfigWithToken(out, internalCfg, clientName, token)
}

// Otherwise, write a kubeconfig file with a generate client cert
return kubeconfigphase.WriteKubeConfigWithClientCert(out, internalcfg, clientName, organizations)
return kubeconfigphase.WriteKubeConfigWithClientCert(out, internalCfg, clientName, organizations)
},
Args: cobra.NoArgs,
}

// Add ClusterConfiguration backed flags to the command
cmd.Flags().StringVar(&clusterCfg.CertificatesDir, options.CertificatesDir, clusterCfg.CertificatesDir, "The path where certificates are stored")
cmd.Flags().StringVar(&clusterCfg.ClusterName, "cluster-name", clusterCfg.ClusterName, "Cluster name to be used in kubeconfig")

// Add InitConfiguration backed flags to the command
cmd.Flags().StringVar(&initCfg.LocalAPIEndpoint.AdvertiseAddress, options.APIServerAdvertiseAddress, initCfg.LocalAPIEndpoint.AdvertiseAddress, "The IP address the API server is accessible on")
cmd.Flags().Int32Var(&initCfg.LocalAPIEndpoint.BindPort, options.APIServerBindPort, initCfg.LocalAPIEndpoint.BindPort, "The port the API server is accessible on")
options.AddConfigFlag(cmd.Flags(), &cfgPath)

// Add command specific flags
cmd.Flags().StringVar(&token, options.TokenStr, 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")

cmd.MarkFlagRequired(options.CfgPath)
cmd.MarkFlagRequired("client-name")
return cmd
}
86 changes: 66 additions & 20 deletions cmd/kubeadm/app/cmd/alpha/kubeconfig_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,61 @@ package alpha
import (
"bytes"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"testing"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/tools/clientcmd"
"sigs.k8s.io/yaml"

kubeadmapiv1beta2 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta2"
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 generateTestKubeadmConfig(dir, id, certDir, clusterName string) (string, error) {
cfgPath := filepath.Join(dir, id)
initCfg := kubeadmapiv1beta2.InitConfiguration{
TypeMeta: metav1.TypeMeta{
APIVersion: "kubeadm.k8s.io/v1beta2",
Kind: "InitConfiguration",
},
LocalAPIEndpoint: kubeadmapiv1beta2.APIEndpoint{
AdvertiseAddress: "1.2.3.4",
BindPort: 1234,
},
}
clusterCfg := kubeadmapiv1beta2.ClusterConfiguration{
TypeMeta: metav1.TypeMeta{
APIVersion: "kubeadm.k8s.io/v1beta2",
Kind: "ClusterConfiguration",
},
CertificatesDir: certDir,
ClusterName: clusterName,
KubernetesVersion: "v1.19.0",
}

var buf bytes.Buffer
data, err := yaml.Marshal(&initCfg)
if err != nil {
return "", err
}
buf.Write(data)
buf.WriteString("---\n")
data, err = yaml.Marshal(&clusterCfg)
if err != nil {
return "", err
}
buf.Write(data)

err = ioutil.WriteFile(cfgPath, buf.Bytes(), 0644)
return cfgPath, err
}

func TestKubeConfigSubCommandsThatWritesToOut(t *testing.T) {

// Temporary folders for the test case
Expand All @@ -44,19 +89,12 @@ func TestKubeConfigSubCommandsThatWritesToOut(t *testing.T) {
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
clusterName string
withClientCert bool
withToken bool
withClusterName bool
additionalFlags []string
}{
{
Expand All @@ -65,11 +103,10 @@ func TestKubeConfigSubCommandsThatWritesToOut(t *testing.T) {
withClientCert: true,
},
{
name: "user subCommand withClientCert",
command: "user",
withClientCert: true,
withClusterName: true,
additionalFlags: []string{"--cluster-name=my-cluster"},
name: "user subCommand withClientCert",
command: "user",
withClientCert: true,
clusterName: "my-cluster",
},
{
name: "user subCommand withToken",
Expand All @@ -81,8 +118,8 @@ func TestKubeConfigSubCommandsThatWritesToOut(t *testing.T) {
name: "user subCommand withToken",
withToken: true,
command: "user",
withClusterName: true,
additionalFlags: []string{"--token=123456", "--cluster-name=my-cluster"},
clusterName: "my-cluster-with-token",
additionalFlags: []string{"--token=123456"},
},
}

Expand All @@ -93,18 +130,27 @@ func TestKubeConfigSubCommandsThatWritesToOut(t *testing.T) {
// Get subcommands working in the temporary directory
cmd := newCmdUserKubeConfig(buf)

cfgPath, err := generateTestKubeadmConfig(tmpdir, test.name, pkidir, test.clusterName)
if err != nil {
t.Fatalf("Failed to generate kubeadm config: %v", err)
}

commonFlags := []string{
"--client-name=myUser",
fmt.Sprintf("--config=%s", cfgPath),
}

// Execute the subcommand
allFlags := append(commonFlags, test.additionalFlags...)
cmd.SetArgs(allFlags)
if err := cmd.Execute(); err != nil {
t.Fatal("Could not execute subcommand")
t.Fatalf("Could not execute subcommand: %v", err)
}

// 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
t.Fatalf("couldn't read kubeconfig file from buffer: %v", err)
}

// checks that CLI flags are properly propagated
Expand All @@ -120,9 +166,9 @@ func TestKubeConfigSubCommandsThatWritesToOut(t *testing.T) {
kubeconfigtestutil.AssertKubeConfigCurrentAuthInfoWithToken(t, config, "myUser", "123456")
}

if test.withClusterName {
if len(test.clusterName) > 0 {
// checks that kubeconfig files have expected cluster name
kubeconfigtestutil.AssertKubeConfigCurrentContextWithClusterName(t, config, "my-cluster")
kubeconfigtestutil.AssertKubeConfigCurrentContextWithClusterName(t, config, test.clusterName)
}
})
}
Expand Down

0 comments on commit 9f32854

Please sign in to comment.