mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 11:50:44 +00:00
Merge pull request #62850 from neolit123/token-config
Automatic merge from submit-queue (batch tested with PRs 62850, 63504). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>. kubeadm-token: search for existing kubeconfig files **What this PR does / why we need it**: Add means to search the current user home path and the environment variable KUBECONFIG for existing files if the user does not provide a --kubeconfig flag. If the user provides a --kubeconfig flag respect it. **Which issue(s) this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close the issue(s) when PR gets merged)*: Fixes https://github.com/kubernetes/kubeadm/issues/198 **Special notes for your reviewer**: i'm not 100% sure if that's the correct approach and if that's what's requested. so let's discuss it. **Release note**: ```release-note Search standard KubeConfig file locations when using `kubeadm token` without `--kubeconfig`. ```
This commit is contained in:
commit
24e5265dbc
@ -73,6 +73,7 @@ go_library(
|
||||
"//vendor/k8s.io/apiserver/pkg/util/flag:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/bootstrap/token/api:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/clientcmd:go_default_library",
|
||||
"//vendor/k8s.io/client-go/util/cert:go_default_library",
|
||||
"//vendor/k8s.io/utils/exec:go_default_library",
|
||||
],
|
||||
@ -102,6 +103,7 @@ go_test(
|
||||
"//vendor/k8s.io/client-go/kubernetes/fake:go_default_library",
|
||||
"//vendor/k8s.io/client-go/testing:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/bootstrap/token/api:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/clientcmd:go_default_library",
|
||||
"//vendor/k8s.io/utils/exec:go_default_library",
|
||||
"//vendor/k8s.io/utils/exec/testing:go_default_library",
|
||||
],
|
||||
|
@ -35,6 +35,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/duration"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
bootstrapapi "k8s.io/client-go/tools/bootstrap/token/api"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
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"
|
||||
@ -50,6 +51,8 @@ import (
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
)
|
||||
|
||||
const defaultKubeConfig = "/etc/kubernetes/admin.conf"
|
||||
|
||||
// NewCmdToken returns cobra.Command for token management
|
||||
func NewCmdToken(out io.Writer, errW io.Writer) *cobra.Command {
|
||||
var kubeConfigFile string
|
||||
@ -85,7 +88,7 @@ func NewCmdToken(out io.Writer, errW io.Writer) *cobra.Command {
|
||||
}
|
||||
|
||||
tokenCmd.PersistentFlags().StringVar(&kubeConfigFile,
|
||||
"kubeconfig", "/etc/kubernetes/admin.conf", "The KubeConfig file to use when talking to the cluster")
|
||||
"kubeconfig", defaultKubeConfig, "The KubeConfig file to use when talking to the cluster. If the flag is not set a set of standard locations are searched for an existing KubeConfig file")
|
||||
tokenCmd.PersistentFlags().BoolVar(&dryRun,
|
||||
"dry-run", dryRun, "Whether to enable dry-run mode or not")
|
||||
|
||||
@ -121,6 +124,7 @@ func NewCmdToken(out io.Writer, errW io.Writer) *cobra.Command {
|
||||
kubeadmutil.CheckErr(err)
|
||||
|
||||
glog.V(1).Infoln("[token] getting Clientsets from KubeConfig file")
|
||||
kubeConfigFile = findExistingKubeConfig(kubeConfigFile)
|
||||
client, err := getClientset(kubeConfigFile, dryRun)
|
||||
kubeadmutil.CheckErr(err)
|
||||
|
||||
@ -152,6 +156,7 @@ func NewCmdToken(out io.Writer, errW io.Writer) *cobra.Command {
|
||||
This command will list all bootstrap tokens for you.
|
||||
`),
|
||||
Run: func(tokenCmd *cobra.Command, args []string) {
|
||||
kubeConfigFile = findExistingKubeConfig(kubeConfigFile)
|
||||
client, err := getClientset(kubeConfigFile, dryRun)
|
||||
kubeadmutil.CheckErr(err)
|
||||
|
||||
@ -175,6 +180,7 @@ func NewCmdToken(out io.Writer, errW io.Writer) *cobra.Command {
|
||||
if len(args) < 1 {
|
||||
kubeadmutil.CheckErr(fmt.Errorf("missing subcommand; 'token delete' is missing token of form [%q]", tokenutil.TokenIDRegexpString))
|
||||
}
|
||||
kubeConfigFile = findExistingKubeConfig(kubeConfigFile)
|
||||
client, err := getClientset(kubeConfigFile, dryRun)
|
||||
kubeadmutil.CheckErr(err)
|
||||
|
||||
@ -381,3 +387,16 @@ func getClientset(file string, dryRun bool) (clientset.Interface, error) {
|
||||
}
|
||||
return kubeconfigutil.ClientSetFromFile(file)
|
||||
}
|
||||
|
||||
func findExistingKubeConfig(file string) string {
|
||||
// The user did provide a --kubeconfig flag. Respect that and threat it as an
|
||||
// explicit path without building a DefaultClientConfigLoadingRules object.
|
||||
if file != defaultKubeConfig {
|
||||
return file
|
||||
}
|
||||
// The user did not provide a --kubeconfig flag. Find a config in the standard
|
||||
// locations using DefaultClientConfigLoadingRules, but also consider `defaultKubeConfig`.
|
||||
rules := clientcmd.NewDefaultClientConfigLoadingRules()
|
||||
rules.Precedence = append(rules.Precedence, defaultKubeConfig)
|
||||
return rules.GetDefaultFilename()
|
||||
}
|
||||
|
@ -37,12 +37,13 @@ import (
|
||||
"k8s.io/client-go/kubernetes/fake"
|
||||
core "k8s.io/client-go/testing"
|
||||
bootstrapapi "k8s.io/client-go/tools/bootstrap/token/api"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
kubeadmapiext "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha1"
|
||||
)
|
||||
|
||||
const (
|
||||
TokenExpectedRegex = "^\\S{6}\\.\\S{16}\n$"
|
||||
TestConfig = `apiVersion: v1
|
||||
tokenExpectedRegex = "^\\S{6}\\.\\S{16}\n$"
|
||||
testConfigToken = `apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
certificate-authority-data:
|
||||
@ -63,8 +64,8 @@ users:
|
||||
client-certificate-data:
|
||||
client-key-data:
|
||||
`
|
||||
TestConfigCertAuthorityData = "certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5RENDQWJDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRFM01USXhOREUxTlRFek1Gb1hEVEkzTVRJeE1qRTFOVEV6TUZvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTlZrCnNkT0NjRDBIOG9ycXZ5djBEZ09jZEpjRGc4aTJPNGt3QVpPOWZUanJGRHJqbDZlVXRtdlMyZ1lZd0c4TGhPV2gKb0lkZ3AvbVkrbVlDakliUUJtTmE2Ums1V2JremhJRzM1c1lseE9NVUJJR0xXMzN0RTh4SlR1RVd3V0NmZnpLcQpyaU1UT1A3REF3MUxuM2xUNlpJNGRNM09NOE1IUk9Wd3lRMDVpbWo5eUx5R1lYdTlvSncwdTVXWVpFYmpUL3VpCjJBZ2QwVDMrZGFFb044aVBJOTlVQkQxMzRkc2VGSEJEY3hHcmsvVGlQdHBpSC9IOGoxRWZaYzRzTGlONzJmL2YKYUpacTROSHFiT2F5UkpITCtJejFNTW1DRkN3cjdHOHVENWVvWWp2dEdZN2xLc1pBTlUwK3VlUnJsTitxTzhQWQpxaTZNMDFBcmV1UzFVVHFuTkM4Q0F3RUFBYU1qTUNFd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFNbXo4Nm9LMmFLa0owMnlLSC9ZcTlzaDZZcDEKYmhLS25mMFJCaTA1clRacWdhTi9oTnROdmQxSzJxZGRLNzhIT2pVdkpNRGp3NERieXF0Wll2V01XVFRCQnQrSgpPMGNyWkg5NXlqUW42YzRlcU1FTjFhOUFKNXRlclNnTDVhREJsK0FMTWxaNVpxTzBUOUJDdTJtNXV3dGNWaFZuCnh6cGpTT3V5WVdOQ3A5bW9mV2VPUTljNXhEcElWeUlMUkFvNmZ5Z2c3N25TSDN4ckVmd0VKUHFMd1RPYVk1bTcKeEZWWWJoR3dxUGU5V0I5aTR5cnNrZUFBWlpUSzdVbklKMXFkRmlHQk9aZlRtaDhYQ3BOTHZZcFBLQW9hWWlsRwpjOW1acVhpWVlESTV6R1IxMElpc2FWNXJUY2hDenNQVWRhQzRVbnpTZG01cTdKYTAyb0poQlU1TE1FMD0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo="
|
||||
TestConfigNoCluster = `apiVersion: v1
|
||||
testConfigTokenCertAuthorityData = "certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5RENDQWJDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRFM01USXhOREUxTlRFek1Gb1hEVEkzTVRJeE1qRTFOVEV6TUZvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTlZrCnNkT0NjRDBIOG9ycXZ5djBEZ09jZEpjRGc4aTJPNGt3QVpPOWZUanJGRHJqbDZlVXRtdlMyZ1lZd0c4TGhPV2gKb0lkZ3AvbVkrbVlDakliUUJtTmE2Ums1V2JremhJRzM1c1lseE9NVUJJR0xXMzN0RTh4SlR1RVd3V0NmZnpLcQpyaU1UT1A3REF3MUxuM2xUNlpJNGRNM09NOE1IUk9Wd3lRMDVpbWo5eUx5R1lYdTlvSncwdTVXWVpFYmpUL3VpCjJBZ2QwVDMrZGFFb044aVBJOTlVQkQxMzRkc2VGSEJEY3hHcmsvVGlQdHBpSC9IOGoxRWZaYzRzTGlONzJmL2YKYUpacTROSHFiT2F5UkpITCtJejFNTW1DRkN3cjdHOHVENWVvWWp2dEdZN2xLc1pBTlUwK3VlUnJsTitxTzhQWQpxaTZNMDFBcmV1UzFVVHFuTkM4Q0F3RUFBYU1qTUNFd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFNbXo4Nm9LMmFLa0owMnlLSC9ZcTlzaDZZcDEKYmhLS25mMFJCaTA1clRacWdhTi9oTnROdmQxSzJxZGRLNzhIT2pVdkpNRGp3NERieXF0Wll2V01XVFRCQnQrSgpPMGNyWkg5NXlqUW42YzRlcU1FTjFhOUFKNXRlclNnTDVhREJsK0FMTWxaNVpxTzBUOUJDdTJtNXV3dGNWaFZuCnh6cGpTT3V5WVdOQ3A5bW9mV2VPUTljNXhEcElWeUlMUkFvNmZ5Z2c3N25TSDN4ckVmd0VKUHFMd1RPYVk1bTcKeEZWWWJoR3dxUGU5V0I5aTR5cnNrZUFBWlpUSzdVbklKMXFkRmlHQk9aZlRtaDhYQ3BOTHZZcFBLQW9hWWlsRwpjOW1acVhpWVlESTV6R1IxMElpc2FWNXJUY2hDenNQVWRhQzRVbnpTZG01cTdKYTAyb0poQlU1TE1FMD0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo="
|
||||
testConfigTokenNoCluster = `apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
server:
|
||||
@ -89,12 +90,12 @@ func TestRunGenerateToken(t *testing.T) {
|
||||
|
||||
output := buf.String()
|
||||
|
||||
matched, err := regexp.MatchString(TokenExpectedRegex, output)
|
||||
matched, err := regexp.MatchString(tokenExpectedRegex, output)
|
||||
if err != nil {
|
||||
t.Fatalf("Encountered an error while trying to match RunGenerateToken's output: %v", err)
|
||||
}
|
||||
if !matched {
|
||||
t.Errorf("RunGenerateToken's output did not match expected regex; wanted: [%s], got: [%s]", TokenExpectedRegex, output)
|
||||
t.Errorf("RunGenerateToken's output did not match expected regex; wanted: [%s], got: [%s]", tokenExpectedRegex, output)
|
||||
}
|
||||
}
|
||||
|
||||
@ -211,14 +212,14 @@ func TestNewCmdTokenGenerate(t *testing.T) {
|
||||
|
||||
func TestNewCmdToken(t *testing.T) {
|
||||
var buf, bufErr bytes.Buffer
|
||||
testConfigFile := "test-config-file"
|
||||
testConfigTokenFile := "test-config-file"
|
||||
|
||||
tmpDir, err := ioutil.TempDir("", "kubeadm-token-test")
|
||||
if err != nil {
|
||||
t.Errorf("Unable to create temporary directory: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
fullPath := filepath.Join(tmpDir, testConfigFile)
|
||||
fullPath := filepath.Join(tmpDir, testConfigTokenFile)
|
||||
|
||||
f, err := os.Create(fullPath)
|
||||
if err != nil {
|
||||
@ -230,6 +231,7 @@ func TestNewCmdToken(t *testing.T) {
|
||||
name string
|
||||
args []string
|
||||
configToWrite string
|
||||
kubeConfigEnv string
|
||||
expectedError bool
|
||||
}{
|
||||
{
|
||||
@ -239,23 +241,39 @@ func TestNewCmdToken(t *testing.T) {
|
||||
expectedError: false,
|
||||
},
|
||||
{
|
||||
name: "valid: delete",
|
||||
name: "valid: delete from --kubeconfig",
|
||||
args: []string{"delete", "abcdef.1234567890123456", "--dry-run", "--kubeconfig=" + fullPath},
|
||||
configToWrite: TestConfig,
|
||||
configToWrite: testConfigToken,
|
||||
expectedError: false,
|
||||
},
|
||||
{
|
||||
name: "valid: delete from " + clientcmd.RecommendedConfigPathEnvVar,
|
||||
args: []string{"delete", "abcdef.1234567890123456", "--dry-run"},
|
||||
configToWrite: testConfigToken,
|
||||
kubeConfigEnv: fullPath,
|
||||
expectedError: false,
|
||||
},
|
||||
}
|
||||
|
||||
cmd := NewCmdToken(&buf, &bufErr)
|
||||
for _, tc := range testCases {
|
||||
// the command is created for each test so that the kubeConfigFile
|
||||
// variable in NewCmdToken() is reset.
|
||||
cmd := NewCmdToken(&buf, &bufErr)
|
||||
if _, err = f.WriteString(tc.configToWrite); err != nil {
|
||||
t.Errorf("Unable to write test file %q: %v", fullPath, err)
|
||||
}
|
||||
// store the current value of the environment variable.
|
||||
storedEnv := os.Getenv(clientcmd.RecommendedConfigPathEnvVar)
|
||||
if tc.kubeConfigEnv != "" {
|
||||
os.Setenv(clientcmd.RecommendedConfigPathEnvVar, tc.kubeConfigEnv)
|
||||
}
|
||||
cmd.SetArgs(tc.args)
|
||||
err := cmd.Execute()
|
||||
if (err != nil) != tc.expectedError {
|
||||
t.Errorf("Test case %q: NewCmdToken expected error: %v, saw: %v", tc.name, tc.expectedError, (err != nil))
|
||||
}
|
||||
// restore the environment variable.
|
||||
os.Setenv(clientcmd.RecommendedConfigPathEnvVar, storedEnv)
|
||||
}
|
||||
}
|
||||
|
||||
@ -276,14 +294,14 @@ func TestGetSecretString(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetClientset(t *testing.T) {
|
||||
testConfigFile := "test-config-file"
|
||||
testConfigTokenFile := "test-config-file"
|
||||
|
||||
tmpDir, err := ioutil.TempDir("", "kubeadm-token-test")
|
||||
if err != nil {
|
||||
t.Errorf("Unable to create temporary directory: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
fullPath := filepath.Join(tmpDir, testConfigFile)
|
||||
fullPath := filepath.Join(tmpDir, testConfigTokenFile)
|
||||
|
||||
// test dryRun = false on a non-exisiting file
|
||||
if _, err = getClientset(fullPath, false); err == nil {
|
||||
@ -301,7 +319,7 @@ func TestGetClientset(t *testing.T) {
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
if _, err = f.WriteString(TestConfig); err != nil {
|
||||
if _, err = f.WriteString(testConfigToken); err != nil {
|
||||
t.Errorf("Unable to write test file %q: %v", fullPath, err)
|
||||
}
|
||||
|
||||
@ -327,7 +345,7 @@ func TestRunDeleteToken(t *testing.T) {
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
if _, err = f.WriteString(TestConfig); err != nil {
|
||||
if _, err = f.WriteString(testConfigToken); err != nil {
|
||||
t.Errorf("Unable to write test file %q: %v", fullPath, err)
|
||||
}
|
||||
|
||||
@ -369,7 +387,7 @@ func TestRunListTokens(t *testing.T) {
|
||||
defer f.Close()
|
||||
|
||||
// test config without secrets; should fail
|
||||
if _, err = f.WriteString(TestConfig); err != nil {
|
||||
if _, err = f.WriteString(testConfigToken); err != nil {
|
||||
t.Errorf("Unable to write test file %q: %v", fullPath, err)
|
||||
}
|
||||
|
||||
@ -394,9 +412,9 @@ func TestRunListTokens(t *testing.T) {
|
||||
}()
|
||||
|
||||
fmt.Printf("dummy API server listening on localhost:%s\n", portString)
|
||||
testConfigOpenPort := strings.Replace(TestConfig, "server: localhost:8000", "server: localhost:"+portString, -1)
|
||||
testConfigTokenOpenPort := strings.Replace(testConfigToken, "server: localhost:8000", "server: localhost:"+portString, -1)
|
||||
|
||||
if _, err = f.WriteString(testConfigOpenPort); err != nil {
|
||||
if _, err = f.WriteString(testConfigTokenOpenPort); err != nil {
|
||||
t.Errorf("Unable to write test file %q: %v", fullPath, err)
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user