mirror of https://github.com/k3s-io/k3s
Merge pull request #35144 from pipejakob/generate-token
Automatic merge from submit-queue New command: "kubeadm token generate" As part of #33930, this PR adds a new top-level command to kubeadm to just generate a token for use with the init/join commands. Otherwise, users are left to either figure out how to generate a token on their own, or let `kubeadm init` generate a token, capture and parse the output, and then use that token for `kubeadm join`. At this point, I was hoping for feedback on the CLI experience, and then I can add tests. I spoke with @mikedanese and he didn't like the original propose of `kubeadm util generate-token`, so here are the runners up: ``` $ kubeadm generate-token # <--- current implementation $ kubeadm generate token # in case kubeadm might generate other things in the future? $ kubeadm init --generate-token # possibly as a subcommand of an existing one ``` Currently, the output is simply the token on one line without any padding/formatting: ``` $ kubeadm generate-token 1087fd.722b60cdd39b1a5f ``` CC: @kubernetes/sig-cluster-lifecycle **Release note**: <!-- Steps to write your release note: 1. Use the release-note-* labels to set the release note state (if you have access) 2. Enter your extended release note in the below block; leaving it blank means using the PR title as the release note. If no release note is required, just write `NONE`. --> ``` release-note New kubeadm command: generate-token ```pull/6/head
commit
afa99c68b8
1
Makefile
1
Makefile
|
@ -193,6 +193,7 @@ test-e2e-node: ginkgo generated_files
|
|||
# make test-cmd
|
||||
.PHONY: test-cmd
|
||||
test-cmd: generated_files
|
||||
hack/make-rules/test-kubeadm-cmd.sh
|
||||
hack/make-rules/test-cmd.sh
|
||||
|
||||
# Remove all build artifacts.
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Copyright 2016 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.
|
||||
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
set -o pipefail
|
||||
|
||||
KUBE_ROOT=${KUBE_ROOT:-$(dirname "${BASH_SOURCE}")/..}
|
||||
source "${KUBE_ROOT}/cluster/kube-util.sh"
|
||||
|
||||
# Get the absolute path of the directory component of a file, i.e. the
|
||||
# absolute path of the dirname of $1.
|
||||
get_absolute_dirname() {
|
||||
echo "$(cd "$(dirname "$1")" && pwd)"
|
||||
}
|
||||
|
||||
# Detect the OS name/arch so that we can find our binary
|
||||
case "$(uname -s)" in
|
||||
Darwin)
|
||||
host_os=darwin
|
||||
;;
|
||||
Linux)
|
||||
host_os=linux
|
||||
;;
|
||||
*)
|
||||
echo "Unsupported host OS. Must be Linux or Mac OS X." >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
case "$(uname -m)" in
|
||||
x86_64*)
|
||||
host_arch=amd64
|
||||
;;
|
||||
i?86_64*)
|
||||
host_arch=amd64
|
||||
;;
|
||||
amd64*)
|
||||
host_arch=amd64
|
||||
;;
|
||||
arm*)
|
||||
host_arch=arm
|
||||
;;
|
||||
i?86*)
|
||||
host_arch=386
|
||||
;;
|
||||
s390x*)
|
||||
host_arch=s390x
|
||||
;;
|
||||
ppc64le*)
|
||||
host_arch=ppc64le
|
||||
;;
|
||||
*)
|
||||
echo "Unsupported host arch. Must be x86_64, 386, arm, s390x or ppc64le." >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# If KUBEADM_PATH isn't set, gather up the list of likely places and use ls
|
||||
# to find the latest one.
|
||||
if [[ -z "${KUBEADM_PATH:-}" ]]; then
|
||||
locations=(
|
||||
"${KUBE_ROOT}/_output/bin/kubeadm"
|
||||
"${KUBE_ROOT}/_output/dockerized/bin/${host_os}/${host_arch}/kubeadm"
|
||||
"${KUBE_ROOT}/_output/local/bin/${host_os}/${host_arch}/kubeadm"
|
||||
"${KUBE_ROOT}/platforms/${host_os}/${host_arch}/kubeadm"
|
||||
)
|
||||
kubeadm=$( (ls -t "${locations[@]}" 2>/dev/null || true) | head -1 )
|
||||
|
||||
if [[ ! -x "$kubeadm" ]]; then
|
||||
{
|
||||
echo "It looks as if you don't have a compiled kubeadm binary"
|
||||
echo
|
||||
echo "If you are running from a clone of the git repo, please run"
|
||||
echo "'./build/run.sh make cross'. Note that this requires having"
|
||||
echo "Docker installed."
|
||||
echo
|
||||
echo "If you are running from a binary release tarball, something is wrong. "
|
||||
echo "Look at http://kubernetes.io/ for information on how to contact the "
|
||||
echo "development team for help."
|
||||
} >&2
|
||||
exit 1
|
||||
fi
|
||||
elif [[ ! -x "${KUBEADM_PATH}" ]]; then
|
||||
{
|
||||
echo "KUBEADM_PATH environment variable set to '${KUBEADM_PATH}', but "
|
||||
echo "this doesn't seem to be a valid executable."
|
||||
} >&2
|
||||
exit 1
|
||||
fi
|
||||
kubeadm="${KUBEADM_PATH:-${kubeadm}}"
|
||||
|
||||
"${kubeadm}" "${@+$@}"
|
|
@ -17,6 +17,7 @@ go_library(
|
|||
"init.go",
|
||||
"join.go",
|
||||
"reset.go",
|
||||
"token.go",
|
||||
"version.go",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
|
@ -43,7 +44,10 @@ go_library(
|
|||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["reset_test.go"],
|
||||
srcs = [
|
||||
"reset_test.go",
|
||||
"token_test.go",
|
||||
],
|
||||
library = "go_default_library",
|
||||
tags = ["automanaged"],
|
||||
deps = ["//cmd/kubeadm/app/preflight:go_default_library"],
|
||||
|
|
|
@ -81,6 +81,7 @@ func NewKubeadmCommand(f cmdutil.Factory, in io.Reader, out, err io.Writer) *cob
|
|||
cmds.AddCommand(NewCmdInit(out))
|
||||
cmds.AddCommand(NewCmdJoin(out))
|
||||
cmds.AddCommand(NewCmdReset(out))
|
||||
cmds.AddCommand(NewCmdToken(out))
|
||||
cmds.AddCommand(NewCmdVersion(out))
|
||||
|
||||
return cmds
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
Copyright 2016 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 cmd
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/renstrom/dedent"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/util"
|
||||
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
|
||||
)
|
||||
|
||||
func NewCmdToken(out io.Writer) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "token",
|
||||
Short: "Manage tokens used by init/join",
|
||||
|
||||
// Without this callback, if a user runs just the "token"
|
||||
// command without a subcommand, or with an invalid subcommand,
|
||||
// cobra will print usage information, but still exit cleanly.
|
||||
// We want to return an error code in these cases so that the
|
||||
// user knows that their command was invalid.
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if len(args) < 1 {
|
||||
return errors.New("missing subcommand; 'token' is not meant to be run on its own")
|
||||
} else {
|
||||
return fmt.Errorf("invalid subcommand: %s", args[0])
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
cmd.AddCommand(NewCmdTokenGenerate(out))
|
||||
return cmd
|
||||
}
|
||||
|
||||
func NewCmdTokenGenerate(out io.Writer) *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "generate",
|
||||
Short: "Generate and print a token suitable for use with init/join",
|
||||
Long: dedent.Dedent(`
|
||||
This command will print out a randomly-generated token that you can use with
|
||||
the "init" and "join" commands.
|
||||
|
||||
You don't have to use this command in order to generate a token, you can do so
|
||||
yourself as long as it's in the format "<6 characters>.<16 characters>". This
|
||||
command is provided for convenience to generate tokens in that format.
|
||||
|
||||
You can also use "kubeadm init" without specifying a token, and it will
|
||||
generate and print one for you.
|
||||
`),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := RunGenerateToken(out)
|
||||
kubeadmutil.CheckErr(err)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func RunGenerateToken(out io.Writer) error {
|
||||
s := &kubeadmapi.Secrets{}
|
||||
err := util.GenerateToken(s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Fprintln(out, s.GivenToken)
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
Copyright 2016 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 cmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"regexp"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const (
|
||||
TokenExpectedRegex = "^\\S{6}\\.\\S{16}\n$"
|
||||
)
|
||||
|
||||
func TestRunGenerateToken(t *testing.T) {
|
||||
var buf bytes.Buffer
|
||||
|
||||
err := RunGenerateToken(&buf)
|
||||
if err != nil {
|
||||
t.Errorf("RunGenerateToken returned an error: %v", err)
|
||||
}
|
||||
|
||||
output := buf.String()
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_binary",
|
||||
"go_library",
|
||||
"go_test",
|
||||
"cgo_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["util.go"],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["token_test.go"],
|
||||
library = "go_default_library",
|
||||
tags = ["automanaged"],
|
||||
deps = [],
|
||||
)
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
Copyright 2016 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 kubeadm
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"regexp"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const (
|
||||
TokenExpectedRegex = "^\\S{6}\\.\\S{16}\n$"
|
||||
)
|
||||
|
||||
var kubeadmPath string
|
||||
|
||||
func init() {
|
||||
flag.StringVar(&kubeadmPath, "kubeadm-path", "cluster/kubeadm.sh", "Location of kubeadm")
|
||||
}
|
||||
|
||||
func TestCmdTokenGenerate(t *testing.T) {
|
||||
stdout, _, err := RunCmd(kubeadmPath, "token", "generate")
|
||||
if err != nil {
|
||||
t.Errorf("'kubeadm token generate' exited uncleanly: %v", err)
|
||||
}
|
||||
|
||||
matched, err := regexp.MatchString(TokenExpectedRegex, stdout)
|
||||
if err != nil {
|
||||
t.Fatalf("encountered an error while trying to match 'kubeadm token generate' stdout: %v", err)
|
||||
}
|
||||
if !matched {
|
||||
t.Errorf("'kubeadm token generate' stdout did not match expected regex; wanted: [%s], got: [%s]", TokenExpectedRegex, stdout)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCmdTokenGenerateTypoError(t *testing.T) {
|
||||
/*
|
||||
Since we expect users to do things like this:
|
||||
|
||||
$ TOKEN=$(kubeadm token generate)
|
||||
|
||||
we want to make sure that if they have a typo in their command, we exit
|
||||
with a non-zero status code after showing the command's usage, so that
|
||||
the usage itself isn't captured as a token without the user noticing.
|
||||
*/
|
||||
|
||||
_, _, err := RunCmd(kubeadmPath, "token", "genorate") // subtle typo
|
||||
if err == nil {
|
||||
t.Error("'kubeadm token genorate' (a deliberate typo) exited without an error when we expected non-zero exit status")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
Copyright 2016 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 kubeadm
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
// Forked from test/e2e/framework because the e2e framework is quite bloated
|
||||
// for our purposes here, and modified to remove undesired logging.
|
||||
func RunCmd(command string, args ...string) (string, string, error) {
|
||||
var bout, berr bytes.Buffer
|
||||
cmd := exec.Command(command, args...)
|
||||
cmd.Stdout = io.MultiWriter(os.Stdout, &bout)
|
||||
cmd.Stderr = io.MultiWriter(os.Stderr, &berr)
|
||||
err := cmd.Run()
|
||||
stdout, stderr := bout.String(), berr.String()
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("error running %s %v; got error %v, stdout %q, stderr %q",
|
||||
command, args, err, stdout, stderr)
|
||||
}
|
||||
return stdout, stderr, nil
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Copyright 2016 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.
|
||||
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
set -o pipefail
|
||||
|
||||
KUBE_ROOT=$(dirname "${BASH_SOURCE}")/../..
|
||||
source "${KUBE_ROOT}/hack/lib/init.sh"
|
||||
|
||||
KUBEADM_PATH="${KUBEADM_PATH:=$(kube::realpath "${KUBE_ROOT}")/cluster/kubeadm.sh}"
|
||||
|
||||
# If testing a different version of kubeadm than the current build, you can
|
||||
# comment this out to save yourself from needlessly building here.
|
||||
make -C "${KUBE_ROOT}" WHAT=cmd/kubeadm
|
||||
|
||||
make -C "${KUBE_ROOT}" test \
|
||||
WHAT=cmd/kubeadm/test \
|
||||
KUBE_TEST_ARGS="--kubeadm-path '${KUBEADM_PATH}'"
|
|
@ -35,6 +35,7 @@ kube::test::find_dirs() {
|
|||
-path './_artifacts/*' \
|
||||
-o -path './_output/*' \
|
||||
-o -path './_gopath/*' \
|
||||
-o -path './cmd/kubeadm/test/*' \
|
||||
-o -path './contrib/podex/*' \
|
||||
-o -path './output/*' \
|
||||
-o -path './release/*' \
|
||||
|
|
|
@ -302,6 +302,7 @@ kube-master
|
|||
kube-master
|
||||
kube-master-url
|
||||
kube-reserved
|
||||
kubeadm-path
|
||||
kubecfg-file
|
||||
kubectl-path
|
||||
kubelet-address
|
||||
|
|
|
@ -468,6 +468,7 @@ k8s.io/kubernetes/cmd/kubeadm/app/cmd,caesarxuchao,1
|
|||
k8s.io/kubernetes/cmd/kubeadm/app/images,davidopp,1
|
||||
k8s.io/kubernetes/cmd/kubeadm/app/preflight,apprenda,0
|
||||
k8s.io/kubernetes/cmd/kubeadm/app/util,krousey,1
|
||||
k8s.io/kubernetes/cmd/kubeadm/test,pipejakob,0
|
||||
k8s.io/kubernetes/cmd/kubelet/app,hurf,1
|
||||
k8s.io/kubernetes/cmd/libs/go2idl/client-gen/types,caesarxuchao,0
|
||||
k8s.io/kubernetes/cmd/libs/go2idl/go-to-protobuf/protobuf,smarterclayton,0
|
||||
|
|
|
Loading…
Reference in New Issue