mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-08 03:33:56 +00:00
kubeadm: Add the 'kubeadm phase bootstrap-token' command
This commit is contained in:
parent
04748160a6
commit
5f4e19beb8
139
cmd/kubeadm/app/cmd/phases/bootstraptoken.go
Normal file
139
cmd/kubeadm/app/cmd/phases/bootstraptoken.go
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
/*
|
||||||
|
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 phases
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
clientset "k8s.io/client-go/kubernetes"
|
||||||
|
"k8s.io/kubernetes/cmd/kubeadm/app/phases/bootstraptoken/clusterinfo"
|
||||||
|
"k8s.io/kubernetes/cmd/kubeadm/app/phases/bootstraptoken/node"
|
||||||
|
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
|
||||||
|
kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig"
|
||||||
|
versionutil "k8s.io/kubernetes/pkg/util/version"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewCmdBootstrapToken returns the Cobra command for running the mark-master phase
|
||||||
|
func NewCmdBootstrapToken() *cobra.Command {
|
||||||
|
var kubeConfigFile string
|
||||||
|
cmd := &cobra.Command{
|
||||||
|
Use: "bootstrap-token",
|
||||||
|
Short: "Manage kubeadm-specific Bootstrap Token functions.",
|
||||||
|
Aliases: []string{"bootstraptoken"},
|
||||||
|
RunE: subCmdRunE("bootstrap-token"),
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.PersistentFlags().StringVar(&kubeConfigFile, "kubeconfig", "/etc/kubernetes/admin.conf", "The KubeConfig file to use for talking to the cluster")
|
||||||
|
|
||||||
|
// Add subcommands
|
||||||
|
cmd.AddCommand(NewSubCmdClusterInfo(&kubeConfigFile))
|
||||||
|
cmd.AddCommand(NewSubCmdNodeBootstrapToken(&kubeConfigFile))
|
||||||
|
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSubCmdClusterInfo returns the Cobra command for running the cluster-info sub-phase
|
||||||
|
func NewSubCmdClusterInfo(kubeConfigFile *string) *cobra.Command {
|
||||||
|
cmd := &cobra.Command{
|
||||||
|
Use: "cluster-info <clusterinfo-file>",
|
||||||
|
Short: "Uploads and exposes the cluster-info ConfigMap publicly from the given cluster-info file",
|
||||||
|
Aliases: []string{"clusterinfo"},
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
err := validateExactArgNumber(args, []string{"clusterinfo-file"})
|
||||||
|
kubeadmutil.CheckErr(err)
|
||||||
|
|
||||||
|
client, err := kubeconfigutil.ClientSetFromFile(*kubeConfigFile)
|
||||||
|
kubeadmutil.CheckErr(err)
|
||||||
|
|
||||||
|
// Here it's safe to get args[0], since we've validated that the argument exists above in validateExactArgNumber
|
||||||
|
clusterInfoFile := args[0]
|
||||||
|
// Create the cluster-info ConfigMap or update if it already exists
|
||||||
|
err = clusterinfo.CreateBootstrapConfigMapIfNotExists(client, clusterInfoFile)
|
||||||
|
kubeadmutil.CheckErr(err)
|
||||||
|
|
||||||
|
// Create the RBAC rules that expose the cluster-info ConfigMap properly
|
||||||
|
err = clusterinfo.CreateClusterInfoRBACRules(client)
|
||||||
|
kubeadmutil.CheckErr(err)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSubCmdNodeBootstrapToken returns the Cobra command for running the node sub-phase
|
||||||
|
func NewSubCmdNodeBootstrapToken(kubeConfigFile *string) *cobra.Command {
|
||||||
|
cmd := &cobra.Command{
|
||||||
|
Use: "node",
|
||||||
|
Short: "Manages Node Bootstrap Tokens",
|
||||||
|
Aliases: []string{"clusterinfo"},
|
||||||
|
RunE: subCmdRunE("node"),
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.AddCommand(NewSubCmdNodeBootstrapTokenPostCSRs(kubeConfigFile))
|
||||||
|
cmd.AddCommand(NewSubCmdNodeBootstrapTokenAutoApprove(kubeConfigFile))
|
||||||
|
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSubCmdNodeBootstrapTokenPostCSRs returns the Cobra command for running the allow-post-csrs sub-phase
|
||||||
|
func NewSubCmdNodeBootstrapTokenPostCSRs(kubeConfigFile *string) *cobra.Command {
|
||||||
|
cmd := &cobra.Command{
|
||||||
|
Use: "allow-post-csrs",
|
||||||
|
Short: "Configure RBAC to allow Node Bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
client, err := kubeconfigutil.ClientSetFromFile(*kubeConfigFile)
|
||||||
|
kubeadmutil.CheckErr(err)
|
||||||
|
|
||||||
|
err = node.AllowBootstrapTokensToPostCSRs(client)
|
||||||
|
kubeadmutil.CheckErr(err)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSubCmdNodeBootstrapToken returns the Cobra command for running the allow-auto-approve sub-phase
|
||||||
|
func NewSubCmdNodeBootstrapTokenAutoApprove(kubeConfigFile *string) *cobra.Command {
|
||||||
|
cmd := &cobra.Command{
|
||||||
|
Use: "allow-auto-approve",
|
||||||
|
Short: "Configure RBAC rules to allow the csrapprover controller automatically approve CSRs from a Node Bootstrap Token",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
client, err := kubeconfigutil.ClientSetFromFile(*kubeConfigFile)
|
||||||
|
kubeadmutil.CheckErr(err)
|
||||||
|
|
||||||
|
clusterVersion, err := getClusterVersion(client)
|
||||||
|
kubeadmutil.CheckErr(err)
|
||||||
|
|
||||||
|
err = node.AutoApproveNodeBootstrapTokens(client, clusterVersion)
|
||||||
|
kubeadmutil.CheckErr(err)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
// getClusterVersion fetches the API server version and parses it
|
||||||
|
func getClusterVersion(client clientset.Interface) (*versionutil.Version, error) {
|
||||||
|
clusterVersionInfo, err := client.Discovery().ServerVersion()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to check server version: %v", err)
|
||||||
|
}
|
||||||
|
clusterVersion, err := versionutil.ParseSemantic(clusterVersionInfo.String())
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to parse server version: %v", err)
|
||||||
|
}
|
||||||
|
return clusterVersion, nil
|
||||||
|
}
|
@ -22,6 +22,7 @@ import (
|
|||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
markmasterphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/markmaster"
|
markmasterphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/markmaster"
|
||||||
|
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
|
||||||
kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig"
|
kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -33,16 +34,11 @@ func NewCmdMarkMaster() *cobra.Command {
|
|||||||
Short: "Create KubeConfig files from given credentials.",
|
Short: "Create KubeConfig files from given credentials.",
|
||||||
Aliases: []string{"markmaster"},
|
Aliases: []string{"markmaster"},
|
||||||
RunE: func(_ *cobra.Command, args []string) error {
|
RunE: func(_ *cobra.Command, args []string) error {
|
||||||
if len(args) < 1 || len(args[0]) == 0 {
|
err := validateExactArgNumber(args, []string{"node-name"})
|
||||||
return fmt.Errorf("missing required argument node-name")
|
kubeadmutil.CheckErr(err)
|
||||||
}
|
|
||||||
if len(args) > 1 {
|
|
||||||
return fmt.Errorf("too many arguments, only one argument supported: node-name")
|
|
||||||
}
|
|
||||||
client, err := kubeconfigutil.ClientSetFromFile(kubeConfigFile)
|
client, err := kubeconfigutil.ClientSetFromFile(kubeConfigFile)
|
||||||
if err != nil {
|
kubeadmutil.CheckErr(err)
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
nodeName := args[0]
|
nodeName := args[0]
|
||||||
fmt.Printf("[markmaster] Will mark node %s as master by adding a label and a taint\n", nodeName)
|
fmt.Printf("[markmaster] Will mark node %s as master by adding a label and a taint\n", nodeName)
|
||||||
|
@ -23,6 +23,7 @@ import (
|
|||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// NewCmdPhase returns the cobra command for the "kubeadm phase" command (currently alpha-gated)
|
||||||
func NewCmdPhase(out io.Writer) *cobra.Command {
|
func NewCmdPhase(out io.Writer) *cobra.Command {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "phase",
|
Use: "phase",
|
||||||
@ -36,6 +37,7 @@ func NewCmdPhase(out io.Writer) *cobra.Command {
|
|||||||
cmd.AddCommand(NewCmdSelfhosting())
|
cmd.AddCommand(NewCmdSelfhosting())
|
||||||
cmd.AddCommand(NewCmdMarkMaster())
|
cmd.AddCommand(NewCmdMarkMaster())
|
||||||
cmd.AddCommand(NewCmdUploadConfig())
|
cmd.AddCommand(NewCmdUploadConfig())
|
||||||
|
cmd.AddCommand(NewCmdBootstrapToken())
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
@ -54,3 +56,22 @@ func subCmdRunE(name string) func(*cobra.Command, []string) error {
|
|||||||
return fmt.Errorf("invalid subcommand: %q", args[0])
|
return fmt.Errorf("invalid subcommand: %q", args[0])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// validateExactArgNumber validates that the required top-level arguments are specified
|
||||||
|
func validateExactArgNumber(args []string, supportedArgs []string) error {
|
||||||
|
validArgs := 0
|
||||||
|
// Disregard possible "" arguments; they are invalid
|
||||||
|
for _, arg := range args {
|
||||||
|
if len(arg) > 0 {
|
||||||
|
validArgs++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if validArgs < len(supportedArgs) {
|
||||||
|
return fmt.Errorf("missing one or more required arguments. Required arguments: %v", supportedArgs)
|
||||||
|
}
|
||||||
|
if validArgs > len(supportedArgs) {
|
||||||
|
return fmt.Errorf("too many arguments, only %d argument(s) supported: %v", validArgs, supportedArgs)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
64
cmd/kubeadm/app/cmd/phases/phase_test.go
Normal file
64
cmd/kubeadm/app/cmd/phases/phase_test.go
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
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 phases
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestValidateExactArgNumber(t *testing.T) {
|
||||||
|
var tests = []struct {
|
||||||
|
args, supportedArgs []string
|
||||||
|
expectedErr bool
|
||||||
|
}{
|
||||||
|
{ // one arg given and one arg expected
|
||||||
|
args: []string{"my-node-1234"},
|
||||||
|
supportedArgs: []string{"node-name"},
|
||||||
|
expectedErr: false,
|
||||||
|
},
|
||||||
|
{ // two args given and two args expected
|
||||||
|
args: []string{"my-node-1234", "foo"},
|
||||||
|
supportedArgs: []string{"node-name", "second-toplevel-arg"},
|
||||||
|
expectedErr: false,
|
||||||
|
},
|
||||||
|
{ // too few supplied args
|
||||||
|
args: []string{},
|
||||||
|
supportedArgs: []string{"node-name"},
|
||||||
|
expectedErr: true,
|
||||||
|
},
|
||||||
|
{ // too few non-empty args
|
||||||
|
args: []string{""},
|
||||||
|
supportedArgs: []string{"node-name"},
|
||||||
|
expectedErr: true,
|
||||||
|
},
|
||||||
|
{ // too many args
|
||||||
|
args: []string{"my-node-1234", "foo"},
|
||||||
|
supportedArgs: []string{"node-name"},
|
||||||
|
expectedErr: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, rt := range tests {
|
||||||
|
actual := validateExactArgNumber(rt.args, rt.supportedArgs)
|
||||||
|
if (actual != nil) != rt.expectedErr {
|
||||||
|
t.Errorf(
|
||||||
|
"failed validateExactArgNumber:\n\texpected error: %t\n\t actual error: %t",
|
||||||
|
rt.expectedErr,
|
||||||
|
(actual != nil),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user