-
Notifications
You must be signed in to change notification settings - Fork 453
Allow using K0S_TOKEN environ as source of Join token #6766
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
s3rj1k
wants to merge
3
commits into
k0sproject:main
Choose a base branch
from
s3rj1k:token-from-env
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+265
−52
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
s3rj1k marked this conversation as resolved.
Show resolved
Hide resolved
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,70 @@ | ||
| // SPDX-FileCopyrightText: 2025 k0s authors | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| package internal | ||
|
|
||
| import ( | ||
| "errors" | ||
| "fmt" | ||
| "os" | ||
| ) | ||
|
|
||
| // EnvVarToken is the environment variable name for the join token | ||
| const EnvVarToken = "K0S_TOKEN" | ||
|
|
||
| // CheckSingleTokenSource verifies that at most one token source is provided. | ||
| // Returns an error if multiple sources are specified. | ||
| func CheckSingleTokenSource(tokenArg, tokenFile string) error { | ||
| tokenSources := 0 | ||
| if tokenArg != "" { | ||
| tokenSources++ | ||
| } | ||
| if tokenFile != "" { | ||
| tokenSources++ | ||
| } | ||
| if os.Getenv(EnvVarToken) != "" { | ||
| tokenSources++ | ||
| } | ||
|
|
||
| if tokenSources > 1 { | ||
| return fmt.Errorf("you can only pass one token source: either as a CLI argument, via '--token-file [path]', or via the %s environment variable", EnvVarToken) | ||
| } | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
| // GetTokenData resolves the join token from multiple possible sources: | ||
| // CLI argument, token file, or K0S_TOKEN environment variable. | ||
| // Returns empty string if no token source is available. | ||
| func GetTokenData(tokenArg, tokenFile string) (string, error) { | ||
| tokenEnvValue := os.Getenv(EnvVarToken) | ||
|
|
||
| if tokenArg != "" { | ||
| return tokenArg, nil | ||
| } | ||
|
|
||
| if tokenEnvValue != "" { | ||
| return tokenEnvValue, nil | ||
| } | ||
|
|
||
| if tokenFile == "" { | ||
| return "", nil | ||
| } | ||
|
|
||
| var problem string | ||
| data, err := os.ReadFile(tokenFile) | ||
| if errors.Is(err, os.ErrNotExist) { | ||
| problem = "not found" | ||
| } else if err != nil { | ||
| return "", fmt.Errorf("failed to read token file: %w", err) | ||
| } else if len(data) == 0 { | ||
| problem = "is empty" | ||
| } | ||
| if problem != "" { | ||
| return "", fmt.Errorf("token file %q %s"+ | ||
| `: obtain a new token via "k0s token create ..." and store it in the file`+ | ||
| ` or reinstall this node via "k0s install --force ..." or "k0sctl apply --force ..."`, | ||
| tokenFile, problem) | ||
| } | ||
| return string(data), nil | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,160 @@ | ||
| // SPDX-FileCopyrightText: 2025 k0s authors | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| package internal | ||
|
|
||
| import ( | ||
| "os" | ||
| "path/filepath" | ||
| "testing" | ||
|
|
||
| "github.com/stretchr/testify/assert" | ||
| "github.com/stretchr/testify/require" | ||
| ) | ||
|
|
||
| func TestCheckSingleTokenSource(t *testing.T) { | ||
| testToken := "test-token-data" | ||
|
|
||
| t.Run("returns nil when no token sources provided", func(t *testing.T) { | ||
| t.Setenv(EnvVarToken, "") | ||
|
|
||
| err := CheckSingleTokenSource("", "") | ||
| require.NoError(t, err) | ||
| }) | ||
|
|
||
| t.Run("returns nil when only arg provided", func(t *testing.T) { | ||
| t.Setenv(EnvVarToken, "") | ||
|
|
||
| err := CheckSingleTokenSource(testToken, "") | ||
| require.NoError(t, err) | ||
| }) | ||
|
|
||
| t.Run("returns nil when only file provided", func(t *testing.T) { | ||
| t.Setenv(EnvVarToken, "") | ||
|
|
||
| err := CheckSingleTokenSource("", "/path/to/token") | ||
| require.NoError(t, err) | ||
| }) | ||
|
|
||
| t.Run("returns nil when only env provided", func(t *testing.T) { | ||
| t.Setenv(EnvVarToken, testToken) | ||
|
|
||
| err := CheckSingleTokenSource("", "") | ||
| require.NoError(t, err) | ||
| }) | ||
|
|
||
| t.Run("returns error when multiple token sources provided - env and arg", func(t *testing.T) { | ||
| t.Setenv(EnvVarToken, testToken) | ||
|
|
||
| err := CheckSingleTokenSource(testToken, "") | ||
| require.Error(t, err) | ||
| assert.Contains(t, err.Error(), "you can only pass one token source") | ||
| assert.Contains(t, err.Error(), EnvVarToken) | ||
| }) | ||
|
|
||
| t.Run("returns error when multiple token sources provided - env and file", func(t *testing.T) { | ||
| t.Setenv(EnvVarToken, testToken) | ||
|
|
||
| err := CheckSingleTokenSource("", "/path/to/token") | ||
| require.Error(t, err) | ||
| assert.Contains(t, err.Error(), "you can only pass one token source") | ||
| }) | ||
|
|
||
| t.Run("returns error when multiple token sources provided - arg and file", func(t *testing.T) { | ||
| t.Setenv(EnvVarToken, "") | ||
|
|
||
| err := CheckSingleTokenSource(testToken, "/path/to/token") | ||
| require.Error(t, err) | ||
| assert.Contains(t, err.Error(), "you can only pass one token source") | ||
| }) | ||
|
|
||
| t.Run("returns error when all three token sources provided", func(t *testing.T) { | ||
| t.Setenv(EnvVarToken, testToken) | ||
|
|
||
| err := CheckSingleTokenSource(testToken, "/path/to/token") | ||
| require.Error(t, err) | ||
| assert.Contains(t, err.Error(), "you can only pass one token source") | ||
| }) | ||
| } | ||
|
|
||
| func TestGetTokenData_EnvVar(t *testing.T) { | ||
| testToken := "test-token-data" | ||
|
|
||
| t.Run("reads token from K0S_TOKEN env var", func(t *testing.T) { | ||
| t.Setenv(EnvVarToken, testToken) | ||
|
|
||
| token, err := GetTokenData("", "") | ||
| require.NoError(t, err) | ||
| assert.Equal(t, testToken, token) | ||
| }) | ||
|
|
||
| t.Run("empty K0S_TOKEN returns empty string", func(t *testing.T) { | ||
| t.Setenv(EnvVarToken, "") | ||
|
|
||
| token, err := GetTokenData("", "") | ||
| require.NoError(t, err) | ||
| assert.Empty(t, token) | ||
| }) | ||
| } | ||
|
|
||
| func TestGetTokenData_TokenArg(t *testing.T) { | ||
| testToken := "test-token-data" | ||
|
|
||
| t.Run("reads token from argument", func(t *testing.T) { | ||
| t.Setenv(EnvVarToken, "") | ||
|
|
||
| token, err := GetTokenData(testToken, "") | ||
| require.NoError(t, err) | ||
| assert.Equal(t, testToken, token) | ||
| }) | ||
| } | ||
|
|
||
| func TestGetTokenData_TokenFile(t *testing.T) { | ||
| testToken := "test-token-from-file" | ||
|
|
||
| t.Run("reads token from file", func(t *testing.T) { | ||
| t.Setenv(EnvVarToken, "") | ||
|
|
||
| tmpDir := t.TempDir() | ||
| tokenFile := filepath.Join(tmpDir, "token") | ||
| require.NoError(t, os.WriteFile(tokenFile, []byte(testToken), 0600)) | ||
|
|
||
| token, err := GetTokenData("", tokenFile) | ||
| require.NoError(t, err) | ||
| assert.Equal(t, testToken, token) | ||
| }) | ||
|
|
||
| t.Run("returns error for non-existent file", func(t *testing.T) { | ||
| t.Setenv(EnvVarToken, "") | ||
|
|
||
| _, err := GetTokenData("", "/non/existent/path") | ||
| require.Error(t, err) | ||
| assert.Contains(t, err.Error(), "token file") | ||
| assert.Contains(t, err.Error(), "not found") | ||
| assert.Contains(t, err.Error(), "k0s token create") | ||
| }) | ||
|
|
||
| t.Run("returns error for empty file", func(t *testing.T) { | ||
| t.Setenv(EnvVarToken, "") | ||
|
|
||
| tmpDir := t.TempDir() | ||
| tokenFile := filepath.Join(tmpDir, "empty-token") | ||
| require.NoError(t, os.WriteFile(tokenFile, []byte{}, 0600)) | ||
|
|
||
| _, err := GetTokenData("", tokenFile) | ||
| require.Error(t, err) | ||
| assert.Contains(t, err.Error(), "token file") | ||
| assert.Contains(t, err.Error(), "is empty") | ||
| assert.Contains(t, err.Error(), "k0s token create") | ||
| }) | ||
| } | ||
|
|
||
| func TestGetTokenData_NoToken(t *testing.T) { | ||
| t.Run("returns empty string when no token provided", func(t *testing.T) { | ||
| t.Setenv(EnvVarToken, "") | ||
|
|
||
| token, err := GetTokenData("", "") | ||
| require.NoError(t, err) | ||
| assert.Empty(t, token) | ||
| }) | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd prefer to leave this check in place (or refactor it out and reuse it here via a function, whichever makes more sense.) We should verify the command line's correctness before attempting to do anything.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hopefully handled by
internal.CheckSingleTokenSource