kubeadm graduate kubeconfig phase

This commit is contained in:
fabriziopandini 2018-10-30 16:35:29 +01:00
parent 03a145de8a
commit 3cadb3ca1d
9 changed files with 256 additions and 529 deletions

View File

@ -50,7 +50,6 @@ import (
certsphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/certs" certsphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/certs"
controlplanephase "k8s.io/kubernetes/cmd/kubeadm/app/phases/controlplane" controlplanephase "k8s.io/kubernetes/cmd/kubeadm/app/phases/controlplane"
etcdphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/etcd" etcdphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/etcd"
kubeconfigphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig"
kubeletphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/kubelet" kubeletphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/kubelet"
markmasterphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/markmaster" markmasterphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/markmaster"
patchnodephase "k8s.io/kubernetes/cmd/kubeadm/app/phases/patchnode" patchnodephase "k8s.io/kubernetes/cmd/kubeadm/app/phases/patchnode"
@ -130,6 +129,7 @@ type initData struct {
ignorePreflightErrors sets.String ignorePreflightErrors sets.String
certificatesDir string certificatesDir string
dryRunDir string dryRunDir string
externalCA bool
client clientset.Interface client clientset.Interface
} }
@ -146,7 +146,7 @@ func NewCmdInit(out io.Writer) *cobra.Command {
kubeadmutil.CheckErr(err) kubeadmutil.CheckErr(err)
data := c.(initData) data := c.(initData)
fmt.Printf("[init] using Kubernetes version: %s\n", data.cfg.KubernetesVersion) fmt.Printf("[init] Using Kubernetes version: %s\n", data.cfg.KubernetesVersion)
err = initRunner.Run() err = initRunner.Run()
kubeadmutil.CheckErr(err) kubeadmutil.CheckErr(err)
@ -166,8 +166,9 @@ func NewCmdInit(out io.Writer) *cobra.Command {
// initialize the workflow runner with the list of phases // initialize the workflow runner with the list of phases
initRunner.AppendPhase(phases.NewPreflightMasterPhase()) initRunner.AppendPhase(phases.NewPreflightMasterPhase())
initRunner.AppendPhase(phases.NewCertsPhase())
initRunner.AppendPhase(phases.NewKubeletStartPhase()) initRunner.AppendPhase(phases.NewKubeletStartPhase())
initRunner.AppendPhase(phases.NewCertsPhase())
initRunner.AppendPhase(phases.NewKubeConfigPhase())
// TODO: add other phases to the runner. // TODO: add other phases to the runner.
// sets the data builder function, that will be used by the runner // sets the data builder function, that will be used by the runner
@ -313,6 +314,9 @@ func newInitData(cmd *cobra.Command, options *initOptions) (initData, error) {
} }
} }
// Checks if an external CA is provided by the user.
externalCA, _ := certsphase.UsingExternalCA(cfg)
return initData{ return initData{
cfg: cfg, cfg: cfg,
certificatesDir: cfg.CertificatesDir, certificatesDir: cfg.CertificatesDir,
@ -320,6 +324,7 @@ func newInitData(cmd *cobra.Command, options *initOptions) (initData, error) {
dryRun: options.dryRun, dryRun: options.dryRun,
dryRunDir: dryRunDir, dryRunDir: dryRunDir,
ignorePreflightErrors: ignorePreflightErrorsSet, ignorePreflightErrors: ignorePreflightErrorsSet,
externalCA: externalCA,
}, nil }, nil
} }
@ -380,6 +385,11 @@ func (d initData) KubeletDir() string {
return kubeadmconstants.KubeletRunDirectory return kubeadmconstants.KubeletRunDirectory
} }
// ExternalCA returns true if an external CA is provided by the user.
func (d initData) ExternalCA() bool {
return d.externalCA
}
// Client returns a Kubernetes client to be used by kubeadm. // Client returns a Kubernetes client to be used by kubeadm.
// This function is implemented as a singleton, thus avoiding to recreate the client when it is used by different phases. // This function is implemented as a singleton, thus avoiding to recreate the client when it is used by different phases.
// Important. This function must be called after the admin.conf kubeconfig file is created. // Important. This function must be called after the admin.conf kubeconfig file is created.
@ -426,18 +436,6 @@ func runInit(i *initData, out io.Writer) error {
adminKubeConfigPath := filepath.Join(kubeConfigDir, kubeadmconstants.AdminKubeConfigFileName) adminKubeConfigPath := filepath.Join(kubeConfigDir, kubeadmconstants.AdminKubeConfigFileName)
if res, _ := certsphase.UsingExternalCA(i.cfg); !res {
// PHASE 2: Generate kubeconfig files for the admin and the kubelet
glog.V(2).Infof("[init] generating kubeconfig files")
if err := kubeconfigphase.CreateInitKubeConfigFiles(kubeConfigDir, i.cfg); err != nil {
return err
}
} else {
fmt.Println("[externalca] the file 'ca.key' was not found, yet all other certificates are present. Using external CA mode - certificates or kubeconfig will not be generated")
}
if features.Enabled(i.cfg.FeatureGates, features.Auditing) { if features.Enabled(i.cfg.FeatureGates, features.Auditing) {
// Setup the AuditPolicy (either it was passed in and exists or it wasn't passed in and generate a default policy) // Setup the AuditPolicy (either it was passed in and exists or it wasn't passed in and generate a default policy)
if i.cfg.AuditPolicyConfiguration.Path != "" { if i.cfg.AuditPolicyConfiguration.Path != "" {

View File

@ -22,7 +22,6 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
kubeadmscheme "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/scheme" kubeadmscheme "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/scheme"
kubeadmapiv1beta1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta1" kubeadmapiv1beta1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta1"
@ -36,23 +35,6 @@ import (
) )
var ( var (
allCertsLongDesc = normalizer.LongDesc(`
Generates a self-signed CA to provision identities for each component in the cluster (including nodes)
and client certificates to be used by various components.
If a given certificate and private key pair both exist, kubeadm skips the generation step and
existing files will be used.
` + cmdutil.AlphaDisclaimer)
allCertsExample = normalizer.Examples(`
# Creates all PKI assets necessary to establish the control plane,
# functionally equivalent to what generated by kubeadm init.
kubeadm alpha phase certs all
# Creates all PKI assets using options read from a configuration file.
kubeadm alpha phase certs all --config masterconfiguration.yaml
`)
saKeyLongDesc = fmt.Sprintf(normalizer.LongDesc(` saKeyLongDesc = fmt.Sprintf(normalizer.LongDesc(`
Generates the private key for signing service account tokens along with its public key, and saves them into Generates the private key for signing service account tokens along with its public key, and saves them into
%s and %s files. %s and %s files.
@ -71,6 +53,7 @@ var (
// (and thus with different runtime data struct, all of them requested to be compliant to this interface) // (and thus with different runtime data struct, all of them requested to be compliant to this interface)
type certsData interface { type certsData interface {
Cfg() *kubeadmapi.InitConfiguration Cfg() *kubeadmapi.InitConfiguration
ExternalCA() bool
CertificateDir() string CertificateDir() string
CertificateWriteDir() string CertificateWriteDir() string
} }
@ -80,7 +63,8 @@ func NewCertsPhase() workflow.Phase {
return workflow.Phase{ return workflow.Phase{
Name: "certs", Name: "certs",
Short: "Certificate generation", Short: "Certificate generation",
Phases: getCertsSubPhases(), Phases: newCertSubPhases(),
Run: runCerts,
} }
} }
@ -102,8 +86,8 @@ func getCertsSubCommands() []*cobra.Command {
return []*cobra.Command{certscmdphase.NewCmdCertsRenewal()} return []*cobra.Command{certscmdphase.NewCmdCertsRenewal()}
} }
// getCertsSubPhases returns sub phases for certs phase // newCertSubPhases returns sub phases for certs phase
func getCertsSubPhases() []workflow.Phase { func newCertSubPhases() []workflow.Phase {
subPhases := []workflow.Phase{} subPhases := []workflow.Phase{}
certTree, _ := certsphase.GetDefaultCertList().AsMap().CertTree() certTree, _ := certsphase.GetDefaultCertList().AsMap().CertTree()
@ -116,8 +100,6 @@ func getCertsSubPhases() []workflow.Phase {
certPhase := newCertSubPhase(cert, runCertPhase(cert, ca)) certPhase := newCertSubPhase(cert, runCertPhase(cert, ca))
subPhases = append(subPhases, certPhase) subPhases = append(subPhases, certPhase)
} }
subPhases = append(subPhases, caPhase)
} }
// SA creates the private/public key pair, which doesn't use x509 at all // SA creates the private/public key pair, which doesn't use x509 at all
@ -133,19 +115,6 @@ func getCertsSubPhases() []workflow.Phase {
return subPhases return subPhases
} }
func runCertsSa(c workflow.RunData) error {
data, ok := c.(certsData)
if !ok {
return errors.New("certs phase invoked with an invalid data struct")
}
cfg := data.Cfg()
cfg.CertificatesDir = data.CertificateWriteDir()
defer func() { cfg.CertificatesDir = data.CertificateDir() }()
return certsphase.CreateServiceAccountKeyAndPublicKeyFiles(cfg)
}
func newCertSubPhase(certSpec *certsphase.KubeadmCert, run func(c workflow.RunData) error) workflow.Phase { func newCertSubPhase(certSpec *certsphase.KubeadmCert, run func(c workflow.RunData) error) workflow.Phase {
phase := workflow.Phase{ phase := workflow.Phase{
Name: certSpec.Name, Name: certSpec.Name,
@ -195,6 +164,37 @@ func getSANDescription(certSpec *certsphase.KubeadmCert) string {
return fmt.Sprintf("\n\nDefault SANs are %s", strings.Join(sans, ", ")) return fmt.Sprintf("\n\nDefault SANs are %s", strings.Join(sans, ", "))
} }
func runCertsSa(c workflow.RunData) error {
data, ok := c.(certsData)
if !ok {
return errors.New("certs phase invoked with an invalid data struct")
}
// if external CA mode, skip service account key generation
if data.ExternalCA() {
fmt.Printf("[certs] External CA mode: Using existing sa keys\n")
return nil
}
// if dryrunning, write certificates to a temporary folder (and defer restore to the path originally specified by the user)
cfg := data.Cfg()
cfg.CertificatesDir = data.CertificateWriteDir()
defer func() { cfg.CertificatesDir = data.CertificateDir() }()
// create the new service account key (or use existing)
return certsphase.CreateServiceAccountKeyAndPublicKeyFiles(cfg)
}
func runCerts(c workflow.RunData) error {
data, ok := c.(certsData)
if !ok {
return errors.New("certs phase invoked with an invalid data struct")
}
fmt.Printf("[certs] Using certificateDir folder %q\n", data.CertificateWriteDir())
return nil
}
func runCAPhase(ca *certsphase.KubeadmCert) func(c workflow.RunData) error { func runCAPhase(ca *certsphase.KubeadmCert) func(c workflow.RunData) error {
return func(c workflow.RunData) error { return func(c workflow.RunData) error {
data, ok := c.(certsData) data, ok := c.(certsData)
@ -202,10 +202,24 @@ func runCAPhase(ca *certsphase.KubeadmCert) func(c workflow.RunData) error {
return errors.New("certs phase invoked with an invalid data struct") return errors.New("certs phase invoked with an invalid data struct")
} }
// if external CA mode, skips certificate authority generation
if data.ExternalCA() {
fmt.Printf("[certs] External CA mode: Using existing %s certificate authority\n", ca.BaseName)
return nil
}
// if using external etcd, skips etcd certificate authority generation
if data.Cfg().Etcd.External != nil && ca.Name == "etcd-ca" {
fmt.Printf("[certs] External etcd mode: Skipping %s certificate authority generation\n", ca.BaseName)
return nil
}
// if dryrunning, write certificates authority to a temporary folder (and defer restore to the path originally specified by the user)
cfg := data.Cfg() cfg := data.Cfg()
cfg.CertificatesDir = data.CertificateWriteDir() cfg.CertificatesDir = data.CertificateWriteDir()
defer func() { cfg.CertificatesDir = data.CertificateDir() }() defer func() { cfg.CertificatesDir = data.CertificateDir() }()
// create the new certificate authority (or use existing)
return certsphase.CreateCACertAndKeyFiles(ca, cfg) return certsphase.CreateCACertAndKeyFiles(ca, cfg)
} }
} }
@ -217,10 +231,24 @@ func runCertPhase(cert *certsphase.KubeadmCert, caCert *certsphase.KubeadmCert)
return errors.New("certs phase invoked with an invalid data struct") return errors.New("certs phase invoked with an invalid data struct")
} }
// if external CA mode, skip certificate generation
if data.ExternalCA() {
fmt.Printf("[certs] External CA mode: Using existing %s certificate\n", cert.BaseName)
return nil
}
// if using external etcd, skips etcd certificates generation
if data.Cfg().Etcd.External != nil && cert.CAName == "etcd-ca" {
fmt.Printf("[certs] External etcd mode: Skipping %s certificate authority generation\n", cert.BaseName)
return nil
}
// if dryrunning, write certificates to a temporary folder (and defer restore to the path originally specified by the user)
cfg := data.Cfg() cfg := data.Cfg()
cfg.CertificatesDir = data.CertificateWriteDir() cfg.CertificatesDir = data.CertificateWriteDir()
defer func() { cfg.CertificatesDir = data.CertificateDir() }() defer func() { cfg.CertificatesDir = data.CertificateDir() }()
// create the new certificate (or use existing)
return certsphase.CreateCertAndKeyFilesWithCA(cert, caCert, cfg) return certsphase.CreateCertAndKeyFilesWithCA(cert, caCert, cfg)
} }
} }

View File

@ -19,14 +19,13 @@ package phases
import ( import (
"fmt" "fmt"
"io" "io"
"path/filepath"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
kubeadmscheme "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/scheme" kubeadmscheme "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/scheme"
kubeadmapiv1beta1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta1" kubeadmapiv1beta1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta1"
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/workflow"
cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util" cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util"
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
kubeconfigphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig" kubeconfigphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig"
@ -34,62 +33,136 @@ import (
) )
var ( var (
allKubeconfigLongDesc = normalizer.LongDesc(` kubeconfigLongDesc = normalizer.LongDesc(`
Generates all kubeconfig files necessary to establish the control plane and the admin kubeconfig file. kubeconfig file utilities.
` + cmdutil.AlphaDisclaimer) ` + cmdutil.AlphaDisclaimer)
allKubeconfigExample = normalizer.Examples(`
# Generates all kubeconfig files, functionally equivalent to what generated
# by kubeadm init.
kubeadm alpha phase kubeconfig all
# Generates all kubeconfig files using options read from a configuration file.
kubeadm alpha phase kubeconfig all --config masterconfiguration.yaml
`)
adminKubeconfigLongDesc = fmt.Sprintf(normalizer.LongDesc(`
Generates the kubeconfig file for the admin and for kubeadm itself, and saves it to %s file.
`+cmdutil.AlphaDisclaimer), kubeadmconstants.AdminKubeConfigFileName)
kubeletKubeconfigLongDesc = fmt.Sprintf(normalizer.LongDesc(`
Generates the kubeconfig file for the kubelet to use and saves it to %s file.
Please note that this should *only* be used for bootstrapping purposes. After your control plane is up,
you should request all kubelet credentials from the CSR API.
`+cmdutil.AlphaDisclaimer), filepath.Join(kubeadmconstants.KubernetesDir, kubeadmconstants.KubeletKubeConfigFileName))
controllerManagerKubeconfigLongDesc = fmt.Sprintf(normalizer.LongDesc(`
Generates the kubeconfig file for the controller manager to use and saves it to %s file.
`+cmdutil.AlphaDisclaimer), filepath.Join(kubeadmconstants.KubernetesDir, kubeadmconstants.ControllerManagerKubeConfigFileName))
schedulerKubeconfigLongDesc = fmt.Sprintf(normalizer.LongDesc(`
Generates the kubeconfig file for the scheduler to use and saves it to %s file.
`+cmdutil.AlphaDisclaimer), filepath.Join(kubeadmconstants.KubernetesDir, kubeadmconstants.SchedulerKubeConfigFileName))
userKubeconfigLongDesc = normalizer.LongDesc(` userKubeconfigLongDesc = normalizer.LongDesc(`
Outputs a kubeconfig file for an additional user. Outputs a kubeconfig file for an additional user.
` + cmdutil.AlphaDisclaimer) ` + cmdutil.AlphaDisclaimer)
userKubeconfigExample = normalizer.Examples(` userKubeconfigExample = normalizer.Examples(`
# Outputs a kubeconfig file for an additional user named foo # Outputs a kubeconfig file for an additional user named foo
kubeadm alpha phase kubeconfig user --client-name=foo kubeadm alpha kubeconfig user --client-name=foo
`) `)
kubeconfigFilePhaseProperties = map[string]struct {
name string
short string
long string
}{
kubeadmconstants.AdminKubeConfigFileName: {
name: "admin",
short: "Generates a kubeconfig file for the admin to use and for kubeadm itself",
long: "Generates the kubeconfig file for the admin and for kubeadm itself, and saves it to %s file.",
},
kubeadmconstants.KubeletKubeConfigFileName: {
name: "kubelet",
short: "Generates a kubeconfig file for the kubelet to use *only* for cluster bootstrapping purposes",
long: normalizer.LongDesc(`
Generates the kubeconfig file for the kubelet to use and saves it to %s file.
Please note that this should *only* be used for cluster bootstrapping purposes. After your control plane is up,
you should request all kubelet credentials from the CSR API.`),
},
kubeadmconstants.ControllerManagerKubeConfigFileName: {
name: "controller-manager",
short: "Generates a kubeconfig file for the controller manager to use",
long: "Generates the kubeconfig file for the controller manager to use and saves it to %s file",
},
kubeadmconstants.SchedulerKubeConfigFileName: {
name: "scheduler",
short: "Generates a kubeconfig file for the scheduler to use",
long: "Generates the kubeconfig file for the scheduler to use and saves it to %s file.",
},
}
) )
// kubeConfigData defines the behavior that a runtime data struct passed to the kubeconfig phase
// should have. Please note that we are using an interface in order to make this phase reusable in different workflows
// (and thus with different runtime data struct, all of them requested to be compliant to this interface)
type kubeConfigData interface {
Cfg() *kubeadmapi.InitConfiguration
ExternalCA() bool
CertificateDir() string
CertificateWriteDir() string
KubeConfigDir() string
}
// NewKubeConfigPhase creates a kubeadm workflow phase that creates all kubeconfig files necessary to establish the control plane and the admin kubeconfig file.
func NewKubeConfigPhase() workflow.Phase {
return workflow.Phase{
Name: "kubeconfig",
Short: "Generates all kubeconfig files necessary to establish the control plane and the admin kubeconfig file",
Phases: []workflow.Phase{
NewKubeConfigFilePhase(kubeadmconstants.AdminKubeConfigFileName),
NewKubeConfigFilePhase(kubeadmconstants.KubeletKubeConfigFileName),
NewKubeConfigFilePhase(kubeadmconstants.ControllerManagerKubeConfigFileName),
NewKubeConfigFilePhase(kubeadmconstants.SchedulerKubeConfigFileName),
},
Run: runKubeConfig,
}
}
// NewKubeConfigFilePhase creates a kubeadm workflow phase that creates a kubeconfig file.
func NewKubeConfigFilePhase(kubeConfigFileName string) workflow.Phase {
return workflow.Phase{
Name: kubeconfigFilePhaseProperties[kubeConfigFileName].name,
Short: kubeconfigFilePhaseProperties[kubeConfigFileName].short,
Long: fmt.Sprintf(kubeconfigFilePhaseProperties[kubeConfigFileName].long, kubeConfigFileName),
Run: runKubeConfigFile(kubeConfigFileName),
}
}
func runKubeConfig(c workflow.RunData) error {
data, ok := c.(kubeConfigData)
if !ok {
return errors.New("kubeconfig phase invoked with an invalid data struct")
}
fmt.Printf("[kubeconfig] Using kubeconfig folder %q\n", data.KubeConfigDir())
return nil
}
// runKubeConfigFile executes kubeconfig creation logic.
func runKubeConfigFile(kubeConfigFileName string) func(workflow.RunData) error {
return func(c workflow.RunData) error {
data, ok := c.(kubeConfigData)
if !ok {
return errors.New("kubeconfig phase invoked with an invalid data struct")
}
// if external CA mode, skip certificate authority generation
if data.ExternalCA() {
//TODO: implement validation of existing kubeconfig files
fmt.Printf("[kubeconfig] External CA mode: Using user provided %s\n", kubeConfigFileName)
return nil
}
// if dryrunning, reads certificates from a temporary folder (and defer restore to the path originally specified by the user)
cfg := data.Cfg()
cfg.CertificatesDir = data.CertificateWriteDir()
defer func() { cfg.CertificatesDir = data.CertificateDir() }()
// creates the KubeConfig file (or use existing)
return kubeconfigphase.CreateKubeConfigFile(kubeConfigFileName, data.KubeConfigDir(), data.Cfg())
}
}
// NewCmdKubeConfig returns main command for kubeconfig phase // NewCmdKubeConfig returns main command for kubeconfig phase
func NewCmdKubeConfig(out io.Writer) *cobra.Command { func NewCmdKubeConfig(out io.Writer) *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "kubeconfig", Use: "kubeconfig",
Short: "Generates all kubeconfig files necessary to establish the control plane and the admin kubeconfig file", Short: "kubeconfig file utilities",
Long: cmdutil.MacroCommandLongDescription, Long: kubeconfigLongDesc,
} }
cmd.AddCommand(getKubeConfigSubCommands(out, kubeadmconstants.KubernetesDir, "")...) cmd.AddCommand(NewCmdUserKubeConfig(out, kubeadmconstants.KubernetesDir, ""))
return cmd return cmd
} }
// getKubeConfigSubCommands returns sub commands for kubeconfig phase // NewCmdUserKubeConfig returns sub commands for kubeconfig phase
func getKubeConfigSubCommands(out io.Writer, outDir, defaultKubernetesVersion string) []*cobra.Command { func NewCmdUserKubeConfig(out io.Writer, outDir, defaultKubernetesVersion string) *cobra.Command {
cfg := &kubeadmapiv1beta1.InitConfiguration{} cfg := &kubeadmapiv1beta1.InitConfiguration{}
@ -98,52 +171,14 @@ func getKubeConfigSubCommands(out io.Writer, outDir, defaultKubernetesVersion st
var cfgPath, token, clientName string var cfgPath, token, clientName string
var organizations []string var organizations []string
var subCmds []*cobra.Command
subCmdProperties := []struct { // Creates the UX Command
use string cmd := &cobra.Command{
short string Use: "user",
long string Short: "Outputs a kubeconfig file for an additional user",
examples string Long: userKubeconfigLongDesc,
cmdFunc func(outDir string, cfg *kubeadmapi.InitConfiguration) error Example: userKubeconfigExample,
}{ Run: runCmdPhase(func(outDir string, cfg *kubeadmapi.InitConfiguration) error {
{
use: "all",
short: "Generates all kubeconfig files necessary to establish the control plane and the admin kubeconfig file",
long: allKubeconfigLongDesc,
examples: allKubeconfigExample,
cmdFunc: kubeconfigphase.CreateInitKubeConfigFiles,
},
{
use: "admin",
short: "Generates a kubeconfig file for the admin to use and for kubeadm itself",
long: adminKubeconfigLongDesc,
cmdFunc: kubeconfigphase.CreateAdminKubeConfigFile,
},
{
use: "kubelet",
short: "Generates a kubeconfig file for the kubelet to use. Please note that this should be used *only* for bootstrapping purposes",
long: kubeletKubeconfigLongDesc,
cmdFunc: kubeconfigphase.CreateKubeletKubeConfigFile,
},
{
use: "controller-manager",
short: "Generates a kubeconfig file for the controller manager to use",
long: controllerManagerKubeconfigLongDesc,
cmdFunc: kubeconfigphase.CreateControllerManagerKubeConfigFile,
},
{
use: "scheduler",
short: "Generates a kubeconfig file for the scheduler to use",
long: schedulerKubeconfigLongDesc,
cmdFunc: kubeconfigphase.CreateSchedulerKubeConfigFile,
},
{
use: "user",
short: "Outputs a kubeconfig file for an additional user",
long: userKubeconfigLongDesc,
examples: userKubeconfigExample,
cmdFunc: func(outDir string, cfg *kubeadmapi.InitConfiguration) error {
if clientName == "" { if clientName == "" {
return errors.New("missing required argument --client-name") return errors.New("missing required argument --client-name")
} }
@ -155,39 +190,17 @@ func getKubeConfigSubCommands(out io.Writer, outDir, defaultKubernetesVersion st
// Otherwise, write a kubeconfig file with a generate client cert // Otherwise, write a kubeconfig file with a generate client cert
return kubeconfigphase.WriteKubeConfigWithClientCert(out, cfg, clientName, organizations) return kubeconfigphase.WriteKubeConfigWithClientCert(out, cfg, clientName, organizations)
}, }, &outDir, &cfgPath, cfg, defaultKubernetesVersion),
},
}
for _, properties := range subCmdProperties {
// Creates the UX Command
cmd := &cobra.Command{
Use: properties.use,
Short: properties.short,
Long: properties.long,
Example: properties.examples,
Run: runCmdPhase(properties.cmdFunc, &outDir, &cfgPath, cfg, defaultKubernetesVersion),
} }
// Add flags to the command // Add flags to the command
if properties.use != "user" {
cmd.Flags().StringVar(&cfgPath, "config", cfgPath, "Path to kubeadm config file. WARNING: Usage of a configuration file is experimental")
}
cmd.Flags().StringVar(&cfg.CertificatesDir, "cert-dir", cfg.CertificatesDir, "The path where certificates are stored") cmd.Flags().StringVar(&cfg.CertificatesDir, "cert-dir", cfg.CertificatesDir, "The path where certificates are stored")
cmd.Flags().StringVar(&cfg.APIEndpoint.AdvertiseAddress, "apiserver-advertise-address", cfg.APIEndpoint.AdvertiseAddress, "The IP address the API server is accessible on") cmd.Flags().StringVar(&cfg.APIEndpoint.AdvertiseAddress, "apiserver-advertise-address", cfg.APIEndpoint.AdvertiseAddress, "The IP address the API server is accessible on")
cmd.Flags().Int32Var(&cfg.APIEndpoint.BindPort, "apiserver-bind-port", cfg.APIEndpoint.BindPort, "The port the API server is accessible on") cmd.Flags().Int32Var(&cfg.APIEndpoint.BindPort, "apiserver-bind-port", cfg.APIEndpoint.BindPort, "The port the API server is accessible on")
cmd.Flags().StringVar(&outDir, "kubeconfig-dir", outDir, "The path where to save the kubeconfig file") cmd.Flags().StringVar(&outDir, "kubeconfig-dir", outDir, "The path where to save the kubeconfig file")
if properties.use == "all" || properties.use == "kubelet" {
cmd.Flags().StringVar(&cfg.NodeRegistration.Name, "node-name", cfg.NodeRegistration.Name, `The node name that should be used for the kubelet client certificate`)
}
if properties.use == "user" {
cmd.Flags().StringVar(&token, "token", token, "The token that should be used as the authentication mechanism for this kubeconfig, instead of client certificates") cmd.Flags().StringVar(&token, "token", 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().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.Flags().StringSliceVar(&organizations, "org", organizations, "The orgnizations of the client certificate. It will be used as the O if client certificates are created")
}
subCmds = append(subCmds, cmd) return cmd
}
return subCmds
} }

View File

@ -20,299 +20,30 @@ import (
"bytes" "bytes"
"fmt" "fmt"
"os" "os"
"path/filepath"
"testing" "testing"
"github.com/spf13/cobra"
"k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/tools/clientcmd"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
"k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/pkiutil" "k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/pkiutil"
testutil "k8s.io/kubernetes/cmd/kubeadm/test" testutil "k8s.io/kubernetes/cmd/kubeadm/test"
cmdtestutil "k8s.io/kubernetes/cmd/kubeadm/test/cmd" cmdtestutil "k8s.io/kubernetes/cmd/kubeadm/test/cmd"
kubeconfigtestutil "k8s.io/kubernetes/cmd/kubeadm/test/kubeconfig" kubeconfigtestutil "k8s.io/kubernetes/cmd/kubeadm/test/kubeconfig"
) )
func TestKubeConfigCSubCommandsHasFlags(t *testing.T) { func TestKubeConfigCSubCommandsHasFlags(t *testing.T) {
cmd := NewCmdUserKubeConfig(nil, "", phaseTestK8sVersion)
subCmds := getKubeConfigSubCommands(nil, "", phaseTestK8sVersion) flags := []string{
commonFlags := []string{
"cert-dir", "cert-dir",
"apiserver-advertise-address", "apiserver-advertise-address",
"apiserver-bind-port", "apiserver-bind-port",
"kubeconfig-dir", "kubeconfig-dir",
}
var tests = []struct {
command string
additionalFlags []string
}{
{
command: "all",
additionalFlags: []string{
"config",
"node-name",
},
},
{
command: "admin",
additionalFlags: []string{
"config",
},
},
{
command: "kubelet",
additionalFlags: []string{
"config",
"node-name",
},
},
{
command: "controller-manager",
additionalFlags: []string{
"config",
},
},
{
command: "scheduler",
additionalFlags: []string{
"config",
},
},
{
command: "user",
additionalFlags: []string{
"token", "token",
"client-name", "client-name",
},
},
} }
for _, test := range tests { cmdtestutil.AssertSubCommandHasFlags(t, []*cobra.Command{cmd}, "user", flags...)
expectedFlags := append(commonFlags, test.additionalFlags...)
cmdtestutil.AssertSubCommandHasFlags(t, subCmds, test.command, expectedFlags...)
}
}
func TestKubeConfigSubCommandsThatCreateFilesWithFlags(t *testing.T) {
commonFlags := []string{
"--apiserver-advertise-address=1.2.3.4",
"--apiserver-bind-port=1234",
}
var tests = []struct {
command string
additionalFlags []string
expectedFiles []string
}{
{
command: "all",
additionalFlags: []string{"--node-name=valid-nome-name"},
expectedFiles: []string{
kubeadmconstants.AdminKubeConfigFileName,
kubeadmconstants.KubeletKubeConfigFileName,
kubeadmconstants.ControllerManagerKubeConfigFileName,
kubeadmconstants.SchedulerKubeConfigFileName,
},
},
{
command: "admin",
expectedFiles: []string{kubeadmconstants.AdminKubeConfigFileName},
},
{
command: "kubelet",
additionalFlags: []string{"--node-name=valid-nome-name"},
expectedFiles: []string{kubeadmconstants.KubeletKubeConfigFileName},
},
{
command: "controller-manager",
expectedFiles: []string{kubeadmconstants.ControllerManagerKubeConfigFileName},
},
{
command: "scheduler",
expectedFiles: []string{kubeadmconstants.SchedulerKubeConfigFileName},
},
}
var kubeConfigAssertions = map[string]struct {
clientName string
organizations []string
}{
kubeadmconstants.AdminKubeConfigFileName: {
clientName: "kubernetes-admin",
organizations: []string{kubeadmconstants.MastersGroup},
},
kubeadmconstants.KubeletKubeConfigFileName: {
clientName: "system:node:valid-nome-name",
organizations: []string{kubeadmconstants.NodesGroup},
},
kubeadmconstants.ControllerManagerKubeConfigFileName: {
clientName: kubeadmconstants.ControllerManagerUser,
},
kubeadmconstants.SchedulerKubeConfigFileName: {
clientName: kubeadmconstants.SchedulerUser,
},
}
for _, test := range tests {
// Create temp folder for the test case
tmpdir := testutil.SetupTempDir(t)
defer os.RemoveAll(tmpdir)
// Adds a pki folder with a ca certs to the temp folder
pkidir := testutil.SetupPkiDirWithCertificateAuthorithy(t, tmpdir)
outputdir := tmpdir
// Retrieves ca cert for assertions
caCert, _, err := pkiutil.TryLoadCertAndKeyFromDisk(pkidir, kubeadmconstants.CACertAndKeyBaseName)
if err != nil {
t.Fatalf("couldn't retrieve ca cert: %v", err)
}
// Get subcommands working in the temporary directory
subCmds := getKubeConfigSubCommands(nil, tmpdir, phaseTestK8sVersion)
// Execute the subcommand
certDirFlag := fmt.Sprintf("--cert-dir=%s", pkidir)
outputDirFlag := fmt.Sprintf("--kubeconfig-dir=%s", outputdir)
allFlags := append(commonFlags, certDirFlag)
allFlags = append(allFlags, outputDirFlag)
allFlags = append(allFlags, test.additionalFlags...)
cmdtestutil.RunSubCommand(t, subCmds, test.command, allFlags...)
// Checks that requested files are there
testutil.AssertFileExists(t, tmpdir, test.expectedFiles...)
// Checks contents of generated files
for _, file := range test.expectedFiles {
// reads generated files
config, err := clientcmd.LoadFromFile(filepath.Join(tmpdir, file))
if err != nil {
t.Errorf("couldn't load generated kubeconfig file: %v", err)
}
// checks that CLI flags are properly propagated and kubeconfig properties are correct
kubeconfigtestutil.AssertKubeConfigCurrentCluster(t, config, "https://1.2.3.4:1234", caCert)
expectedClientName := kubeConfigAssertions[file].clientName
expectedOrganizations := kubeConfigAssertions[file].organizations
kubeconfigtestutil.AssertKubeConfigCurrentAuthInfoWithClientCert(t, config, caCert, expectedClientName, expectedOrganizations...)
}
}
}
func TestKubeConfigSubCommandsThatCreateFilesWithConfigFile(t *testing.T) {
var tests = []struct {
command string
expectedFiles []string
}{
{
command: "all",
expectedFiles: []string{
kubeadmconstants.AdminKubeConfigFileName,
kubeadmconstants.KubeletKubeConfigFileName,
kubeadmconstants.ControllerManagerKubeConfigFileName,
kubeadmconstants.SchedulerKubeConfigFileName,
},
},
{
command: "admin",
expectedFiles: []string{kubeadmconstants.AdminKubeConfigFileName},
},
{
command: "kubelet",
expectedFiles: []string{kubeadmconstants.KubeletKubeConfigFileName},
},
{
command: "controller-manager",
expectedFiles: []string{kubeadmconstants.ControllerManagerKubeConfigFileName},
},
{
command: "scheduler",
expectedFiles: []string{kubeadmconstants.SchedulerKubeConfigFileName},
},
}
var kubeConfigAssertions = map[string]struct {
clientName string
organizations []string
}{
kubeadmconstants.AdminKubeConfigFileName: {
clientName: "kubernetes-admin",
organizations: []string{kubeadmconstants.MastersGroup},
},
kubeadmconstants.KubeletKubeConfigFileName: {
clientName: "system:node:valid-node-name",
organizations: []string{kubeadmconstants.NodesGroup},
},
kubeadmconstants.ControllerManagerKubeConfigFileName: {
clientName: kubeadmconstants.ControllerManagerUser,
},
kubeadmconstants.SchedulerKubeConfigFileName: {
clientName: kubeadmconstants.SchedulerUser,
},
}
for _, test := range tests {
// Create temp folder for the test case
tmpdir := testutil.SetupTempDir(t)
defer os.RemoveAll(tmpdir)
// Adds a pki folder with a ca certs to the temp folder
pkidir := testutil.SetupPkiDirWithCertificateAuthorithy(t, tmpdir)
// Retrieves ca cert for assertions
caCert, _, err := pkiutil.TryLoadCertAndKeyFromDisk(pkidir, kubeadmconstants.CACertAndKeyBaseName)
if err != nil {
t.Fatalf("couldn't retrieve ca cert: %v", err)
}
// Adds a master configuration file
cfg := &kubeadmapi.InitConfiguration{
APIEndpoint: kubeadmapi.APIEndpoint{AdvertiseAddress: "1.2.3.4", BindPort: 1234},
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
CertificatesDir: pkidir,
},
NodeRegistration: kubeadmapi.NodeRegistrationOptions{Name: "valid-node-name"},
}
cfgPath := testutil.SetupInitConfigurationFile(t, tmpdir, cfg)
// Get subcommands working in the temporary directory
subCmds := getKubeConfigSubCommands(nil, tmpdir, phaseTestK8sVersion)
// Execute the subcommand
configFlag := fmt.Sprintf("--config=%s", cfgPath)
cmdtestutil.RunSubCommand(t, subCmds, test.command, configFlag)
// Checks that requested files are there
testutil.AssertFileExists(t, tmpdir, test.expectedFiles...)
// Checks contents of generated files
for _, file := range test.expectedFiles {
// reads generated files
config, err := clientcmd.LoadFromFile(filepath.Join(tmpdir, file))
if err != nil {
t.Errorf("couldn't load generated kubeconfig file: %v", err)
}
// checks that config file properties are properly propagated and kubeconfig properties are correct
kubeconfigtestutil.AssertKubeConfigCurrentCluster(t, config, "https://1.2.3.4:1234", caCert)
expectedClientName := kubeConfigAssertions[file].clientName
expectedOrganizations := kubeConfigAssertions[file].organizations
kubeconfigtestutil.AssertKubeConfigCurrentAuthInfoWithClientCert(t, config, caCert, expectedClientName, expectedOrganizations...)
}
}
} }
func TestKubeConfigSubCommandsThatWritesToOut(t *testing.T) { func TestKubeConfigSubCommandsThatWritesToOut(t *testing.T) {
@ -361,11 +92,11 @@ func TestKubeConfigSubCommandsThatWritesToOut(t *testing.T) {
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
// Get subcommands working in the temporary directory // Get subcommands working in the temporary directory
subCmds := getKubeConfigSubCommands(buf, tmpdir, phaseTestK8sVersion) cmd := NewCmdUserKubeConfig(buf, tmpdir, phaseTestK8sVersion)
// Execute the subcommand // Execute the subcommand
allFlags := append(commonFlags, test.additionalFlags...) allFlags := append(commonFlags, test.additionalFlags...)
cmdtestutil.RunSubCommand(t, subCmds, test.command, allFlags...) cmdtestutil.RunSubCommand(t, []*cobra.Command{cmd}, test.command, allFlags...)
// reads kubeconfig written to stdout // reads kubeconfig written to stdout
config, err := clientcmd.Load(buf.Bytes()) config, err := clientcmd.Load(buf.Bytes())

View File

@ -81,7 +81,7 @@ func runPreflightMaster(c workflow.RunData) error {
return errors.New("preflight phase invoked with an invalid data struct") return errors.New("preflight phase invoked with an invalid data struct")
} }
fmt.Println("[preflight] running pre-flight checks") fmt.Println("[preflight] Running pre-flight checks")
if err := preflight.RunInitMasterChecks(utilsexec.New(), data.Cfg(), data.IgnorePreflightErrors()); err != nil { if err := preflight.RunInitMasterChecks(utilsexec.New(), data.Cfg(), data.IgnorePreflightErrors()); err != nil {
return err return err
} }

View File

@ -25,7 +25,6 @@ import (
"github.com/golang/glog" "github.com/golang/glog"
"github.com/pkg/errors" "github.com/pkg/errors"
certutil "k8s.io/client-go/util/cert" certutil "k8s.io/client-go/util/cert"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
@ -57,7 +56,7 @@ func CreatePKIAssets(cfg *kubeadmapi.InitConfiguration) error {
return errors.Wrap(err, "error creating PKI assets") return errors.Wrap(err, "error creating PKI assets")
} }
fmt.Printf("[certificates] valid certificates and keys now exist in %q\n", cfg.CertificatesDir) fmt.Printf("[certs] valid certificates and keys now exist in %q\n", cfg.CertificatesDir)
// Service accounts are not x509 certs, so handled separately // Service accounts are not x509 certs, so handled separately
if err := CreateServiceAccountKeyAndPublicKeyFiles(cfg); err != nil { if err := CreateServiceAccountKeyAndPublicKeyFiles(cfg); err != nil {
@ -190,15 +189,14 @@ func writeCertificateAuthorithyFilesIfNotExist(pkiDir string, baseName string, c
// kubeadm doesn't validate the existing certificate Authority more than this; // kubeadm doesn't validate the existing certificate Authority more than this;
// Basically, if we find a certificate file with the same path; and it is a CA // Basically, if we find a certificate file with the same path; and it is a CA
// kubeadm thinks those files are equal and doesn't bother writing a new file // kubeadm thinks those files are equal and doesn't bother writing a new file
fmt.Printf("[certificates] Using the existing %s certificate and key.\n", baseName) fmt.Printf("[certs] Using the existing %q certificate and key\n", baseName)
} else { } else {
// Write .crt and .key files to disk // Write .crt and .key files to disk
fmt.Printf("[certs] Generating %q certificate and key\n", baseName)
if err := pkiutil.WriteCertAndKey(pkiDir, baseName, caCert, caKey); err != nil { if err := pkiutil.WriteCertAndKey(pkiDir, baseName, caCert, caKey); err != nil {
return errors.Wrapf(err, "failure while saving %s certificate and key", baseName) return errors.Wrapf(err, "failure while saving %s certificate and key", baseName)
} }
fmt.Printf("[certificates] Generated %s certificate and key.\n", baseName)
} }
return nil return nil
} }
@ -226,17 +224,16 @@ func writeCertificateFilesIfNotExist(pkiDir string, baseName string, signingCert
// Basically, if we find a certificate file with the same path; and it is signed by // Basically, if we find a certificate file with the same path; and it is signed by
// the expected certificate authority, kubeadm thinks those files are equal and // the expected certificate authority, kubeadm thinks those files are equal and
// doesn't bother writing a new file // doesn't bother writing a new file
fmt.Printf("[certificates] Using the existing %s certificate and key.\n", baseName) fmt.Printf("[certs] Using the existing %q certificate and key\n", baseName)
} else { } else {
// Write .crt and .key files to disk // Write .crt and .key files to disk
fmt.Printf("[certs] Generating %q certificate and key\n", baseName)
if err := pkiutil.WriteCertAndKey(pkiDir, baseName, cert, key); err != nil { if err := pkiutil.WriteCertAndKey(pkiDir, baseName, cert, key); err != nil {
return errors.Wrapf(err, "failure while saving %s certificate and key", baseName) return errors.Wrapf(err, "failure while saving %s certificate and key", baseName)
} }
fmt.Printf("[certificates] Generated %s certificate and key.\n", baseName)
if pkiutil.HasServerAuth(cert) { if pkiutil.HasServerAuth(cert) {
fmt.Printf("[certificates] %s serving cert is signed for DNS names %v and IPs %v\n", baseName, cert.DNSNames, cert.IPAddresses) fmt.Printf("[certs] %s serving cert is signed for DNS names %v and IPs %v\n", baseName, cert.DNSNames, cert.IPAddresses)
} }
} }
@ -261,10 +258,12 @@ func writeKeyFilesIfNotExist(pkiDir string, baseName string, key *rsa.PrivateKey
// kubeadm doesn't validate the existing certificate key more than this; // kubeadm doesn't validate the existing certificate key more than this;
// Basically, if we find a key file with the same path kubeadm thinks those files // Basically, if we find a key file with the same path kubeadm thinks those files
// are equal and doesn't bother writing a new file // are equal and doesn't bother writing a new file
fmt.Printf("[certificates] Using the existing %s key.\n", baseName) fmt.Printf("[certs] Using the existing %q key\n", baseName)
} else { } else {
// Write .key and .pub files to disk // Write .key and .pub files to disk
fmt.Printf("[certs] Generating %q key and public key\n", baseName)
if err := pkiutil.WriteKey(pkiDir, baseName, key); err != nil { if err := pkiutil.WriteKey(pkiDir, baseName, key); err != nil {
return errors.Wrapf(err, "failure while saving %s key", baseName) return errors.Wrapf(err, "failure while saving %s key", baseName)
} }
@ -272,7 +271,6 @@ func writeKeyFilesIfNotExist(pkiDir string, baseName string, key *rsa.PrivateKey
if err := pkiutil.WritePublicKey(pkiDir, baseName, &key.PublicKey); err != nil { if err := pkiutil.WritePublicKey(pkiDir, baseName, &key.PublicKey); err != nil {
return errors.Wrapf(err, "failure while saving %s public key", baseName) return errors.Wrapf(err, "failure while saving %s public key", baseName)
} }
fmt.Printf("[certificates] Generated %s key and public key.\n", baseName)
} }
return nil return nil

View File

@ -18,17 +18,15 @@ package kubeconfig
import ( import (
"bytes" "bytes"
"crypto/rsa"
"crypto/x509" "crypto/x509"
"fmt" "fmt"
"io" "io"
"os" "os"
"path/filepath" "path/filepath"
"crypto/rsa"
"github.com/golang/glog" "github.com/golang/glog"
"github.com/pkg/errors" "github.com/pkg/errors"
"k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api" clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
certutil "k8s.io/client-go/util/cert" certutil "k8s.io/client-go/util/cert"
@ -88,32 +86,11 @@ func CreateJoinControlPlaneKubeConfigFiles(outDir string, cfg *kubeadmapi.InitCo
) )
} }
// CreateAdminKubeConfigFile create a kubeconfig file for the admin to use and for kubeadm itself. // CreateKubeConfigFile creates a kubeconfig file.
// If the kubeconfig file already exists, it is used only if evaluated equal; otherwise an error is returned. // If the kubeconfig file already exists, it is used only if evaluated equal; otherwise an error is returned.
func CreateAdminKubeConfigFile(outDir string, cfg *kubeadmapi.InitConfiguration) error { func CreateKubeConfigFile(kubeConfigFileName string, outDir string, cfg *kubeadmapi.InitConfiguration) error {
glog.V(1).Infoln("create a kubeconfig file for the admin and for kubeadm itself") glog.V(1).Infof("creating kubeconfig file for %s", kubeConfigFileName)
return createKubeConfigFiles(outDir, cfg, kubeadmconstants.AdminKubeConfigFileName) return createKubeConfigFiles(outDir, cfg, kubeConfigFileName)
}
// CreateKubeletKubeConfigFile create a kubeconfig file for the Kubelet to use.
// If the kubeconfig file already exists, it is used only if evaluated equal; otherwise an error is returned.
func CreateKubeletKubeConfigFile(outDir string, cfg *kubeadmapi.InitConfiguration) error {
glog.V(1).Infoln("creating a kubeconfig file for the Kubelet")
return createKubeConfigFiles(outDir, cfg, kubeadmconstants.KubeletKubeConfigFileName)
}
// CreateControllerManagerKubeConfigFile create a kubeconfig file for the ControllerManager to use.
// If the kubeconfig file already exists, it is used only if evaluated equal; otherwise an error is returned.
func CreateControllerManagerKubeConfigFile(outDir string, cfg *kubeadmapi.InitConfiguration) error {
glog.V(1).Infoln("creating kubeconfig file for the ControllerManager")
return createKubeConfigFiles(outDir, cfg, kubeadmconstants.ControllerManagerKubeConfigFileName)
}
// CreateSchedulerKubeConfigFile create a create a kubeconfig file for the Scheduler to use.
// If the kubeconfig file already exists, it is used only if evaluated equal; otherwise an error is returned.
func CreateSchedulerKubeConfigFile(outDir string, cfg *kubeadmapi.InitConfiguration) error {
glog.V(1).Infoln("creating kubeconfig file for Scheduler")
return createKubeConfigFiles(outDir, cfg, kubeadmconstants.SchedulerKubeConfigFileName)
} }
// createKubeConfigFiles creates all the requested kubeconfig files. // createKubeConfigFiles creates all the requested kubeconfig files.
@ -248,12 +225,12 @@ func createKubeConfigFileIfNotExists(outDir, filename string, config *clientcmda
// Check if the file exist, and if it doesn't, just write it to disk // Check if the file exist, and if it doesn't, just write it to disk
if _, err := os.Stat(kubeConfigFilePath); os.IsNotExist(err) { if _, err := os.Stat(kubeConfigFilePath); os.IsNotExist(err) {
fmt.Printf("[kubeconfig] Writing %q kubeconfig file\n", filename)
err = kubeconfigutil.WriteToDisk(kubeConfigFilePath, config) err = kubeconfigutil.WriteToDisk(kubeConfigFilePath, config)
if err != nil { if err != nil {
return errors.Wrapf(err, "failed to save kubeconfig file %s on disk", kubeConfigFilePath) return errors.Wrapf(err, "failed to save kubeconfig file %s on disk", kubeConfigFilePath)
} }
fmt.Printf("[kubeconfig] Wrote KubeConfig file to disk: %q\n", kubeConfigFilePath)
return nil return nil
} }

View File

@ -292,22 +292,6 @@ func TestCreateKubeconfigFilesAndWrappers(t *testing.T) {
kubeadmconstants.SchedulerKubeConfigFileName, kubeadmconstants.SchedulerKubeConfigFileName,
}, },
}, },
{ // Test CreateAdminKubeConfigFile (wrapper to createKubeConfigFile)
createKubeConfigFunction: CreateAdminKubeConfigFile,
expectedFiles: []string{kubeadmconstants.AdminKubeConfigFileName},
},
{ // Test CreateKubeletKubeConfigFile (wrapper to createKubeConfigFile)
createKubeConfigFunction: CreateKubeletKubeConfigFile,
expectedFiles: []string{kubeadmconstants.KubeletKubeConfigFileName},
},
{ // Test CreateControllerManagerKubeConfigFile (wrapper to createKubeConfigFile)
createKubeConfigFunction: CreateControllerManagerKubeConfigFile,
expectedFiles: []string{kubeadmconstants.ControllerManagerKubeConfigFileName},
},
{ // Test createKubeConfigFile (wrapper to createKubeConfigFile)
createKubeConfigFunction: CreateSchedulerKubeConfigFile,
expectedFiles: []string{kubeadmconstants.SchedulerKubeConfigFileName},
},
} }
for _, test := range tests { for _, test := range tests {

View File

@ -40,7 +40,6 @@ func TestCmdInitToken(t *testing.T) {
args string args string
expected bool expected bool
}{ }{
/*
{ {
name: "invalid token size", name: "invalid token size",
args: "--token=abcd:1234567890abcd", args: "--token=abcd:1234567890abcd",
@ -51,7 +50,6 @@ func TestCmdInitToken(t *testing.T) {
args: "--token=Abcdef:1234567890abcdef", args: "--token=Abcdef:1234567890abcdef",
expected: false, expected: false,
}, },
*/
{ {
name: "valid token is accepted", name: "valid token is accepted",
args: "--token=abcdef.0123456789abcdef", args: "--token=abcdef.0123456789abcdef",