Merge pull request #72111 from rosti/reduce-initcfg

kubeadm: Reduce the usage of InitConfiguration
pull/564/head
Kubernetes Prow Robot 2019-01-29 14:01:07 -08:00 committed by GitHub
commit b8b689aae0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
42 changed files with 458 additions and 620 deletions

View File

@ -125,7 +125,7 @@ func getSelfhostingSubCommand(in io.Reader) *cobra.Command {
// KubernetesVersion is not used, but we set it explicitly to avoid the lookup // KubernetesVersion is not used, but we set it explicitly to avoid the lookup
// of the version from the internet when executing ConfigFileAndDefaultsToInternalConfig // of the version from the internet when executing ConfigFileAndDefaultsToInternalConfig
phases.SetKubernetesVersion(cfg) phases.SetKubernetesVersion(&cfg.ClusterConfiguration)
// This call returns the ready-to-use configuration based on the configuration file that might or might not exist and the default cfg populated by flags // This call returns the ready-to-use configuration based on the configuration file that might or might not exist and the default cfg populated by flags
internalcfg, err := configutil.ConfigFileAndDefaultsToInternalConfig(cfgPath, cfg) internalcfg, err := configutil.ConfigFileAndDefaultsToInternalConfig(cfgPath, cfg)

View File

@ -388,7 +388,7 @@ func RunConfigView(out io.Writer, client clientset.Interface) error {
func uploadConfiguration(client clientset.Interface, cfgPath string, defaultcfg *kubeadmapiv1beta1.InitConfiguration) error { func uploadConfiguration(client clientset.Interface, cfgPath string, defaultcfg *kubeadmapiv1beta1.InitConfiguration) error {
// KubernetesVersion is not used, but we set it explicitly to avoid the lookup // KubernetesVersion is not used, but we set it explicitly to avoid the lookup
// of the version from the internet when executing ConfigFileAndDefaultsToInternalConfig // of the version from the internet when executing ConfigFileAndDefaultsToInternalConfig
phaseutil.SetKubernetesVersion(defaultcfg) phaseutil.SetKubernetesVersion(&defaultcfg.ClusterConfiguration)
// Default both statically and dynamically, convert to internal API type, and validate everything // Default both statically and dynamically, convert to internal API type, and validate everything
// First argument is unset here as we shouldn't load a config file from disk // First argument is unset here as we shouldn't load a config file from disk

View File

@ -333,7 +333,7 @@ func newInitData(cmd *cobra.Command, args []string, options *initOptions, out io
} }
// Checks if an external CA is provided by the user. // Checks if an external CA is provided by the user.
externalCA, _ := certsphase.UsingExternalCA(cfg) externalCA, _ := certsphase.UsingExternalCA(&cfg.ClusterConfiguration)
if externalCA { if externalCA {
kubeconfigDir := kubeadmconstants.KubernetesDir kubeconfigDir := kubeadmconstants.KubernetesDir
if options.dryRun { if options.dryRun {

View File

@ -466,14 +466,14 @@ func (j *joinData) Run() error {
// Continue with more specific checks based on the init configuration // Continue with more specific checks based on the init configuration
klog.V(1).Infoln("[preflight] Running configuration dependant checks") klog.V(1).Infoln("[preflight] Running configuration dependant checks")
if err := preflight.RunOptionalJoinNodeChecks(utilsexec.New(), initCfg, j.ignorePreflightErrors); err != nil { if err := preflight.RunOptionalJoinNodeChecks(utilsexec.New(), &initCfg.ClusterConfiguration, j.ignorePreflightErrors); err != nil {
return err return err
} }
if j.cfg.ControlPlane != nil { if j.cfg.ControlPlane != nil {
// Checks if the cluster configuration supports // Checks if the cluster configuration supports
// joining a new control plane instance and if all the necessary certificates are provided // joining a new control plane instance and if all the necessary certificates are provided
if err := j.CheckIfReadyForAdditionalControlPlane(initCfg); err != nil { if err := j.CheckIfReadyForAdditionalControlPlane(&initCfg.ClusterConfiguration); err != nil {
// outputs the not ready for hosting a new control plane instance message // outputs the not ready for hosting a new control plane instance message
ctx := map[string]string{ ctx := map[string]string{
"Error": err.Error(), "Error": err.Error(),
@ -539,14 +539,14 @@ func (j *joinData) Run() error {
// CheckIfReadyForAdditionalControlPlane ensures that the cluster is in a state that supports // CheckIfReadyForAdditionalControlPlane ensures that the cluster is in a state that supports
// joining an additional control plane instance and if the node is ready to join // joining an additional control plane instance and if the node is ready to join
func (j *joinData) CheckIfReadyForAdditionalControlPlane(initConfiguration *kubeadmapi.InitConfiguration) error { func (j *joinData) CheckIfReadyForAdditionalControlPlane(cfg *kubeadmapi.ClusterConfiguration) error {
// blocks if the cluster was created without a stable control plane endpoint // blocks if the cluster was created without a stable control plane endpoint
if initConfiguration.ControlPlaneEndpoint == "" { if cfg.ControlPlaneEndpoint == "" {
return errors.New("unable to add a new control plane instance a cluster that doesn't have a stable controlPlaneEndpoint address") return errors.New("unable to add a new control plane instance a cluster that doesn't have a stable controlPlaneEndpoint address")
} }
// checks if the certificates that must be equal across contolplane instances are provided // checks if the certificates that must be equal across contolplane instances are provided
if ret, err := certsphase.SharedCertificateExists(initConfiguration); !ret { if ret, err := certsphase.SharedCertificateExists(cfg); !ret {
return err return err
} }
@ -586,7 +586,7 @@ func (j *joinData) PrepareForHostingControlPlane(initConfiguration *kubeadmapi.I
return errors.Wrap(err, "couldn't create Kubernetes client") return errors.Wrap(err, "couldn't create Kubernetes client")
} }
if err := etcdphase.CheckLocalEtcdClusterStatus(client, initConfiguration); err != nil { if err := etcdphase.CheckLocalEtcdClusterStatus(client, &initConfiguration.ClusterConfiguration); err != nil {
return err return err
} }
} }
@ -638,7 +638,7 @@ func (j *joinData) BootstrapKubelet(tlsBootstrapCfg *clientcmdapi.Config, initCo
// register the joining node with the specified taints if the node // register the joining node with the specified taints if the node
// is not a master. The markmaster phase will register the taints otherwise. // is not a master. The markmaster phase will register the taints otherwise.
registerTaintsUsingFlags := j.cfg.ControlPlane == nil registerTaintsUsingFlags := j.cfg.ControlPlane == nil
if err := kubeletphase.WriteKubeletDynamicEnvFile(initConfiguration, registerTaintsUsingFlags, kubeadmconstants.KubeletRunDirectory); err != nil { if err := kubeletphase.WriteKubeletDynamicEnvFile(&initConfiguration.ClusterConfiguration, &initConfiguration.NodeRegistration, registerTaintsUsingFlags, kubeadmconstants.KubeletRunDirectory); err != nil {
return err return err
} }
@ -690,7 +690,7 @@ func (j *joinData) PostInstallControlPlane(initConfiguration *kubeadmapi.InitCon
// because it needs two members as majority to agree on the consensus. You will only see this behavior between the time // because it needs two members as majority to agree on the consensus. You will only see this behavior between the time
// etcdctl member add informs the cluster about the new member and the new member successfully establishing a connection to the existing one." // etcdctl member add informs the cluster about the new member and the new member successfully establishing a connection to the existing one."
klog.V(1).Info("[join] adding etcd") klog.V(1).Info("[join] adding etcd")
if err := etcdphase.CreateStackedEtcdStaticPodManifestFile(client, kubeadmconstants.GetStaticPodDirectory(), initConfiguration); err != nil { if err := etcdphase.CreateStackedEtcdStaticPodManifestFile(client, kubeadmconstants.GetStaticPodDirectory(), initConfiguration.NodeRegistration.Name, &initConfiguration.ClusterConfiguration, &initConfiguration.LocalAPIEndpoint); err != nil {
return errors.Wrap(err, "error creating local etcd static pod manifest file") return errors.Wrap(err, "error creating local etcd static pod manifest file")
} }
} }

View File

@ -95,7 +95,7 @@ func runCoreDNSAddon(c workflow.RunData) error {
if err != nil { if err != nil {
return err return err
} }
return dnsaddon.EnsureDNSAddon(cfg, client) return dnsaddon.EnsureDNSAddon(&cfg.ClusterConfiguration, client)
} }
// runKubeProxyAddon installs KubeProxy addon to a Kubernetes cluster // runKubeProxyAddon installs KubeProxy addon to a Kubernetes cluster
@ -104,7 +104,7 @@ func runKubeProxyAddon(c workflow.RunData) error {
if err != nil { if err != nil {
return err return err
} }
return proxyaddon.EnsureProxyAddon(cfg, client) return proxyaddon.EnsureProxyAddon(&cfg.ClusterConfiguration, &cfg.LocalAPIEndpoint, client)
} }
func getAddonPhaseFlags(name string) []string { func getAddonPhaseFlags(name string) []string {

View File

@ -204,13 +204,8 @@ func runCertsSa(c workflow.RunData) error {
return nil 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) // create the new service account key (or use existing)
return certsphase.CreateServiceAccountKeyAndPublicKeyFiles(cfg) return certsphase.CreateServiceAccountKeyAndPublicKeyFiles(data.CertificateWriteDir())
} }
func runCerts(c workflow.RunData) error { func runCerts(c workflow.RunData) error {

View File

@ -150,6 +150,6 @@ func runControlPlaneSubPhase(component string) func(c workflow.RunData) error {
cfg := data.Cfg() cfg := data.Cfg()
fmt.Printf("[control-plane] Creating static Pod manifest for %q\n", component) fmt.Printf("[control-plane] Creating static Pod manifest for %q\n", component)
return controlplane.CreateStaticPodFiles(data.ManifestDir(), cfg, component) return controlplane.CreateStaticPodFiles(data.ManifestDir(), &cfg.ClusterConfiguration, &cfg.LocalAPIEndpoint, component)
} }
} }

View File

@ -90,7 +90,7 @@ func runEtcdPhaseLocal() func(c workflow.RunData) error {
// Add etcd static pod spec only if external etcd is not configured // Add etcd static pod spec only if external etcd is not configured
if cfg.Etcd.External == nil { if cfg.Etcd.External == nil {
fmt.Printf("[etcd] Creating static Pod manifest for local etcd in %q\n", data.ManifestDir()) fmt.Printf("[etcd] Creating static Pod manifest for local etcd in %q\n", data.ManifestDir())
if err := etcdphase.CreateLocalEtcdStaticPodManifestFile(data.ManifestDir(), cfg); err != nil { if err := etcdphase.CreateLocalEtcdStaticPodManifestFile(data.ManifestDir(), cfg.NodeRegistration.Name, &cfg.ClusterConfiguration, &cfg.LocalAPIEndpoint); err != nil {
return errors.Wrap(err, "error creating local etcd static pod manifest file") return errors.Wrap(err, "error creating local etcd static pod manifest file")
} }
} else { } else {

View File

@ -75,7 +75,7 @@ func runKubeletStart(c workflow.RunData) error {
// Write env file with flags for the kubelet to use. We do not need to write the --register-with-taints for the master, // Write env file with flags for the kubelet to use. We do not need to write the --register-with-taints for the master,
// as we handle that ourselves in the markmaster phase // as we handle that ourselves in the markmaster phase
// TODO: Maybe we want to do that some time in the future, in order to remove some logic from the markmaster phase? // TODO: Maybe we want to do that some time in the future, in order to remove some logic from the markmaster phase?
if err := kubeletphase.WriteKubeletDynamicEnvFile(data.Cfg(), false, data.KubeletDir()); err != nil { if err := kubeletphase.WriteKubeletDynamicEnvFile(&data.Cfg().ClusterConfiguration, &data.Cfg().NodeRegistration, false, data.KubeletDir()); err != nil {
return errors.Wrap(err, "error writing a dynamic environment file for the kubelet") return errors.Wrap(err, "error writing a dynamic environment file for the kubelet")
} }

View File

@ -126,7 +126,7 @@ func runUploadKubeletConfig(c workflow.RunData) error {
} }
klog.V(1).Infof("[upload-config] Uploading the kubelet component config to a ConfigMap") klog.V(1).Infof("[upload-config] Uploading the kubelet component config to a ConfigMap")
if err = kubeletphase.CreateConfigMap(cfg, client); err != nil { if err = kubeletphase.CreateConfigMap(cfg.ClusterConfiguration.ComponentConfigs.Kubelet, cfg.KubernetesVersion, client); err != nil {
return errors.Wrap(err, "error creating kubelet configuration ConfigMap") return errors.Wrap(err, "error creating kubelet configuration ConfigMap")
} }

View File

@ -23,7 +23,7 @@ import (
// SetKubernetesVersion gets the current Kubeadm version and sets it as KubeadmVersion in the config, // SetKubernetesVersion gets the current Kubeadm version and sets it as KubeadmVersion in the config,
// unless it's already set to a value different from the default. // unless it's already set to a value different from the default.
func SetKubernetesVersion(cfg *kubeadmapiv1beta1.InitConfiguration) { func SetKubernetesVersion(cfg *kubeadmapiv1beta1.ClusterConfiguration) {
if cfg.KubernetesVersion != kubeadmapiv1beta1.DefaultKubernetesVersion && cfg.KubernetesVersion != "" { if cfg.KubernetesVersion != kubeadmapiv1beta1.DefaultKubernetesVersion && cfg.KubernetesVersion != "" {
return return

View File

@ -51,7 +51,7 @@ func TestSetKubernetesVersion(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
cfg := &kubeadmapiv1beta1.InitConfiguration{ClusterConfiguration: kubeadmapiv1beta1.ClusterConfiguration{KubernetesVersion: test.input}} cfg := &kubeadmapiv1beta1.ClusterConfiguration{KubernetesVersion: test.input}
SetKubernetesVersion(cfg) SetKubernetesVersion(cfg)
if cfg.KubernetesVersion != test.output { if cfg.KubernetesVersion != test.output {
t.Fatalf("expected %q, got %q", test.output, cfg.KubernetesVersion) t.Fatalf("expected %q, got %q", test.output, cfg.KubernetesVersion)

View File

@ -212,7 +212,7 @@ func NewCmdTokenGenerate(out io.Writer) *cobra.Command {
func RunCreateToken(out io.Writer, client clientset.Interface, cfgPath string, cfg *kubeadmapiv1beta1.InitConfiguration, printJoinCommand bool, kubeConfigFile string) error { func RunCreateToken(out io.Writer, client clientset.Interface, cfgPath string, cfg *kubeadmapiv1beta1.InitConfiguration, printJoinCommand bool, kubeConfigFile string) error {
// KubernetesVersion is not used, but we set it explicitly to avoid the lookup // KubernetesVersion is not used, but we set it explicitly to avoid the lookup
// of the version from the internet when executing ConfigFileAndDefaultsToInternalConfig // of the version from the internet when executing ConfigFileAndDefaultsToInternalConfig
phaseutil.SetKubernetesVersion(cfg) phaseutil.SetKubernetesVersion(&cfg.ClusterConfiguration)
// This call returns the ready-to-use configuration based on the configuration file that might or might not exist and the default cfg populated by flags // This call returns the ready-to-use configuration based on the configuration file that might or might not exist and the default cfg populated by flags
klog.V(1).Infoln("[token] loading configurations") klog.V(1).Infoln("[token] loading configurations")

View File

@ -105,7 +105,7 @@ func runDiff(flags *diffFlags, args []string) error {
return err return err
} }
specs := controlplane.GetStaticPodSpecs(cfg, k8sVer) specs := controlplane.GetStaticPodSpecs(&cfg.ClusterConfiguration, &cfg.LocalAPIEndpoint, k8sVer)
for spec, pod := range specs { for spec, pod := range specs {
var path string var path string
switch spec { switch spec {

View File

@ -74,14 +74,14 @@ func DeployedDNSAddon(client clientset.Interface) (kubeadmapi.DNSAddOnType, stri
} }
// EnsureDNSAddon creates the kube-dns or CoreDNS addon // EnsureDNSAddon creates the kube-dns or CoreDNS addon
func EnsureDNSAddon(cfg *kubeadmapi.InitConfiguration, client clientset.Interface) error { func EnsureDNSAddon(cfg *kubeadmapi.ClusterConfiguration, client clientset.Interface) error {
if cfg.DNS.Type == kubeadmapi.CoreDNS { if cfg.DNS.Type == kubeadmapi.CoreDNS {
return coreDNSAddon(cfg, client) return coreDNSAddon(cfg, client)
} }
return kubeDNSAddon(cfg, client) return kubeDNSAddon(cfg, client)
} }
func kubeDNSAddon(cfg *kubeadmapi.InitConfiguration, client clientset.Interface) error { func kubeDNSAddon(cfg *kubeadmapi.ClusterConfiguration, client clientset.Interface) error {
if err := CreateServiceAccount(client); err != nil { if err := CreateServiceAccount(client); err != nil {
return err return err
} }
@ -103,9 +103,9 @@ func kubeDNSAddon(cfg *kubeadmapi.InitConfiguration, client clientset.Interface)
dnsDeploymentBytes, err := kubeadmutil.ParseTemplate(KubeDNSDeployment, dnsDeploymentBytes, err := kubeadmutil.ParseTemplate(KubeDNSDeployment,
struct{ DeploymentName, KubeDNSImage, DNSMasqImage, SidecarImage, DNSBindAddr, DNSProbeAddr, DNSDomain, MasterTaintKey string }{ struct{ DeploymentName, KubeDNSImage, DNSMasqImage, SidecarImage, DNSBindAddr, DNSProbeAddr, DNSDomain, MasterTaintKey string }{
DeploymentName: kubeadmconstants.KubeDNSDeploymentName, DeploymentName: kubeadmconstants.KubeDNSDeploymentName,
KubeDNSImage: images.GetDNSImage(&cfg.ClusterConfiguration, kubeadmconstants.KubeDNSKubeDNSImageName), KubeDNSImage: images.GetDNSImage(cfg, kubeadmconstants.KubeDNSKubeDNSImageName),
DNSMasqImage: images.GetDNSImage(&cfg.ClusterConfiguration, kubeadmconstants.KubeDNSDnsMasqNannyImageName), DNSMasqImage: images.GetDNSImage(cfg, kubeadmconstants.KubeDNSDnsMasqNannyImageName),
SidecarImage: images.GetDNSImage(&cfg.ClusterConfiguration, kubeadmconstants.KubeDNSSidecarImageName), SidecarImage: images.GetDNSImage(cfg, kubeadmconstants.KubeDNSSidecarImageName),
DNSBindAddr: dnsBindAddr, DNSBindAddr: dnsBindAddr,
DNSProbeAddr: dnsProbeAddr, DNSProbeAddr: dnsProbeAddr,
DNSDomain: cfg.Networking.DNSDomain, DNSDomain: cfg.Networking.DNSDomain,
@ -155,11 +155,11 @@ func createKubeDNSAddon(deploymentBytes, serviceBytes []byte, client clientset.I
return createDNSService(kubednsService, serviceBytes, client) return createDNSService(kubednsService, serviceBytes, client)
} }
func coreDNSAddon(cfg *kubeadmapi.InitConfiguration, client clientset.Interface) error { func coreDNSAddon(cfg *kubeadmapi.ClusterConfiguration, client clientset.Interface) error {
// Get the YAML manifest // Get the YAML manifest
coreDNSDeploymentBytes, err := kubeadmutil.ParseTemplate(CoreDNSDeployment, struct{ DeploymentName, Image, MasterTaintKey string }{ coreDNSDeploymentBytes, err := kubeadmutil.ParseTemplate(CoreDNSDeployment, struct{ DeploymentName, Image, MasterTaintKey string }{
DeploymentName: kubeadmconstants.CoreDNSDeploymentName, DeploymentName: kubeadmconstants.CoreDNSDeploymentName,
Image: images.GetDNSImage(&cfg.ClusterConfiguration, kubeadmconstants.CoreDNSImageName), Image: images.GetDNSImage(cfg, kubeadmconstants.CoreDNSImageName),
MasterTaintKey: kubeadmconstants.LabelNodeRoleMaster, MasterTaintKey: kubeadmconstants.LabelNodeRoleMaster,
}) })
if err != nil { if err != nil {

View File

@ -47,13 +47,13 @@ const (
) )
// EnsureProxyAddon creates the kube-proxy addons // EnsureProxyAddon creates the kube-proxy addons
func EnsureProxyAddon(cfg *kubeadmapi.InitConfiguration, client clientset.Interface) error { func EnsureProxyAddon(cfg *kubeadmapi.ClusterConfiguration, localEndpoint *kubeadmapi.APIEndpoint, client clientset.Interface) error {
if err := CreateServiceAccount(client); err != nil { if err := CreateServiceAccount(client); err != nil {
return errors.Wrap(err, "error when creating kube-proxy service account") return errors.Wrap(err, "error when creating kube-proxy service account")
} }
// Generate Master Enpoint kubeconfig file // Generate Master Enpoint kubeconfig file
masterEndpoint, err := kubeadmutil.GetMasterEndpoint(cfg) masterEndpoint, err := kubeadmutil.GetMasterEndpoint(cfg.ControlPlaneEndpoint, localEndpoint)
if err != nil { if err != nil {
return err return err
} }
@ -81,7 +81,7 @@ func EnsureProxyAddon(cfg *kubeadmapi.InitConfiguration, client clientset.Interf
return errors.Wrap(err, "error when parsing kube-proxy configmap template") return errors.Wrap(err, "error when parsing kube-proxy configmap template")
} }
proxyDaemonSetBytes, err = kubeadmutil.ParseTemplate(KubeProxyDaemonSet19, struct{ Image, ProxyConfigMap, ProxyConfigMapKey string }{ proxyDaemonSetBytes, err = kubeadmutil.ParseTemplate(KubeProxyDaemonSet19, struct{ Image, ProxyConfigMap, ProxyConfigMapKey string }{
Image: images.GetKubernetesImage(constants.KubeProxy, &cfg.ClusterConfiguration), Image: images.GetKubernetesImage(constants.KubeProxy, cfg),
ProxyConfigMap: constants.KubeProxyConfigMap, ProxyConfigMap: constants.KubeProxyConfigMap,
ProxyConfigMapKey: constants.KubeProxyConfigMapKey, ProxyConfigMapKey: constants.KubeProxyConfigMapKey,
}) })

View File

@ -223,7 +223,7 @@ func TestEnsureProxyAddon(t *testing.T) {
t.Errorf("test failed to set dynamic defaults: %v", err) t.Errorf("test failed to set dynamic defaults: %v", err)
break break
} }
err = EnsureProxyAddon(intMaster, client) err = EnsureProxyAddon(&intMaster.ClusterConfiguration, &intMaster.LocalAPIEndpoint, client)
// Compare actual to expected errors // Compare actual to expected errors
actErr := "No error" actErr := "No error"

View File

@ -60,12 +60,12 @@ func CreatePKIAssets(cfg *kubeadmapi.InitConfiguration) error {
fmt.Printf("[certs] 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
return CreateServiceAccountKeyAndPublicKeyFiles(cfg) return CreateServiceAccountKeyAndPublicKeyFiles(cfg.CertificatesDir)
} }
// CreateServiceAccountKeyAndPublicKeyFiles create a new public/private key files for signing service account users. // CreateServiceAccountKeyAndPublicKeyFiles create a new public/private key files for signing service account users.
// If the sa public/private key files already exists in the target folder, they are used only if evaluated equals; otherwise an error is returned. // If the sa public/private key files already exists in the target folder, they are used only if evaluated equals; otherwise an error is returned.
func CreateServiceAccountKeyAndPublicKeyFiles(cfg *kubeadmapi.InitConfiguration) error { func CreateServiceAccountKeyAndPublicKeyFiles(certsDir string) error {
klog.V(1).Infoln("creating a new public/private key files for signing service account users") klog.V(1).Infoln("creating a new public/private key files for signing service account users")
saSigningKey, err := NewServiceAccountSigningKey() saSigningKey, err := NewServiceAccountSigningKey()
if err != nil { if err != nil {
@ -73,7 +73,7 @@ func CreateServiceAccountKeyAndPublicKeyFiles(cfg *kubeadmapi.InitConfiguration)
} }
return writeKeyFilesIfNotExist( return writeKeyFilesIfNotExist(
cfg.CertificatesDir, certsDir,
kubeadmconstants.ServiceAccountKeyBaseName, kubeadmconstants.ServiceAccountKeyBaseName,
saSigningKey, saSigningKey,
) )
@ -329,7 +329,7 @@ type certKeyLocation struct {
// SharedCertificateExists verifies if the shared certificates - the certificates that must be // SharedCertificateExists verifies if the shared certificates - the certificates that must be
// equal across masters: ca.key, ca.crt, sa.key, sa.pub + etcd/ca.key, etcd/ca.crt if local/stacked etcd // equal across masters: ca.key, ca.crt, sa.key, sa.pub + etcd/ca.key, etcd/ca.crt if local/stacked etcd
func SharedCertificateExists(cfg *kubeadmapi.InitConfiguration) (bool, error) { func SharedCertificateExists(cfg *kubeadmapi.ClusterConfiguration) (bool, error) {
if err := validateCACertAndKey(certKeyLocation{cfg.CertificatesDir, kubeadmconstants.CACertAndKeyBaseName, "", "CA"}); err != nil { if err := validateCACertAndKey(certKeyLocation{cfg.CertificatesDir, kubeadmconstants.CACertAndKeyBaseName, "", "CA"}); err != nil {
return false, err return false, err
@ -356,7 +356,7 @@ func SharedCertificateExists(cfg *kubeadmapi.InitConfiguration) (bool, error) {
// UsingExternalCA determines whether the user is relying on an external CA. We currently implicitly determine this is the case // UsingExternalCA determines whether the user is relying on an external CA. We currently implicitly determine this is the case
// when both the CA Cert and the front proxy CA Cert are present but the CA Key and front proxy CA Key are not. // when both the CA Cert and the front proxy CA Cert are present but the CA Key and front proxy CA Key are not.
// This allows us to, e.g., skip generating certs or not start the csr signing controller. // This allows us to, e.g., skip generating certs or not start the csr signing controller.
func UsingExternalCA(cfg *kubeadmapi.InitConfiguration) (bool, error) { func UsingExternalCA(cfg *kubeadmapi.ClusterConfiguration) (bool, error) {
if err := validateCACert(certKeyLocation{cfg.CertificatesDir, kubeadmconstants.CACertAndKeyBaseName, "", "CA"}); err != nil { if err := validateCACert(certKeyLocation{cfg.CertificatesDir, kubeadmconstants.CACertAndKeyBaseName, "", "CA"}); err != nil {
return false, err return false, err

View File

@ -463,10 +463,8 @@ func TestSharedCertificateExists(t *testing.T) {
os.MkdirAll(tmpdir+"/etcd", os.ModePerm) os.MkdirAll(tmpdir+"/etcd", os.ModePerm)
defer os.RemoveAll(tmpdir) defer os.RemoveAll(tmpdir)
cfg := &kubeadmapi.InitConfiguration{ cfg := &kubeadmapi.ClusterConfiguration{
ClusterConfiguration: kubeadmapi.ClusterConfiguration{ CertificatesDir: tmpdir,
CertificatesDir: tmpdir,
},
} }
// created expected keys // created expected keys
@ -554,7 +552,7 @@ func TestUsingExternalCA(t *testing.T) {
} }
} }
if val, _ := UsingExternalCA(cfg); val != test.expected { if val, _ := UsingExternalCA(&cfg.ClusterConfiguration); val != test.expected {
t.Errorf("UsingExternalCA did not match expected: %v", test.expected) t.Errorf("UsingExternalCA did not match expected: %v", test.expected)
} }
} }

View File

@ -41,6 +41,7 @@ go_library(
"//cmd/kubeadm/app/util/staticpod:go_default_library", "//cmd/kubeadm/app/util/staticpod:go_default_library",
"//pkg/kubeapiserver/authorizer/modes:go_default_library", "//pkg/kubeapiserver/authorizer/modes:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/intstr:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/version:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/version:go_default_library",
"//vendor/github.com/pkg/errors:go_default_library", "//vendor/github.com/pkg/errors:go_default_library",

View File

@ -26,6 +26,7 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/apimachinery/pkg/util/version" "k8s.io/apimachinery/pkg/util/version"
"k8s.io/klog" "k8s.io/klog"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
@ -40,12 +41,12 @@ import (
// CreateInitStaticPodManifestFiles will write all static pod manifest files needed to bring up the control plane. // CreateInitStaticPodManifestFiles will write all static pod manifest files needed to bring up the control plane.
func CreateInitStaticPodManifestFiles(manifestDir string, cfg *kubeadmapi.InitConfiguration) error { func CreateInitStaticPodManifestFiles(manifestDir string, cfg *kubeadmapi.InitConfiguration) error {
klog.V(1).Infoln("[control-plane] creating static Pod files") klog.V(1).Infoln("[control-plane] creating static Pod files")
return CreateStaticPodFiles(manifestDir, cfg, kubeadmconstants.KubeAPIServer, kubeadmconstants.KubeControllerManager, kubeadmconstants.KubeScheduler) return CreateStaticPodFiles(manifestDir, &cfg.ClusterConfiguration, &cfg.LocalAPIEndpoint, kubeadmconstants.KubeAPIServer, kubeadmconstants.KubeControllerManager, kubeadmconstants.KubeScheduler)
} }
// GetStaticPodSpecs returns all staticPodSpecs actualized to the context of the current InitConfiguration // GetStaticPodSpecs returns all staticPodSpecs actualized to the context of the current configuration
// NB. this methods holds the information about how kubeadm creates static pod manifests. // NB. this methods holds the information about how kubeadm creates static pod manifests.
func GetStaticPodSpecs(cfg *kubeadmapi.InitConfiguration, k8sVersion *version.Version) map[string]v1.Pod { func GetStaticPodSpecs(cfg *kubeadmapi.ClusterConfiguration, endpoint *kubeadmapi.APIEndpoint, k8sVersion *version.Version) map[string]v1.Pod {
// Get the required hostpath mounts // Get the required hostpath mounts
mounts := getHostPathVolumesForTheControlPlane(cfg) mounts := getHostPathVolumesForTheControlPlane(cfg)
@ -53,31 +54,31 @@ func GetStaticPodSpecs(cfg *kubeadmapi.InitConfiguration, k8sVersion *version.Ve
staticPodSpecs := map[string]v1.Pod{ staticPodSpecs := map[string]v1.Pod{
kubeadmconstants.KubeAPIServer: staticpodutil.ComponentPod(v1.Container{ kubeadmconstants.KubeAPIServer: staticpodutil.ComponentPod(v1.Container{
Name: kubeadmconstants.KubeAPIServer, Name: kubeadmconstants.KubeAPIServer,
Image: images.GetKubernetesImage(kubeadmconstants.KubeAPIServer, &cfg.ClusterConfiguration), Image: images.GetKubernetesImage(kubeadmconstants.KubeAPIServer, cfg),
ImagePullPolicy: v1.PullIfNotPresent, ImagePullPolicy: v1.PullIfNotPresent,
Command: getAPIServerCommand(cfg), Command: getAPIServerCommand(cfg, endpoint),
VolumeMounts: staticpodutil.VolumeMountMapToSlice(mounts.GetVolumeMounts(kubeadmconstants.KubeAPIServer)), VolumeMounts: staticpodutil.VolumeMountMapToSlice(mounts.GetVolumeMounts(kubeadmconstants.KubeAPIServer)),
LivenessProbe: staticpodutil.ComponentProbe(cfg, kubeadmconstants.KubeAPIServer, int(cfg.LocalAPIEndpoint.BindPort), "/healthz", v1.URISchemeHTTPS), LivenessProbe: livenessProbe(staticpodutil.GetAPIServerProbeAddress(endpoint), int(endpoint.BindPort), v1.URISchemeHTTPS),
Resources: staticpodutil.ComponentResources("250m"), Resources: staticpodutil.ComponentResources("250m"),
Env: getProxyEnvVars(), Env: getProxyEnvVars(),
}, mounts.GetVolumes(kubeadmconstants.KubeAPIServer)), }, mounts.GetVolumes(kubeadmconstants.KubeAPIServer)),
kubeadmconstants.KubeControllerManager: staticpodutil.ComponentPod(v1.Container{ kubeadmconstants.KubeControllerManager: staticpodutil.ComponentPod(v1.Container{
Name: kubeadmconstants.KubeControllerManager, Name: kubeadmconstants.KubeControllerManager,
Image: images.GetKubernetesImage(kubeadmconstants.KubeControllerManager, &cfg.ClusterConfiguration), Image: images.GetKubernetesImage(kubeadmconstants.KubeControllerManager, cfg),
ImagePullPolicy: v1.PullIfNotPresent, ImagePullPolicy: v1.PullIfNotPresent,
Command: getControllerManagerCommand(cfg, k8sVersion), Command: getControllerManagerCommand(cfg, k8sVersion),
VolumeMounts: staticpodutil.VolumeMountMapToSlice(mounts.GetVolumeMounts(kubeadmconstants.KubeControllerManager)), VolumeMounts: staticpodutil.VolumeMountMapToSlice(mounts.GetVolumeMounts(kubeadmconstants.KubeControllerManager)),
LivenessProbe: staticpodutil.ComponentProbe(cfg, kubeadmconstants.KubeControllerManager, 10252, "/healthz", v1.URISchemeHTTP), LivenessProbe: livenessProbe(staticpodutil.GetControllerManagerProbeAddress(cfg), 10252, v1.URISchemeHTTP),
Resources: staticpodutil.ComponentResources("200m"), Resources: staticpodutil.ComponentResources("200m"),
Env: getProxyEnvVars(), Env: getProxyEnvVars(),
}, mounts.GetVolumes(kubeadmconstants.KubeControllerManager)), }, mounts.GetVolumes(kubeadmconstants.KubeControllerManager)),
kubeadmconstants.KubeScheduler: staticpodutil.ComponentPod(v1.Container{ kubeadmconstants.KubeScheduler: staticpodutil.ComponentPod(v1.Container{
Name: kubeadmconstants.KubeScheduler, Name: kubeadmconstants.KubeScheduler,
Image: images.GetKubernetesImage(kubeadmconstants.KubeScheduler, &cfg.ClusterConfiguration), Image: images.GetKubernetesImage(kubeadmconstants.KubeScheduler, cfg),
ImagePullPolicy: v1.PullIfNotPresent, ImagePullPolicy: v1.PullIfNotPresent,
Command: getSchedulerCommand(cfg), Command: getSchedulerCommand(cfg),
VolumeMounts: staticpodutil.VolumeMountMapToSlice(mounts.GetVolumeMounts(kubeadmconstants.KubeScheduler)), VolumeMounts: staticpodutil.VolumeMountMapToSlice(mounts.GetVolumeMounts(kubeadmconstants.KubeScheduler)),
LivenessProbe: staticpodutil.ComponentProbe(cfg, kubeadmconstants.KubeScheduler, 10251, "/healthz", v1.URISchemeHTTP), LivenessProbe: livenessProbe(staticpodutil.GetSchedulerProbeAddress(cfg), 10251, v1.URISchemeHTTP),
Resources: staticpodutil.ComponentResources("100m"), Resources: staticpodutil.ComponentResources("100m"),
Env: getProxyEnvVars(), Env: getProxyEnvVars(),
}, mounts.GetVolumes(kubeadmconstants.KubeScheduler)), }, mounts.GetVolumes(kubeadmconstants.KubeScheduler)),
@ -85,17 +86,33 @@ func GetStaticPodSpecs(cfg *kubeadmapi.InitConfiguration, k8sVersion *version.Ve
return staticPodSpecs return staticPodSpecs
} }
func livenessProbe(host string, port int, scheme v1.URIScheme) *v1.Probe {
return &v1.Probe{
Handler: v1.Handler{
HTTPGet: &v1.HTTPGetAction{
Host: host,
Path: "/healthz",
Port: intstr.FromInt(port),
Scheme: scheme,
},
},
InitialDelaySeconds: 15,
TimeoutSeconds: 15,
FailureThreshold: 8,
}
}
// CreateStaticPodFiles creates all the requested static pod files. // CreateStaticPodFiles creates all the requested static pod files.
func CreateStaticPodFiles(manifestDir string, cfg *kubeadmapi.InitConfiguration, componentNames ...string) error { func CreateStaticPodFiles(manifestDir string, cfg *kubeadmapi.ClusterConfiguration, endpoint *kubeadmapi.APIEndpoint, componentNames ...string) error {
// TODO: Move the "pkg/util/version".Version object into the internal API instead of always parsing the string // TODO: Move the "pkg/util/version".Version object into the internal API instead of always parsing the string
k8sVersion, err := version.ParseSemantic(cfg.KubernetesVersion) k8sVersion, err := version.ParseSemantic(cfg.KubernetesVersion)
if err != nil { if err != nil {
return err return err
} }
// gets the StaticPodSpecs, actualized for the current InitConfiguration // gets the StaticPodSpecs, actualized for the current ClusterConfiguration
klog.V(1).Infoln("[control-plane] getting StaticPodSpecs") klog.V(1).Infoln("[control-plane] getting StaticPodSpecs")
specs := GetStaticPodSpecs(cfg, k8sVersion) specs := GetStaticPodSpecs(cfg, endpoint, k8sVersion)
// creates required static pod specs // creates required static pod specs
for _, componentName := range componentNames { for _, componentName := range componentNames {
@ -117,9 +134,9 @@ func CreateStaticPodFiles(manifestDir string, cfg *kubeadmapi.InitConfiguration,
} }
// getAPIServerCommand builds the right API server command from the given config object and version // getAPIServerCommand builds the right API server command from the given config object and version
func getAPIServerCommand(cfg *kubeadmapi.InitConfiguration) []string { func getAPIServerCommand(cfg *kubeadmapi.ClusterConfiguration, localAPIEndpoint *kubeadmapi.APIEndpoint) []string {
defaultArguments := map[string]string{ defaultArguments := map[string]string{
"advertise-address": cfg.LocalAPIEndpoint.AdvertiseAddress, "advertise-address": localAPIEndpoint.AdvertiseAddress,
"enable-admission-plugins": "NodeRestriction", "enable-admission-plugins": "NodeRestriction",
"service-cluster-ip-range": cfg.Networking.ServiceSubnet, "service-cluster-ip-range": cfg.Networking.ServiceSubnet,
"service-account-key-file": filepath.Join(cfg.CertificatesDir, kubeadmconstants.ServiceAccountPublicKeyName), "service-account-key-file": filepath.Join(cfg.CertificatesDir, kubeadmconstants.ServiceAccountPublicKeyName),
@ -129,7 +146,7 @@ func getAPIServerCommand(cfg *kubeadmapi.InitConfiguration) []string {
"kubelet-client-certificate": filepath.Join(cfg.CertificatesDir, kubeadmconstants.APIServerKubeletClientCertName), "kubelet-client-certificate": filepath.Join(cfg.CertificatesDir, kubeadmconstants.APIServerKubeletClientCertName),
"kubelet-client-key": filepath.Join(cfg.CertificatesDir, kubeadmconstants.APIServerKubeletClientKeyName), "kubelet-client-key": filepath.Join(cfg.CertificatesDir, kubeadmconstants.APIServerKubeletClientKeyName),
"enable-bootstrap-token-auth": "true", "enable-bootstrap-token-auth": "true",
"secure-port": fmt.Sprintf("%d", cfg.LocalAPIEndpoint.BindPort), "secure-port": fmt.Sprintf("%d", localAPIEndpoint.BindPort),
"allow-privileged": "true", "allow-privileged": "true",
"kubelet-preferred-address-types": "InternalIP,ExternalIP,Hostname", "kubelet-preferred-address-types": "InternalIP,ExternalIP,Hostname",
// add options to configure the front proxy. Without the generated client cert, this will never be useable // add options to configure the front proxy. Without the generated client cert, this will never be useable
@ -243,7 +260,7 @@ func calcNodeCidrSize(podSubnet string) string {
} }
// getControllerManagerCommand builds the right controller manager command from the given config object and version // getControllerManagerCommand builds the right controller manager command from the given config object and version
func getControllerManagerCommand(cfg *kubeadmapi.InitConfiguration, k8sVersion *version.Version) []string { func getControllerManagerCommand(cfg *kubeadmapi.ClusterConfiguration, k8sVersion *version.Version) []string {
kubeconfigFile := filepath.Join(kubeadmconstants.KubernetesDir, kubeadmconstants.ControllerManagerKubeConfigFileName) kubeconfigFile := filepath.Join(kubeadmconstants.KubernetesDir, kubeadmconstants.ControllerManagerKubeConfigFileName)
caFile := filepath.Join(cfg.CertificatesDir, kubeadmconstants.CACertName) caFile := filepath.Join(cfg.CertificatesDir, kubeadmconstants.CACertName)
@ -287,7 +304,7 @@ func getControllerManagerCommand(cfg *kubeadmapi.InitConfiguration, k8sVersion *
} }
// getSchedulerCommand builds the right scheduler command from the given config object and version // getSchedulerCommand builds the right scheduler command from the given config object and version
func getSchedulerCommand(cfg *kubeadmapi.InitConfiguration) []string { func getSchedulerCommand(cfg *kubeadmapi.ClusterConfiguration) []string {
defaultArguments := map[string]string{ defaultArguments := map[string]string{
"bind-address": "127.0.0.1", "bind-address": "127.0.0.1",
"leader-elect": "true", "leader-elect": "true",

View File

@ -44,11 +44,9 @@ var cpVersion = kubeadmconstants.MinimumControlPlaneVersion.WithPreRelease("beta
func TestGetStaticPodSpecs(t *testing.T) { func TestGetStaticPodSpecs(t *testing.T) {
// Creates a Master Configuration // Creates a Cluster Configuration
cfg := &kubeadmapi.InitConfiguration{ cfg := &kubeadmapi.ClusterConfiguration{
ClusterConfiguration: kubeadmapi.ClusterConfiguration{ KubernetesVersion: "v1.9.0",
KubernetesVersion: "v1.9.0",
},
} }
// Executes GetStaticPodSpecs // Executes GetStaticPodSpecs
@ -56,7 +54,7 @@ func TestGetStaticPodSpecs(t *testing.T) {
// TODO: Move the "pkg/util/version".Version object into the internal API instead of always parsing the string // TODO: Move the "pkg/util/version".Version object into the internal API instead of always parsing the string
k8sVersion, _ := version.ParseSemantic(cfg.KubernetesVersion) k8sVersion, _ := version.ParseSemantic(cfg.KubernetesVersion)
specs := GetStaticPodSpecs(cfg, k8sVersion) specs := GetStaticPodSpecs(cfg, &kubeadmapi.APIEndpoint{}, k8sVersion)
var assertions = []struct { var assertions = []struct {
staticPodName string staticPodName string
@ -113,16 +111,14 @@ func TestCreateStaticPodFilesAndWrappers(t *testing.T) {
tmpdir := testutil.SetupTempDir(t) tmpdir := testutil.SetupTempDir(t)
defer os.RemoveAll(tmpdir) defer os.RemoveAll(tmpdir)
// Creates a Master Configuration // Creates a Cluster Configuration
cfg := &kubeadmapi.InitConfiguration{ cfg := &kubeadmapi.ClusterConfiguration{
ClusterConfiguration: kubeadmapi.ClusterConfiguration{ KubernetesVersion: "v1.9.0",
KubernetesVersion: "v1.9.0",
},
} }
// Execute createStaticPodFunction // Execute createStaticPodFunction
manifestPath := filepath.Join(tmpdir, kubeadmconstants.ManifestsSubDirName) manifestPath := filepath.Join(tmpdir, kubeadmconstants.ManifestsSubDirName)
err := CreateStaticPodFiles(manifestPath, cfg, test.components...) err := CreateStaticPodFiles(manifestPath, cfg, &kubeadmapi.APIEndpoint{}, test.components...)
if err != nil { if err != nil {
t.Errorf("Error executing createStaticPodFunction: %v", err) t.Errorf("Error executing createStaticPodFunction: %v", err)
continue continue
@ -140,18 +136,17 @@ func TestCreateStaticPodFilesAndWrappers(t *testing.T) {
func TestGetAPIServerCommand(t *testing.T) { func TestGetAPIServerCommand(t *testing.T) {
var tests = []struct { var tests = []struct {
name string name string
cfg *kubeadmapi.InitConfiguration cfg *kubeadmapi.ClusterConfiguration
endpoint *kubeadmapi.APIEndpoint
expected []string expected []string
}{ }{
{ {
name: "testing defaults", name: "testing defaults",
cfg: &kubeadmapi.InitConfiguration{ cfg: &kubeadmapi.ClusterConfiguration{
LocalAPIEndpoint: kubeadmapi.APIEndpoint{BindPort: 123, AdvertiseAddress: "1.2.3.4"}, Networking: kubeadmapi.Networking{ServiceSubnet: "bar"},
ClusterConfiguration: kubeadmapi.ClusterConfiguration{ CertificatesDir: testCertsDir,
Networking: kubeadmapi.Networking{ServiceSubnet: "bar"},
CertificatesDir: testCertsDir,
},
}, },
endpoint: &kubeadmapi.APIEndpoint{BindPort: 123, AdvertiseAddress: "1.2.3.4"},
expected: []string{ expected: []string{
"kube-apiserver", "kube-apiserver",
"--enable-admission-plugins=NodeRestriction", "--enable-admission-plugins=NodeRestriction",
@ -183,13 +178,11 @@ func TestGetAPIServerCommand(t *testing.T) {
}, },
{ {
name: "ipv6 advertise address", name: "ipv6 advertise address",
cfg: &kubeadmapi.InitConfiguration{ cfg: &kubeadmapi.ClusterConfiguration{
LocalAPIEndpoint: kubeadmapi.APIEndpoint{BindPort: 123, AdvertiseAddress: "2001:db8::1"}, Networking: kubeadmapi.Networking{ServiceSubnet: "bar"},
ClusterConfiguration: kubeadmapi.ClusterConfiguration{ CertificatesDir: testCertsDir,
Networking: kubeadmapi.Networking{ServiceSubnet: "bar"},
CertificatesDir: testCertsDir,
},
}, },
endpoint: &kubeadmapi.APIEndpoint{BindPort: 123, AdvertiseAddress: "2001:db8::1"},
expected: []string{ expected: []string{
"kube-apiserver", "kube-apiserver",
"--enable-admission-plugins=NodeRestriction", "--enable-admission-plugins=NodeRestriction",
@ -221,21 +214,19 @@ func TestGetAPIServerCommand(t *testing.T) {
}, },
{ {
name: "an external etcd with custom ca, certs and keys", name: "an external etcd with custom ca, certs and keys",
cfg: &kubeadmapi.InitConfiguration{ cfg: &kubeadmapi.ClusterConfiguration{
LocalAPIEndpoint: kubeadmapi.APIEndpoint{BindPort: 123, AdvertiseAddress: "2001:db8::1"}, Networking: kubeadmapi.Networking{ServiceSubnet: "bar"},
ClusterConfiguration: kubeadmapi.ClusterConfiguration{ Etcd: kubeadmapi.Etcd{
Networking: kubeadmapi.Networking{ServiceSubnet: "bar"}, External: &kubeadmapi.ExternalEtcd{
Etcd: kubeadmapi.Etcd{ Endpoints: []string{"https://8.6.4.1:2379", "https://8.6.4.2:2379"},
External: &kubeadmapi.ExternalEtcd{ CAFile: "fuz",
Endpoints: []string{"https://8.6.4.1:2379", "https://8.6.4.2:2379"}, CertFile: "fiz",
CAFile: "fuz", KeyFile: "faz",
CertFile: "fiz",
KeyFile: "faz",
},
}, },
CertificatesDir: testCertsDir,
}, },
CertificatesDir: testCertsDir,
}, },
endpoint: &kubeadmapi.APIEndpoint{BindPort: 123, AdvertiseAddress: "2001:db8::1"},
expected: []string{ expected: []string{
"kube-apiserver", "kube-apiserver",
"--enable-admission-plugins=NodeRestriction", "--enable-admission-plugins=NodeRestriction",
@ -267,18 +258,16 @@ func TestGetAPIServerCommand(t *testing.T) {
}, },
{ {
name: "an insecure etcd", name: "an insecure etcd",
cfg: &kubeadmapi.InitConfiguration{ cfg: &kubeadmapi.ClusterConfiguration{
LocalAPIEndpoint: kubeadmapi.APIEndpoint{BindPort: 123, AdvertiseAddress: "2001:db8::1"}, Networking: kubeadmapi.Networking{ServiceSubnet: "bar"},
ClusterConfiguration: kubeadmapi.ClusterConfiguration{ Etcd: kubeadmapi.Etcd{
Networking: kubeadmapi.Networking{ServiceSubnet: "bar"}, External: &kubeadmapi.ExternalEtcd{
Etcd: kubeadmapi.Etcd{ Endpoints: []string{"http://127.0.0.1:2379", "http://127.0.0.1:2380"},
External: &kubeadmapi.ExternalEtcd{
Endpoints: []string{"http://127.0.0.1:2379", "http://127.0.0.1:2380"},
},
}, },
CertificatesDir: testCertsDir,
}, },
CertificatesDir: testCertsDir,
}, },
endpoint: &kubeadmapi.APIEndpoint{BindPort: 123, AdvertiseAddress: "2001:db8::1"},
expected: []string{ expected: []string{
"kube-apiserver", "kube-apiserver",
"--enable-admission-plugins=NodeRestriction", "--enable-admission-plugins=NodeRestriction",
@ -307,23 +296,21 @@ func TestGetAPIServerCommand(t *testing.T) {
}, },
{ {
name: "test APIServer.ExtraArgs works as expected", name: "test APIServer.ExtraArgs works as expected",
cfg: &kubeadmapi.InitConfiguration{ cfg: &kubeadmapi.ClusterConfiguration{
LocalAPIEndpoint: kubeadmapi.APIEndpoint{BindPort: 123, AdvertiseAddress: "1.2.3.4"}, Networking: kubeadmapi.Networking{ServiceSubnet: "bar"},
ClusterConfiguration: kubeadmapi.ClusterConfiguration{ CertificatesDir: testCertsDir,
Networking: kubeadmapi.Networking{ServiceSubnet: "bar"}, APIServer: kubeadmapi.APIServer{
CertificatesDir: testCertsDir, ControlPlaneComponent: kubeadmapi.ControlPlaneComponent{
APIServer: kubeadmapi.APIServer{ ExtraArgs: map[string]string{
ControlPlaneComponent: kubeadmapi.ControlPlaneComponent{ "service-cluster-ip-range": "baz",
ExtraArgs: map[string]string{ "advertise-address": "9.9.9.9",
"service-cluster-ip-range": "baz", "audit-policy-file": "/etc/config/audit.yaml",
"advertise-address": "9.9.9.9", "audit-log-path": "/var/log/kubernetes",
"audit-policy-file": "/etc/config/audit.yaml",
"audit-log-path": "/var/log/kubernetes",
},
}, },
}, },
}, },
}, },
endpoint: &kubeadmapi.APIEndpoint{BindPort: 123, AdvertiseAddress: "1.2.3.4"},
expected: []string{ expected: []string{
"kube-apiserver", "kube-apiserver",
"--enable-admission-plugins=NodeRestriction", "--enable-admission-plugins=NodeRestriction",
@ -357,20 +344,18 @@ func TestGetAPIServerCommand(t *testing.T) {
}, },
{ {
name: "authorization-mode extra-args ABAC", name: "authorization-mode extra-args ABAC",
cfg: &kubeadmapi.InitConfiguration{ cfg: &kubeadmapi.ClusterConfiguration{
LocalAPIEndpoint: kubeadmapi.APIEndpoint{BindPort: 123, AdvertiseAddress: "1.2.3.4"}, Networking: kubeadmapi.Networking{ServiceSubnet: "bar"},
ClusterConfiguration: kubeadmapi.ClusterConfiguration{ CertificatesDir: testCertsDir,
Networking: kubeadmapi.Networking{ServiceSubnet: "bar"}, APIServer: kubeadmapi.APIServer{
CertificatesDir: testCertsDir, ControlPlaneComponent: kubeadmapi.ControlPlaneComponent{
APIServer: kubeadmapi.APIServer{ ExtraArgs: map[string]string{
ControlPlaneComponent: kubeadmapi.ControlPlaneComponent{ "authorization-mode": authzmodes.ModeABAC,
ExtraArgs: map[string]string{
"authorization-mode": authzmodes.ModeABAC,
},
}, },
}, },
}, },
}, },
endpoint: &kubeadmapi.APIEndpoint{BindPort: 123, AdvertiseAddress: "1.2.3.4"},
expected: []string{ expected: []string{
"kube-apiserver", "kube-apiserver",
"--enable-admission-plugins=NodeRestriction", "--enable-admission-plugins=NodeRestriction",
@ -402,20 +387,18 @@ func TestGetAPIServerCommand(t *testing.T) {
}, },
{ {
name: "secure-port extra-args", name: "secure-port extra-args",
cfg: &kubeadmapi.InitConfiguration{ cfg: &kubeadmapi.ClusterConfiguration{
LocalAPIEndpoint: kubeadmapi.APIEndpoint{BindPort: 123, AdvertiseAddress: "1.2.3.4"}, Networking: kubeadmapi.Networking{ServiceSubnet: "bar"},
ClusterConfiguration: kubeadmapi.ClusterConfiguration{ CertificatesDir: testCertsDir,
Networking: kubeadmapi.Networking{ServiceSubnet: "bar"}, APIServer: kubeadmapi.APIServer{
CertificatesDir: testCertsDir, ControlPlaneComponent: kubeadmapi.ControlPlaneComponent{
APIServer: kubeadmapi.APIServer{ ExtraArgs: map[string]string{
ControlPlaneComponent: kubeadmapi.ControlPlaneComponent{ "secure-port": "123",
ExtraArgs: map[string]string{
"secure-port": "123",
},
}, },
}, },
}, },
}, },
endpoint: &kubeadmapi.APIEndpoint{BindPort: 123, AdvertiseAddress: "1.2.3.4"},
expected: []string{ expected: []string{
"kube-apiserver", "kube-apiserver",
"--enable-admission-plugins=NodeRestriction", "--enable-admission-plugins=NodeRestriction",
@ -447,20 +430,18 @@ func TestGetAPIServerCommand(t *testing.T) {
}, },
{ {
name: "authorization-mode extra-args Webhook", name: "authorization-mode extra-args Webhook",
cfg: &kubeadmapi.InitConfiguration{ cfg: &kubeadmapi.ClusterConfiguration{
LocalAPIEndpoint: kubeadmapi.APIEndpoint{BindPort: 123, AdvertiseAddress: "1.2.3.4"}, Networking: kubeadmapi.Networking{ServiceSubnet: "bar"},
ClusterConfiguration: kubeadmapi.ClusterConfiguration{ CertificatesDir: testCertsDir,
Networking: kubeadmapi.Networking{ServiceSubnet: "bar"}, APIServer: kubeadmapi.APIServer{
CertificatesDir: testCertsDir, ControlPlaneComponent: kubeadmapi.ControlPlaneComponent{
APIServer: kubeadmapi.APIServer{ ExtraArgs: map[string]string{
ControlPlaneComponent: kubeadmapi.ControlPlaneComponent{ "authorization-mode": authzmodes.ModeWebhook,
ExtraArgs: map[string]string{
"authorization-mode": authzmodes.ModeWebhook,
},
}, },
}, },
}, },
}, },
endpoint: &kubeadmapi.APIEndpoint{BindPort: 123, AdvertiseAddress: "1.2.3.4"},
expected: []string{ expected: []string{
"kube-apiserver", "kube-apiserver",
"--enable-admission-plugins=NodeRestriction", "--enable-admission-plugins=NodeRestriction",
@ -494,7 +475,7 @@ func TestGetAPIServerCommand(t *testing.T) {
for _, rt := range tests { for _, rt := range tests {
t.Run(rt.name, func(t *testing.T) { t.Run(rt.name, func(t *testing.T) {
actual := getAPIServerCommand(rt.cfg) actual := getAPIServerCommand(rt.cfg, rt.endpoint)
sort.Strings(actual) sort.Strings(actual)
sort.Strings(rt.expected) sort.Strings(rt.expected)
if !reflect.DeepEqual(actual, rt.expected) { if !reflect.DeepEqual(actual, rt.expected) {
@ -638,11 +619,7 @@ func TestGetControllerManagerCommand(t *testing.T) {
} }
for _, rt := range tests { for _, rt := range tests {
// TODO: Make getControllerManagerCommand accept a ClusterConfiguration object instead of InitConfiguration actual := getControllerManagerCommand(rt.cfg, version.MustParseSemantic(rt.cfg.KubernetesVersion))
initcfg := &kubeadmapi.InitConfiguration{
ClusterConfiguration: *rt.cfg,
}
actual := getControllerManagerCommand(initcfg, version.MustParseSemantic(rt.cfg.KubernetesVersion))
sort.Strings(actual) sort.Strings(actual)
sort.Strings(rt.expected) sort.Strings(rt.expected)
if !reflect.DeepEqual(actual, rt.expected) { if !reflect.DeepEqual(actual, rt.expected) {
@ -815,7 +792,7 @@ func TestGetControllerManagerCommandExternalCA(t *testing.T) {
} }
} }
actual := getControllerManagerCommand(test.cfg, version.MustParseSemantic(test.cfg.KubernetesVersion)) actual := getControllerManagerCommand(&test.cfg.ClusterConfiguration, version.MustParseSemantic(test.cfg.KubernetesVersion))
expected := test.expectedArgFunc(tmpdir) expected := test.expectedArgFunc(tmpdir)
sort.Strings(actual) sort.Strings(actual)
sort.Strings(expected) sort.Strings(expected)
@ -844,11 +821,7 @@ func TestGetSchedulerCommand(t *testing.T) {
} }
for _, rt := range tests { for _, rt := range tests {
// TODO: Make getSchedulerCommand accept a ClusterConfiguration object instead of InitConfiguration actual := getSchedulerCommand(rt.cfg)
initcfg := &kubeadmapi.InitConfiguration{
ClusterConfiguration: *rt.cfg,
}
actual := getSchedulerCommand(initcfg)
sort.Strings(actual) sort.Strings(actual)
sort.Strings(rt.expected) sort.Strings(rt.expected)
if !reflect.DeepEqual(actual, rt.expected) { if !reflect.DeepEqual(actual, rt.expected) {

View File

@ -42,7 +42,7 @@ const (
var caCertsExtraVolumePaths = []string{"/etc/pki", "/usr/share/ca-certificates", "/usr/local/share/ca-certificates", "/etc/ca-certificates"} var caCertsExtraVolumePaths = []string{"/etc/pki", "/usr/share/ca-certificates", "/usr/local/share/ca-certificates", "/etc/ca-certificates"}
// getHostPathVolumesForTheControlPlane gets the required hostPath volumes and mounts for the control plane // getHostPathVolumesForTheControlPlane gets the required hostPath volumes and mounts for the control plane
func getHostPathVolumesForTheControlPlane(cfg *kubeadmapi.InitConfiguration) controlPlaneHostPathMounts { func getHostPathVolumesForTheControlPlane(cfg *kubeadmapi.ClusterConfiguration) controlPlaneHostPathMounts {
hostPathDirectoryOrCreate := v1.HostPathDirectoryOrCreate hostPathDirectoryOrCreate := v1.HostPathDirectoryOrCreate
hostPathFileOrCreate := v1.HostPathFileOrCreate hostPathFileOrCreate := v1.HostPathFileOrCreate
mounts := newControlPlaneHostPathMounts() mounts := newControlPlaneHostPathMounts()

View File

@ -514,11 +514,7 @@ func TestGetHostPathVolumesForTheControlPlane(t *testing.T) {
defer func() { caCertsExtraVolumePaths = []string{"/etc/pki", "/usr/share/ca-certificates"} }() defer func() { caCertsExtraVolumePaths = []string{"/etc/pki", "/usr/share/ca-certificates"} }()
for _, rt := range tests { for _, rt := range tests {
// TODO: Make getHostPathVolumesForTheControlPlane accept a ClusterConfiguration object instead of InitConfiguration mounts := getHostPathVolumesForTheControlPlane(rt.cfg)
initcfg := &kubeadmapi.InitConfiguration{
ClusterConfiguration: *rt.cfg,
}
mounts := getHostPathVolumesForTheControlPlane(initcfg)
// Avoid unit test errors when the flexvolume is mounted // Avoid unit test errors when the flexvolume is mounted
if _, ok := mounts.volumes[kubeadmconstants.KubeControllerManager][flexvolumeDirVolumeName]; ok { if _, ok := mounts.volumes[kubeadmconstants.KubeControllerManager][flexvolumeDirVolumeName]; ok {

View File

@ -46,8 +46,8 @@ const (
// CreateLocalEtcdStaticPodManifestFile will write local etcd static pod manifest file. // CreateLocalEtcdStaticPodManifestFile will write local etcd static pod manifest file.
// This function is used by init - when the etcd cluster is empty - or by kubeadm // This function is used by init - when the etcd cluster is empty - or by kubeadm
// upgrade - when the etcd cluster is already up and running (and the --initial-cluster flag have no impact) // upgrade - when the etcd cluster is already up and running (and the --initial-cluster flag have no impact)
func CreateLocalEtcdStaticPodManifestFile(manifestDir string, cfg *kubeadmapi.InitConfiguration) error { func CreateLocalEtcdStaticPodManifestFile(manifestDir string, nodeName string, cfg *kubeadmapi.ClusterConfiguration, endpoint *kubeadmapi.APIEndpoint) error {
if cfg.ClusterConfiguration.Etcd.External != nil { if cfg.Etcd.External != nil {
return errors.New("etcd static pod manifest cannot be generated for cluster using external etcd") return errors.New("etcd static pod manifest cannot be generated for cluster using external etcd")
} }
// gets etcd StaticPodSpec // gets etcd StaticPodSpec
@ -58,7 +58,7 @@ func CreateLocalEtcdStaticPodManifestFile(manifestDir string, cfg *kubeadmapi.In
return errors.Wrapf(err, "failed to create etcd directory %q", cfg.Etcd.Local.DataDir) return errors.Wrapf(err, "failed to create etcd directory %q", cfg.Etcd.Local.DataDir)
} }
spec := GetEtcdPodSpec(cfg, emptyInitialCluster) spec := GetEtcdPodSpec(cfg, endpoint, nodeName, emptyInitialCluster)
// writes etcd StaticPod to disk // writes etcd StaticPod to disk
if err := staticpodutil.WriteStaticPodToDisk(kubeadmconstants.Etcd, manifestDir, spec); err != nil { if err := staticpodutil.WriteStaticPodToDisk(kubeadmconstants.Etcd, manifestDir, spec); err != nil {
return err return err
@ -69,7 +69,7 @@ func CreateLocalEtcdStaticPodManifestFile(manifestDir string, cfg *kubeadmapi.In
} }
// CheckLocalEtcdClusterStatus verifies health state of local/stacked etcd cluster before installing a new etcd member // CheckLocalEtcdClusterStatus verifies health state of local/stacked etcd cluster before installing a new etcd member
func CheckLocalEtcdClusterStatus(client clientset.Interface, cfg *kubeadmapi.InitConfiguration) error { func CheckLocalEtcdClusterStatus(client clientset.Interface, cfg *kubeadmapi.ClusterConfiguration) error {
fmt.Println("[etcd] Checking etcd cluster health") fmt.Println("[etcd] Checking etcd cluster health")
// creates an etcd client that connects to all the local/stacked etcd members // creates an etcd client that connects to all the local/stacked etcd members
@ -91,7 +91,7 @@ func CheckLocalEtcdClusterStatus(client clientset.Interface, cfg *kubeadmapi.Ini
// CreateStackedEtcdStaticPodManifestFile will write local etcd static pod manifest file // CreateStackedEtcdStaticPodManifestFile will write local etcd static pod manifest file
// for an additional etcd member that is joining an existing local/stacked etcd cluster. // for an additional etcd member that is joining an existing local/stacked etcd cluster.
// Other members of the etcd cluster will be notified of the joining node in beforehand as well. // Other members of the etcd cluster will be notified of the joining node in beforehand as well.
func CreateStackedEtcdStaticPodManifestFile(client clientset.Interface, manifestDir string, cfg *kubeadmapi.InitConfiguration) error { func CreateStackedEtcdStaticPodManifestFile(client clientset.Interface, manifestDir string, nodeName string, cfg *kubeadmapi.ClusterConfiguration, endpoint *kubeadmapi.APIEndpoint) error {
// creates an etcd client that connects to all the local/stacked etcd members // creates an etcd client that connects to all the local/stacked etcd members
klog.V(1).Info("creating etcd client that connects to etcd pods") klog.V(1).Info("creating etcd client that connects to etcd pods")
etcdClient, err := etcdutil.NewFromCluster(client, cfg.CertificatesDir) etcdClient, err := etcdutil.NewFromCluster(client, cfg.CertificatesDir)
@ -100,10 +100,10 @@ func CreateStackedEtcdStaticPodManifestFile(client clientset.Interface, manifest
} }
// notifies the other members of the etcd cluster about the joining member // notifies the other members of the etcd cluster about the joining member
etcdPeerAddress := etcdutil.GetPeerURL(cfg) etcdPeerAddress := etcdutil.GetPeerURL(endpoint)
klog.V(1).Infof("Adding etcd member: %s", etcdPeerAddress) klog.V(1).Infof("Adding etcd member: %s", etcdPeerAddress)
initialCluster, err := etcdClient.AddMember(cfg.NodeRegistration.Name, etcdPeerAddress) initialCluster, err := etcdClient.AddMember(nodeName, etcdPeerAddress)
if err != nil { if err != nil {
return err return err
} }
@ -117,7 +117,7 @@ func CreateStackedEtcdStaticPodManifestFile(client clientset.Interface, manifest
klog.V(1).Info("Creating local etcd static pod manifest file") klog.V(1).Info("Creating local etcd static pod manifest file")
// gets etcd StaticPodSpec, actualized for the current InitConfiguration and the new list of etcd members // gets etcd StaticPodSpec, actualized for the current InitConfiguration and the new list of etcd members
spec := GetEtcdPodSpec(cfg, initialCluster) spec := GetEtcdPodSpec(cfg, endpoint, nodeName, initialCluster)
// writes etcd StaticPod to disk // writes etcd StaticPod to disk
if err := staticpodutil.WriteStaticPodToDisk(kubeadmconstants.Etcd, manifestDir, spec); err != nil { if err := staticpodutil.WriteStaticPodToDisk(kubeadmconstants.Etcd, manifestDir, spec); err != nil {
return err return err
@ -133,9 +133,9 @@ func CreateStackedEtcdStaticPodManifestFile(client clientset.Interface, manifest
return nil return nil
} }
// GetEtcdPodSpec returns the etcd static Pod actualized to the context of the current InitConfiguration // GetEtcdPodSpec returns the etcd static Pod actualized to the context of the current configuration
// NB. GetEtcdPodSpec methods holds the information about how kubeadm creates etcd static pod manifests. // NB. GetEtcdPodSpec methods holds the information about how kubeadm creates etcd static pod manifests.
func GetEtcdPodSpec(cfg *kubeadmapi.InitConfiguration, initialCluster []etcdutil.Member) v1.Pod { func GetEtcdPodSpec(cfg *kubeadmapi.ClusterConfiguration, endpoint *kubeadmapi.APIEndpoint, nodeName string, initialCluster []etcdutil.Member) v1.Pod {
pathType := v1.HostPathDirectoryOrCreate pathType := v1.HostPathDirectoryOrCreate
etcdMounts := map[string]v1.Volume{ etcdMounts := map[string]v1.Volume{
etcdVolumeName: staticpodutil.NewVolume(etcdVolumeName, cfg.Etcd.Local.DataDir, &pathType), etcdVolumeName: staticpodutil.NewVolume(etcdVolumeName, cfg.Etcd.Local.DataDir, &pathType),
@ -143,8 +143,8 @@ func GetEtcdPodSpec(cfg *kubeadmapi.InitConfiguration, initialCluster []etcdutil
} }
return staticpodutil.ComponentPod(v1.Container{ return staticpodutil.ComponentPod(v1.Container{
Name: kubeadmconstants.Etcd, Name: kubeadmconstants.Etcd,
Command: getEtcdCommand(cfg, initialCluster), Command: getEtcdCommand(cfg, endpoint, nodeName, initialCluster),
Image: images.GetEtcdImage(&cfg.ClusterConfiguration), Image: images.GetEtcdImage(cfg),
ImagePullPolicy: v1.PullIfNotPresent, ImagePullPolicy: v1.PullIfNotPresent,
// Mount the etcd datadir path read-write so etcd can store data in a more persistent manner // Mount the etcd datadir path read-write so etcd can store data in a more persistent manner
VolumeMounts: []v1.VolumeMount{ VolumeMounts: []v1.VolumeMount{
@ -152,20 +152,20 @@ func GetEtcdPodSpec(cfg *kubeadmapi.InitConfiguration, initialCluster []etcdutil
staticpodutil.NewVolumeMount(certsVolumeName, cfg.CertificatesDir+"/etcd", false), staticpodutil.NewVolumeMount(certsVolumeName, cfg.CertificatesDir+"/etcd", false),
}, },
LivenessProbe: staticpodutil.EtcdProbe( LivenessProbe: staticpodutil.EtcdProbe(
cfg, kubeadmconstants.Etcd, kubeadmconstants.EtcdListenClientPort, cfg.CertificatesDir, &cfg.Etcd, kubeadmconstants.EtcdListenClientPort, cfg.CertificatesDir,
kubeadmconstants.EtcdCACertName, kubeadmconstants.EtcdHealthcheckClientCertName, kubeadmconstants.EtcdHealthcheckClientKeyName, kubeadmconstants.EtcdCACertName, kubeadmconstants.EtcdHealthcheckClientCertName, kubeadmconstants.EtcdHealthcheckClientKeyName,
), ),
}, etcdMounts) }, etcdMounts)
} }
// getEtcdCommand builds the right etcd command from the given config object // getEtcdCommand builds the right etcd command from the given config object
func getEtcdCommand(cfg *kubeadmapi.InitConfiguration, initialCluster []etcdutil.Member) []string { func getEtcdCommand(cfg *kubeadmapi.ClusterConfiguration, endpoint *kubeadmapi.APIEndpoint, nodeName string, initialCluster []etcdutil.Member) []string {
defaultArguments := map[string]string{ defaultArguments := map[string]string{
"name": cfg.GetNodeName(), "name": nodeName,
"listen-client-urls": fmt.Sprintf("%s,%s", etcdutil.GetClientURLByIP("127.0.0.1"), etcdutil.GetClientURL(cfg)), "listen-client-urls": fmt.Sprintf("%s,%s", etcdutil.GetClientURLByIP("127.0.0.1"), etcdutil.GetClientURL(endpoint)),
"advertise-client-urls": etcdutil.GetClientURL(cfg), "advertise-client-urls": etcdutil.GetClientURL(endpoint),
"listen-peer-urls": etcdutil.GetPeerURL(cfg), "listen-peer-urls": etcdutil.GetPeerURL(endpoint),
"initial-advertise-peer-urls": etcdutil.GetPeerURL(cfg), "initial-advertise-peer-urls": etcdutil.GetPeerURL(endpoint),
"data-dir": cfg.Etcd.Local.DataDir, "data-dir": cfg.Etcd.Local.DataDir,
"cert-file": filepath.Join(cfg.CertificatesDir, kubeadmconstants.EtcdServerCertName), "cert-file": filepath.Join(cfg.CertificatesDir, kubeadmconstants.EtcdServerCertName),
"key-file": filepath.Join(cfg.CertificatesDir, kubeadmconstants.EtcdServerKeyName), "key-file": filepath.Join(cfg.CertificatesDir, kubeadmconstants.EtcdServerKeyName),
@ -179,7 +179,7 @@ func getEtcdCommand(cfg *kubeadmapi.InitConfiguration, initialCluster []etcdutil
} }
if len(initialCluster) == 0 { if len(initialCluster) == 0 {
defaultArguments["initial-cluster"] = fmt.Sprintf("%s=%s", cfg.GetNodeName(), etcdutil.GetPeerURL(cfg)) defaultArguments["initial-cluster"] = fmt.Sprintf("%s=%s", nodeName, etcdutil.GetPeerURL(endpoint))
} else { } else {
// NB. the joining etcd member should be part of the initialCluster list // NB. the joining etcd member should be part of the initialCluster list
endpoints := []string{} endpoints := []string{}

View File

@ -32,19 +32,18 @@ import (
func TestGetEtcdPodSpec(t *testing.T) { func TestGetEtcdPodSpec(t *testing.T) {
// Creates a Master Configuration // Creates a Master Configuration
cfg := &kubeadmapi.InitConfiguration{ cfg := &kubeadmapi.ClusterConfiguration{
ClusterConfiguration: kubeadmapi.ClusterConfiguration{ KubernetesVersion: "v1.7.0",
KubernetesVersion: "v1.7.0", Etcd: kubeadmapi.Etcd{
Etcd: kubeadmapi.Etcd{ Local: &kubeadmapi.LocalEtcd{
Local: &kubeadmapi.LocalEtcd{ DataDir: "/var/lib/etcd",
DataDir: "/var/lib/etcd",
},
}, },
}, },
} }
endpoint := &kubeadmapi.APIEndpoint{}
// Executes GetEtcdPodSpec // Executes GetEtcdPodSpec
spec := GetEtcdPodSpec(cfg, []etcdutil.Member{}) spec := GetEtcdPodSpec(cfg, endpoint, "", []etcdutil.Member{})
// Assert each specs refers to the right pod // Assert each specs refers to the right pod
if spec.Spec.Containers[0].Name != kubeadmconstants.Etcd { if spec.Spec.Containers[0].Name != kubeadmconstants.Etcd {
@ -58,35 +57,31 @@ func TestCreateLocalEtcdStaticPodManifestFile(t *testing.T) {
defer os.RemoveAll(tmpdir) defer os.RemoveAll(tmpdir)
var tests = []struct { var tests = []struct {
cfg *kubeadmapi.InitConfiguration cfg *kubeadmapi.ClusterConfiguration
expectedError bool expectedError bool
}{ }{
{ {
cfg: &kubeadmapi.InitConfiguration{ cfg: &kubeadmapi.ClusterConfiguration{
ClusterConfiguration: kubeadmapi.ClusterConfiguration{ KubernetesVersion: "v1.7.0",
KubernetesVersion: "v1.7.0", Etcd: kubeadmapi.Etcd{
Etcd: kubeadmapi.Etcd{ Local: &kubeadmapi.LocalEtcd{
Local: &kubeadmapi.LocalEtcd{ DataDir: tmpdir + "/etcd",
DataDir: tmpdir + "/etcd",
},
}, },
}, },
}, },
expectedError: false, expectedError: false,
}, },
{ {
cfg: &kubeadmapi.InitConfiguration{ cfg: &kubeadmapi.ClusterConfiguration{
ClusterConfiguration: kubeadmapi.ClusterConfiguration{ KubernetesVersion: "v1.7.0",
KubernetesVersion: "v1.7.0", Etcd: kubeadmapi.Etcd{
Etcd: kubeadmapi.Etcd{ External: &kubeadmapi.ExternalEtcd{
External: &kubeadmapi.ExternalEtcd{ Endpoints: []string{
Endpoints: []string{ "https://etcd-instance:2379",
"https://etcd-instance:2379",
},
CAFile: "/etc/kubernetes/pki/etcd/ca.crt",
CertFile: "/etc/kubernetes/pki/etcd/apiserver-etcd-client.crt",
KeyFile: "/etc/kubernetes/pki/etcd/apiserver-etcd-client.key",
}, },
CAFile: "/etc/kubernetes/pki/etcd/ca.crt",
CertFile: "/etc/kubernetes/pki/etcd/apiserver-etcd-client.crt",
KeyFile: "/etc/kubernetes/pki/etcd/apiserver-etcd-client.key",
}, },
}, },
}, },
@ -97,7 +92,7 @@ func TestCreateLocalEtcdStaticPodManifestFile(t *testing.T) {
for _, test := range tests { for _, test := range tests {
// Execute createStaticPodFunction // Execute createStaticPodFunction
manifestPath := filepath.Join(tmpdir, kubeadmconstants.ManifestsSubDirName) manifestPath := filepath.Join(tmpdir, kubeadmconstants.ManifestsSubDirName)
err := CreateLocalEtcdStaticPodManifestFile(manifestPath, test.cfg) err := CreateLocalEtcdStaticPodManifestFile(manifestPath, "", test.cfg, &kubeadmapi.APIEndpoint{})
if !test.expectedError { if !test.expectedError {
if err != nil { if err != nil {
@ -230,23 +225,18 @@ func TestGetEtcdCommand(t *testing.T) {
for _, rt := range tests { for _, rt := range tests {
t.Run(rt.name, func(t *testing.T) { t.Run(rt.name, func(t *testing.T) {
cfg := &kubeadmapi.InitConfiguration{ endpoint := &kubeadmapi.APIEndpoint{
LocalAPIEndpoint: kubeadmapi.APIEndpoint{ AdvertiseAddress: rt.advertiseAddress,
AdvertiseAddress: rt.advertiseAddress, }
}, cfg := &kubeadmapi.ClusterConfiguration{
NodeRegistration: kubeadmapi.NodeRegistrationOptions{ Etcd: kubeadmapi.Etcd{
Name: rt.nodeName, Local: &kubeadmapi.LocalEtcd{
}, DataDir: "/var/lib/etcd",
ClusterConfiguration: kubeadmapi.ClusterConfiguration{ ExtraArgs: rt.extraArgs,
Etcd: kubeadmapi.Etcd{
Local: &kubeadmapi.LocalEtcd{
DataDir: "/var/lib/etcd",
ExtraArgs: rt.extraArgs,
},
}, },
}, },
} }
actual := getEtcdCommand(cfg, rt.initialCluster) actual := getEtcdCommand(cfg, endpoint, rt.nodeName, rt.initialCluster)
sort.Strings(actual) sort.Strings(actual)
sort.Strings(rt.expected) sort.Strings(rt.expected)
if !reflect.DeepEqual(actual, rt.expected) { if !reflect.DeepEqual(actual, rt.expected) {

View File

@ -135,7 +135,7 @@ func getKubeConfigSpecs(cfg *kubeadmapi.InitConfiguration) (map[string]*kubeConf
return nil, errors.Wrap(err, "couldn't create a kubeconfig; the CA files couldn't be loaded") return nil, errors.Wrap(err, "couldn't create a kubeconfig; the CA files couldn't be loaded")
} }
masterEndpoint, err := kubeadmutil.GetMasterEndpoint(cfg) masterEndpoint, err := kubeadmutil.GetMasterEndpoint(cfg.ControlPlaneEndpoint, &cfg.LocalAPIEndpoint)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -285,7 +285,7 @@ func WriteKubeConfigWithClientCert(out io.Writer, cfg *kubeadmapi.InitConfigurat
return errors.Wrap(err, "couldn't create a kubeconfig; the CA files couldn't be loaded") return errors.Wrap(err, "couldn't create a kubeconfig; the CA files couldn't be loaded")
} }
masterEndpoint, err := kubeadmutil.GetMasterEndpoint(cfg) masterEndpoint, err := kubeadmutil.GetMasterEndpoint(cfg.ControlPlaneEndpoint, &cfg.LocalAPIEndpoint)
if err != nil { if err != nil {
return err return err
} }
@ -312,7 +312,7 @@ func WriteKubeConfigWithToken(out io.Writer, cfg *kubeadmapi.InitConfiguration,
return errors.Wrap(err, "couldn't create a kubeconfig; the CA files couldn't be loaded") return errors.Wrap(err, "couldn't create a kubeconfig; the CA files couldn't be loaded")
} }
masterEndpoint, err := kubeadmutil.GetMasterEndpoint(cfg) masterEndpoint, err := kubeadmutil.GetMasterEndpoint(cfg.ControlPlaneEndpoint, &cfg.LocalAPIEndpoint)
if err != nil { if err != nil {
return err return err
} }

View File

@ -162,7 +162,7 @@ func TestGetKubeConfigSpecs(t *testing.T) {
} }
// Asserts InitConfiguration values injected into spec // Asserts InitConfiguration values injected into spec
masterEndpoint, err := kubeadmutil.GetMasterEndpoint(cfg) masterEndpoint, err := kubeadmutil.GetMasterEndpoint(cfg.ControlPlaneEndpoint, &cfg.LocalAPIEndpoint)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }

View File

@ -30,7 +30,6 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/version" "k8s.io/apimachinery/pkg/util/version"
clientset "k8s.io/client-go/kubernetes" clientset "k8s.io/client-go/kubernetes"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
"k8s.io/kubernetes/cmd/kubeadm/app/componentconfigs" "k8s.io/kubernetes/cmd/kubeadm/app/componentconfigs"
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
"k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient" "k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
@ -51,9 +50,9 @@ func WriteConfigToDisk(kubeletConfig *kubeletconfig.KubeletConfiguration, kubele
// CreateConfigMap creates a ConfigMap with the generic kubelet configuration. // CreateConfigMap creates a ConfigMap with the generic kubelet configuration.
// Used at "kubeadm init" and "kubeadm upgrade" time // Used at "kubeadm init" and "kubeadm upgrade" time
func CreateConfigMap(cfg *kubeadmapi.InitConfiguration, client clientset.Interface) error { func CreateConfigMap(cfg *kubeletconfig.KubeletConfiguration, k8sVersionStr string, client clientset.Interface) error {
k8sVersion, err := version.ParseSemantic(cfg.KubernetesVersion) k8sVersion, err := version.ParseSemantic(k8sVersionStr)
if err != nil { if err != nil {
return err return err
} }
@ -61,7 +60,7 @@ func CreateConfigMap(cfg *kubeadmapi.InitConfiguration, client clientset.Interfa
configMapName := kubeadmconstants.GetKubeletConfigMapName(k8sVersion) configMapName := kubeadmconstants.GetKubeletConfigMapName(k8sVersion)
fmt.Printf("[kubelet] Creating a ConfigMap %q in namespace %s with the configuration for the kubelets in the cluster\n", configMapName, metav1.NamespaceSystem) fmt.Printf("[kubelet] Creating a ConfigMap %q in namespace %s with the configuration for the kubelets in the cluster\n", configMapName, metav1.NamespaceSystem)
kubeletBytes, err := getConfigBytes(cfg.ComponentConfigs.Kubelet) kubeletBytes, err := getConfigBytes(cfg)
if err != nil { if err != nil {
return err return err
} }

View File

@ -25,7 +25,6 @@ import (
"k8s.io/apimachinery/pkg/util/version" "k8s.io/apimachinery/pkg/util/version"
"k8s.io/client-go/kubernetes/fake" "k8s.io/client-go/kubernetes/fake"
core "k8s.io/client-go/testing" core "k8s.io/client-go/testing"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
"k8s.io/kubernetes/cmd/kubeadm/app/constants" "k8s.io/kubernetes/cmd/kubeadm/app/constants"
kubeletconfig "k8s.io/kubernetes/pkg/kubelet/apis/config" kubeletconfig "k8s.io/kubernetes/pkg/kubelet/apis/config"
) )
@ -33,15 +32,8 @@ import (
func TestCreateConfigMap(t *testing.T) { func TestCreateConfigMap(t *testing.T) {
nodeName := "fake-node" nodeName := "fake-node"
client := fake.NewSimpleClientset() client := fake.NewSimpleClientset()
cfg := &kubeadmapi.InitConfiguration{ k8sVersionStr := constants.CurrentKubernetesVersion.String()
NodeRegistration: kubeadmapi.NodeRegistrationOptions{Name: nodeName}, cfg := &kubeletconfig.KubeletConfiguration{}
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
KubernetesVersion: constants.CurrentKubernetesVersion.String(),
ComponentConfigs: kubeadmapi.ComponentConfigs{
Kubelet: &kubeletconfig.KubeletConfiguration{},
},
},
}
client.PrependReactor("get", "nodes", func(action core.Action) (bool, runtime.Object, error) { client.PrependReactor("get", "nodes", func(action core.Action) (bool, runtime.Object, error) {
return true, &v1.Node{ return true, &v1.Node{
@ -61,7 +53,7 @@ func TestCreateConfigMap(t *testing.T) {
return true, nil, nil return true, nil, nil
}) })
if err := CreateConfigMap(cfg, client); err != nil { if err := CreateConfigMap(cfg, k8sVersionStr, client); err != nil {
t.Errorf("CreateConfigMap: unexpected error %v", err) t.Errorf("CreateConfigMap: unexpected error %v", err)
} }
} }

View File

@ -46,29 +46,29 @@ type kubeletFlagsOpts struct {
// WriteKubeletDynamicEnvFile writes an environment file with dynamic flags to the kubelet. // WriteKubeletDynamicEnvFile writes an environment file with dynamic flags to the kubelet.
// Used at "kubeadm init" and "kubeadm join" time. // Used at "kubeadm init" and "kubeadm join" time.
func WriteKubeletDynamicEnvFile(cfg *kubeadmapi.InitConfiguration, registerTaintsUsingFlags bool, kubeletDir string) error { func WriteKubeletDynamicEnvFile(cfg *kubeadmapi.ClusterConfiguration, nodeReg *kubeadmapi.NodeRegistrationOptions, registerTaintsUsingFlags bool, kubeletDir string) error {
hostName, err := nodeutil.GetHostname("") hostName, err := nodeutil.GetHostname("")
if err != nil { if err != nil {
return err return err
} }
flagOpts := kubeletFlagsOpts{ flagOpts := kubeletFlagsOpts{
nodeRegOpts: &cfg.NodeRegistration, nodeRegOpts: nodeReg,
featureGates: cfg.FeatureGates, featureGates: cfg.FeatureGates,
pauseImage: images.GetPauseImage(&cfg.ClusterConfiguration), pauseImage: images.GetPauseImage(cfg),
registerTaintsUsingFlags: registerTaintsUsingFlags, registerTaintsUsingFlags: registerTaintsUsingFlags,
execer: utilsexec.New(), execer: utilsexec.New(),
pidOfFunc: procfs.PidOf, pidOfFunc: procfs.PidOf,
defaultHostname: hostName, defaultHostname: hostName,
} }
stringMap := buildKubeletArgMap(flagOpts) stringMap := buildKubeletArgMap(flagOpts)
argList := kubeadmutil.BuildArgumentListFromMap(stringMap, cfg.NodeRegistration.KubeletExtraArgs) argList := kubeadmutil.BuildArgumentListFromMap(stringMap, nodeReg.KubeletExtraArgs)
envFileContent := fmt.Sprintf("%s=%s\n", constants.KubeletEnvFileVariableName, strings.Join(argList, " ")) envFileContent := fmt.Sprintf("%s=%s\n", constants.KubeletEnvFileVariableName, strings.Join(argList, " "))
return writeKubeletFlagBytesToDisk([]byte(envFileContent), kubeletDir) return writeKubeletFlagBytesToDisk([]byte(envFileContent), kubeletDir)
} }
// buildKubeletArgMap takes a InitConfiguration object and builds based on that a string-string map with flags // buildKubeletArgMap takes a kubeletFlagsOpts object and builds based on that a string-string map with flags
// that should be given to the local kubelet daemon. // that should be given to the local kubelet daemon.
func buildKubeletArgMap(opts kubeletFlagsOpts) map[string]string { func buildKubeletArgMap(opts kubeletFlagsOpts) map[string]string {
kubeletFlags := map[string]string{} kubeletFlags := map[string]string{}

View File

@ -61,7 +61,7 @@ func PerformPostUpgradeTasks(client clientset.Interface, cfg *kubeadmapi.InitCon
} }
// Create the new, version-branched kubelet ComponentConfig ConfigMap // Create the new, version-branched kubelet ComponentConfig ConfigMap
if err := kubeletphase.CreateConfigMap(cfg, client); err != nil { if err := kubeletphase.CreateConfigMap(cfg.ClusterConfiguration.ComponentConfigs.Kubelet, cfg.KubernetesVersion, client); err != nil {
errs = append(errs, errors.Wrap(err, "error creating kubelet configuration ConfigMap")) errs = append(errs, errors.Wrap(err, "error creating kubelet configuration ConfigMap"))
} }
@ -108,21 +108,21 @@ func PerformPostUpgradeTasks(client clientset.Interface, cfg *kubeadmapi.InitCon
} }
// Upgrade kube-dns/CoreDNS and kube-proxy // Upgrade kube-dns/CoreDNS and kube-proxy
if err := dns.EnsureDNSAddon(cfg, client); err != nil { if err := dns.EnsureDNSAddon(&cfg.ClusterConfiguration, client); err != nil {
errs = append(errs, err) errs = append(errs, err)
} }
// Remove the old DNS deployment if a new DNS service is now used (kube-dns to CoreDNS or vice versa) // Remove the old DNS deployment if a new DNS service is now used (kube-dns to CoreDNS or vice versa)
if err := removeOldDNSDeploymentIfAnotherDNSIsUsed(cfg, client, dryRun); err != nil { if err := removeOldDNSDeploymentIfAnotherDNSIsUsed(&cfg.ClusterConfiguration, client, dryRun); err != nil {
errs = append(errs, err) errs = append(errs, err)
} }
if err := proxy.EnsureProxyAddon(cfg, client); err != nil { if err := proxy.EnsureProxyAddon(&cfg.ClusterConfiguration, &cfg.LocalAPIEndpoint, client); err != nil {
errs = append(errs, err) errs = append(errs, err)
} }
return errorsutil.NewAggregate(errs) return errorsutil.NewAggregate(errs)
} }
func removeOldDNSDeploymentIfAnotherDNSIsUsed(cfg *kubeadmapi.InitConfiguration, client clientset.Interface, dryRun bool) error { func removeOldDNSDeploymentIfAnotherDNSIsUsed(cfg *kubeadmapi.ClusterConfiguration, client clientset.Interface, dryRun bool) error {
return apiclient.TryRunCommand(func() error { return apiclient.TryRunCommand(func() error {
installedDeploymentName := kubeadmconstants.KubeDNSDeploymentName installedDeploymentName := kubeadmconstants.KubeDNSDeploymentName
deploymentToDelete := kubeadmconstants.CoreDNSDeploymentName deploymentToDelete := kubeadmconstants.CoreDNSDeploymentName
@ -210,7 +210,7 @@ func writeKubeletConfigFiles(client clientset.Interface, cfg *kubeadmapi.InitCon
// Write env file with flags for the kubelet to use. We do not need to write the --register-with-taints for the master, // Write env file with flags for the kubelet to use. We do not need to write the --register-with-taints for the master,
// as we handle that ourselves in the markmaster phase // as we handle that ourselves in the markmaster phase
// TODO: Maybe we want to do that some time in the future, in order to remove some logic from the markmaster phase? // TODO: Maybe we want to do that some time in the future, in order to remove some logic from the markmaster phase?
if err := kubeletphase.WriteKubeletDynamicEnvFile(cfg, false, kubeletDir); err != nil { if err := kubeletphase.WriteKubeletDynamicEnvFile(&cfg.ClusterConfiguration, &cfg.NodeRegistration, false, kubeletDir); err != nil {
errs = append(errs, errors.Wrap(err, "error writing a dynamic environment file for the kubelet")) errs = append(errs, errors.Wrap(err, "error writing a dynamic environment file for the kubelet"))
} }

View File

@ -267,7 +267,7 @@ func performEtcdStaticPodUpgrade(client clientset.Interface, waiter apiclient.Wa
if err != nil { if err != nil {
return true, errors.Wrap(err, "failed to retrieve the current etcd version") return true, errors.Wrap(err, "failed to retrieve the current etcd version")
} }
currentEtcdVersionStr, ok := currentEtcdVersions[etcdutil.GetClientURL(cfg)] currentEtcdVersionStr, ok := currentEtcdVersions[etcdutil.GetClientURL(&cfg.LocalAPIEndpoint)]
if !ok { if !ok {
return true, errors.Wrap(err, "failed to retrieve the current etcd version") return true, errors.Wrap(err, "failed to retrieve the current etcd version")
} }
@ -293,7 +293,7 @@ func performEtcdStaticPodUpgrade(client clientset.Interface, waiter apiclient.Wa
// Write the updated etcd static Pod manifest into the temporary directory, at this point no etcd change // Write the updated etcd static Pod manifest into the temporary directory, at this point no etcd change
// has occurred in any aspects. // has occurred in any aspects.
if err := etcdphase.CreateLocalEtcdStaticPodManifestFile(pathMgr.TempManifestDir(), cfg); err != nil { if err := etcdphase.CreateLocalEtcdStaticPodManifestFile(pathMgr.TempManifestDir(), cfg.NodeRegistration.Name, &cfg.ClusterConfiguration, &cfg.LocalAPIEndpoint); err != nil {
return true, errors.Wrap(err, "error creating local etcd static pod manifest file") return true, errors.Wrap(err, "error creating local etcd static pod manifest file")
} }

View File

@ -453,7 +453,7 @@ func TestStaticPodControlPlane(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("couldn't run CreateInitStaticPodManifestFiles: %v", err) t.Fatalf("couldn't run CreateInitStaticPodManifestFiles: %v", err)
} }
err = etcdphase.CreateLocalEtcdStaticPodManifestFile(pathMgr.RealManifestDir(), oldcfg) err = etcdphase.CreateLocalEtcdStaticPodManifestFile(pathMgr.RealManifestDir(), oldcfg.NodeRegistration.Name, &oldcfg.ClusterConfiguration, &oldcfg.LocalAPIEndpoint)
if err != nil { if err != nil {
t.Fatalf("couldn't run CreateLocalEtcdStaticPodManifestFile: %v", err) t.Fatalf("couldn't run CreateLocalEtcdStaticPodManifestFile: %v", err)
} }

View File

@ -973,11 +973,11 @@ func RunJoinNodeChecks(execer utilsexec.Interface, cfg *kubeadmapi.JoinConfigura
} }
// RunOptionalJoinNodeChecks executes all individual, applicable to node configuration dependant checks // RunOptionalJoinNodeChecks executes all individual, applicable to node configuration dependant checks
func RunOptionalJoinNodeChecks(execer utilsexec.Interface, initCfg *kubeadmapi.InitConfiguration, ignorePreflightErrors sets.String) error { func RunOptionalJoinNodeChecks(execer utilsexec.Interface, cfg *kubeadmapi.ClusterConfiguration, ignorePreflightErrors sets.String) error {
checks := []Checker{} checks := []Checker{}
// Check ipvs required kernel module if we use ipvs kube-proxy mode // Check ipvs required kernel module if we use ipvs kube-proxy mode
if initCfg.ComponentConfigs.KubeProxy != nil && initCfg.ComponentConfigs.KubeProxy.Mode == ipvsutil.IPVSProxyMode { if cfg.ComponentConfigs.KubeProxy != nil && cfg.ComponentConfigs.KubeProxy.Mode == ipvsutil.IPVSProxyMode {
checks = append(checks, checks = append(checks,
ipvsutil.RequiredIPVSKernelModulesAvailableCheck{Executor: execer}, ipvsutil.RequiredIPVSKernelModulesAvailableCheck{Executor: execer},
) )

View File

@ -29,35 +29,35 @@ import (
) )
// GetMasterEndpoint returns a properly formatted endpoint for the control plane built according following rules: // GetMasterEndpoint returns a properly formatted endpoint for the control plane built according following rules:
// - If the ControlPlaneEndpoint is defined, use it. // - If the controlPlaneEndpoint is defined, use it.
// - if the ControlPlaneEndpoint is defined but without a port number, use the ControlPlaneEndpoint + api.BindPort is used. // - if the controlPlaneEndpoint is defined but without a port number, use the controlPlaneEndpoint + localEndpoint.BindPort is used.
// - Otherwise, in case the ControlPlaneEndpoint is not defined, use the api.AdvertiseAddress + the api.BindPort. // - Otherwise, in case the controlPlaneEndpoint is not defined, use the localEndpoint.AdvertiseAddress + the localEndpoint.BindPort.
func GetMasterEndpoint(cfg *kubeadmapi.InitConfiguration) (string, error) { func GetMasterEndpoint(controlPlaneEndpoint string, localEndpoint *kubeadmapi.APIEndpoint) (string, error) {
// parse the bind port // parse the bind port
bindPortString := strconv.Itoa(int(cfg.LocalAPIEndpoint.BindPort)) bindPortString := strconv.Itoa(int(localEndpoint.BindPort))
if _, err := ParsePort(bindPortString); err != nil { if _, err := ParsePort(bindPortString); err != nil {
return "", errors.Wrapf(err, "invalid value %q given for api.bindPort", cfg.LocalAPIEndpoint.BindPort) return "", errors.Wrapf(err, "invalid value %q given for api.bindPort", localEndpoint.BindPort)
} }
// parse the AdvertiseAddress // parse the AdvertiseAddress
var ip = net.ParseIP(cfg.LocalAPIEndpoint.AdvertiseAddress) var ip = net.ParseIP(localEndpoint.AdvertiseAddress)
if ip == nil { if ip == nil {
return "", errors.Errorf("invalid value `%s` given for api.advertiseAddress", cfg.LocalAPIEndpoint.AdvertiseAddress) return "", errors.Errorf("invalid value `%s` given for api.advertiseAddress", localEndpoint.AdvertiseAddress)
} }
// set the master url using cfg.API.AdvertiseAddress + the cfg.API.BindPort // set the master url using localEndpoint.AdvertiseAddress + the localEndpoint.BindPort
masterURL := &url.URL{ masterURL := &url.URL{
Scheme: "https", Scheme: "https",
Host: net.JoinHostPort(ip.String(), bindPortString), Host: net.JoinHostPort(ip.String(), bindPortString),
} }
// if the controlplane endpoint is defined // if the controlplane endpoint is defined
if len(cfg.ControlPlaneEndpoint) > 0 { if len(controlPlaneEndpoint) > 0 {
// parse the controlplane endpoint // parse the controlplane endpoint
var host, port string var host, port string
var err error var err error
if host, port, err = ParseHostPort(cfg.ControlPlaneEndpoint); err != nil { if host, port, err = ParseHostPort(controlPlaneEndpoint); err != nil {
return "", errors.Wrapf(err, "invalid value %q given for controlPlaneEndpoint", cfg.ControlPlaneEndpoint) return "", errors.Wrapf(err, "invalid value %q given for controlPlaneEndpoint", controlPlaneEndpoint)
} }
// if a port is provided within the controlPlaneAddress warn the users we are using it, else use the bindport // if a port is provided within the controlPlaneAddress warn the users we are using it, else use the bindport

View File

@ -198,7 +198,7 @@ func TestGetMasterEndpoint(t *testing.T) {
for _, rt := range tests { for _, rt := range tests {
t.Run(rt.name, func(t *testing.T) { t.Run(rt.name, func(t *testing.T) {
actualEndpoint, actualError := GetMasterEndpoint(rt.cfg) actualEndpoint, actualError := GetMasterEndpoint(rt.cfg.ControlPlaneEndpoint, &rt.cfg.LocalAPIEndpoint)
if (actualError != nil) && !rt.expectedError { if (actualError != nil) && !rt.expectedError {
t.Errorf("%s unexpected failure: %v", rt.name, actualError) t.Errorf("%s unexpected failure: %v", rt.name, actualError)

View File

@ -290,14 +290,14 @@ func CheckConfigurationIsHA(cfg *kubeadmapi.Etcd) bool {
// GetClientURL creates an HTTPS URL that uses the configured advertise // GetClientURL creates an HTTPS URL that uses the configured advertise
// address and client port for the API controller // address and client port for the API controller
func GetClientURL(cfg *kubeadmapi.InitConfiguration) string { func GetClientURL(localEndpoint *kubeadmapi.APIEndpoint) string {
return "https://" + net.JoinHostPort(cfg.LocalAPIEndpoint.AdvertiseAddress, strconv.Itoa(constants.EtcdListenClientPort)) return "https://" + net.JoinHostPort(localEndpoint.AdvertiseAddress, strconv.Itoa(constants.EtcdListenClientPort))
} }
// GetPeerURL creates an HTTPS URL that uses the configured advertise // GetPeerURL creates an HTTPS URL that uses the configured advertise
// address and peer port for the API controller // address and peer port for the API controller
func GetPeerURL(cfg *kubeadmapi.InitConfiguration) string { func GetPeerURL(localEndpoint *kubeadmapi.APIEndpoint) string {
return "https://" + net.JoinHostPort(cfg.LocalAPIEndpoint.AdvertiseAddress, strconv.Itoa(constants.EtcdListenPeerPort)) return "https://" + net.JoinHostPort(localEndpoint.AdvertiseAddress, strconv.Itoa(constants.EtcdListenPeerPort))
} }
// GetClientURLByIP creates an HTTPS URL based on an IP address // GetClientURLByIP creates an HTTPS URL based on an IP address

View File

@ -72,7 +72,7 @@ func TestCheckConfigurationIsHA(t *testing.T) {
} }
} }
func testGetURL(t *testing.T, getURLFunc func(*kubeadmapi.InitConfiguration) string, port int) { func testGetURL(t *testing.T, getURLFunc func(*kubeadmapi.APIEndpoint) string, port int) {
portStr := strconv.Itoa(port) portStr := strconv.Itoa(port)
var tests = []struct { var tests = []struct {
name string name string
@ -102,12 +102,7 @@ func testGetURL(t *testing.T, getURLFunc func(*kubeadmapi.InitConfiguration) str
} }
for _, test := range tests { for _, test := range tests {
cfg := &kubeadmapi.InitConfiguration{ url := getURLFunc(&kubeadmapi.APIEndpoint{AdvertiseAddress: test.advertiseAddress})
LocalAPIEndpoint: kubeadmapi.APIEndpoint{
AdvertiseAddress: test.advertiseAddress,
},
}
url := getURLFunc(cfg)
if url != test.expectedURL { if url != test.expectedURL {
t.Errorf("expected %s, got %s", test.expectedURL, url) t.Errorf("expected %s, got %s", test.expectedURL, url)
} }

View File

@ -12,11 +12,9 @@ go_test(
embed = [":go_default_library"], embed = [":go_default_library"],
deps = [ deps = [
"//cmd/kubeadm/app/apis/kubeadm:go_default_library", "//cmd/kubeadm/app/apis/kubeadm:go_default_library",
"//cmd/kubeadm/app/constants:go_default_library",
"//cmd/kubeadm/test:go_default_library", "//cmd/kubeadm/test:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/intstr:go_default_library",
], ],
) )
@ -32,7 +30,6 @@ go_library(
"//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/intstr:go_default_library",
"//vendor/github.com/pkg/errors:go_default_library", "//vendor/github.com/pkg/errors:go_default_library",
], ],
) )

View File

@ -31,7 +31,6 @@ import (
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource" "k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
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"
"k8s.io/kubernetes/cmd/kubeadm/app/util" "k8s.io/kubernetes/cmd/kubeadm/app/util"
@ -82,28 +81,11 @@ func ComponentResources(cpu string) v1.ResourceRequirements {
} }
} }
// ComponentProbe is a helper function building a ready v1.Probe object from some simple parameters
func ComponentProbe(cfg *kubeadmapi.InitConfiguration, componentName string, port int, path string, scheme v1.URIScheme) *v1.Probe {
return &v1.Probe{
Handler: v1.Handler{
HTTPGet: &v1.HTTPGetAction{
Host: GetProbeAddress(cfg, componentName),
Path: path,
Port: intstr.FromInt(port),
Scheme: scheme,
},
},
InitialDelaySeconds: 15,
TimeoutSeconds: 15,
FailureThreshold: 8,
}
}
// EtcdProbe is a helper function for building a shell-based, etcdctl v1.Probe object to healthcheck etcd // EtcdProbe is a helper function for building a shell-based, etcdctl v1.Probe object to healthcheck etcd
func EtcdProbe(cfg *kubeadmapi.InitConfiguration, componentName string, port int, certsDir string, CACertName string, CertName string, KeyName string) *v1.Probe { func EtcdProbe(cfg *kubeadmapi.Etcd, port int, certsDir string, CACertName string, CertName string, KeyName string) *v1.Probe {
tlsFlags := fmt.Sprintf("--cacert=%[1]s/%[2]s --cert=%[1]s/%[3]s --key=%[1]s/%[4]s", certsDir, CACertName, CertName, KeyName) tlsFlags := fmt.Sprintf("--cacert=%[1]s/%[2]s --cert=%[1]s/%[3]s --key=%[1]s/%[4]s", certsDir, CACertName, CertName, KeyName)
// etcd pod is alive if a linearizable get succeeds. // etcd pod is alive if a linearizable get succeeds.
cmd := fmt.Sprintf("ETCDCTL_API=3 etcdctl --endpoints=https://[%s]:%d %s get foo", GetProbeAddress(cfg, componentName), port, tlsFlags) cmd := fmt.Sprintf("ETCDCTL_API=3 etcdctl --endpoints=https://[%s]:%d %s get foo", GetEtcdProbeAddress(cfg), port, tlsFlags)
return &v1.Probe{ return &v1.Probe{
Handler: v1.Handler{ Handler: v1.Handler{
@ -225,71 +207,80 @@ func ReadStaticPodFromDisk(manifestPath string) (*v1.Pod, error) {
return pod, nil return pod, nil
} }
// GetProbeAddress returns an IP address or 127.0.0.1 to use for liveness probes // GetAPIServerProbeAddress returns the probe address for the API server
// in static pod manifests. func GetAPIServerProbeAddress(endpoint *kubeadmapi.APIEndpoint) string {
func GetProbeAddress(cfg *kubeadmapi.InitConfiguration, componentName string) string { // In the case of a self-hosted deployment, the initial host on which kubeadm --init is run,
switch { // will generate a DaemonSet with a nodeSelector such that all nodes with the label
case componentName == kubeadmconstants.KubeAPIServer: // node-role.kubernetes.io/master='' will have the API server deployed to it. Since the init
// In the case of a self-hosted deployment, the initial host on which kubeadm --init is run, // is run only once on an initial host, the API advertise address will be invalid for any
// will generate a DaemonSet with a nodeSelector such that all nodes with the label // future hosts that do not have the same address. Furthermore, since liveness and readiness
// node-role.kubernetes.io/master='' will have the API server deployed to it. Since the init // probes do not support the Downward API we cannot dynamically set the advertise address to
// is run only once on an initial host, the API advertise address will be invalid for any // the node's IP. The only option then is to use localhost.
// future hosts that do not have the same address. Furthermore, since liveness and readiness if endpoint != nil && endpoint.AdvertiseAddress != "" {
// probes do not support the Downward API we cannot dynamically set the advertise address to return endpoint.AdvertiseAddress
// the node's IP. The only option then is to use localhost. }
if cfg.LocalAPIEndpoint.AdvertiseAddress != "" {
return cfg.LocalAPIEndpoint.AdvertiseAddress return "127.0.0.1"
} }
case componentName == kubeadmconstants.KubeControllerManager:
if addr, exists := cfg.ControllerManager.ExtraArgs[kubeControllerManagerAddressArg]; exists { // GetControllerManagerProbeAddress returns the kubernetes controller manager probe address
return addr func GetControllerManagerProbeAddress(cfg *kubeadmapi.ClusterConfiguration) string {
} if addr, exists := cfg.ControllerManager.ExtraArgs[kubeControllerManagerAddressArg]; exists {
case componentName == kubeadmconstants.KubeScheduler: return addr
if addr, exists := cfg.Scheduler.ExtraArgs[kubeSchedulerAddressArg]; exists { }
return addr return "127.0.0.1"
} }
case componentName == kubeadmconstants.Etcd:
if cfg.Etcd.Local != nil && cfg.Etcd.Local.ExtraArgs != nil { // GetSchedulerProbeAddress returns the kubernetes scheduler probe address
if arg, exists := cfg.Etcd.Local.ExtraArgs[etcdListenClientURLsArg]; exists { func GetSchedulerProbeAddress(cfg *kubeadmapi.ClusterConfiguration) string {
// Use the first url in the listen-client-urls if multiple url's are specified. if addr, exists := cfg.Scheduler.ExtraArgs[kubeSchedulerAddressArg]; exists {
if strings.ContainsAny(arg, ",") { return addr
arg = strings.Split(arg, ",")[0] }
return "127.0.0.1"
}
// GetEtcdProbeAddress returns the etcd probe address
func GetEtcdProbeAddress(cfg *kubeadmapi.Etcd) string {
if cfg.Local != nil && cfg.Local.ExtraArgs != nil {
if arg, exists := cfg.Local.ExtraArgs[etcdListenClientURLsArg]; exists {
// Use the first url in the listen-client-urls if multiple url's are specified.
if strings.ContainsAny(arg, ",") {
arg = strings.Split(arg, ",")[0]
}
parsedURL, err := url.Parse(arg)
if err != nil || parsedURL.Hostname() == "" {
return "127.0.0.1"
}
// Return the IP if the URL contains an address instead of a name.
if ip := net.ParseIP(parsedURL.Hostname()); ip != nil {
// etcdctl doesn't support auto-converting zero addresses into loopback addresses
if ip.Equal(net.IPv4zero) {
return "127.0.0.1"
} }
parsedURL, err := url.Parse(arg) if ip.Equal(net.IPv6zero) {
if err != nil || parsedURL.Hostname() == "" { return net.IPv6loopback.String()
break
}
// Return the IP if the URL contains an address instead of a name.
if ip := net.ParseIP(parsedURL.Hostname()); ip != nil {
// etcdctl doesn't support auto-converting zero addresses into loopback addresses
if ip.Equal(net.IPv4zero) {
return "127.0.0.1"
}
if ip.Equal(net.IPv6zero) {
return net.IPv6loopback.String()
}
return ip.String()
}
// Use the local resolver to try resolving the name within the URL.
// If the name can not be resolved, return an IPv4 loopback address.
// Otherwise, select the first valid IPv4 address.
// If the name does not resolve to an IPv4 address, select the first valid IPv6 address.
addrs, err := net.LookupIP(parsedURL.Hostname())
if err != nil {
break
}
var ip net.IP
for _, addr := range addrs {
if addr.To4() != nil {
ip = addr
break
}
if addr.To16() != nil && ip == nil {
ip = addr
}
} }
return ip.String() return ip.String()
} }
// Use the local resolver to try resolving the name within the URL.
// If the name can not be resolved, return an IPv4 loopback address.
// Otherwise, select the first valid IPv4 address.
// If the name does not resolve to an IPv4 address, select the first valid IPv6 address.
addrs, err := net.LookupIP(parsedURL.Hostname())
if err != nil {
return "127.0.0.1"
}
var ip net.IP
for _, addr := range addrs {
if addr.To4() != nil {
ip = addr
break
}
if addr.To16() != nil && ip == nil {
ip = addr
}
}
return ip.String()
} }
} }
return "127.0.0.1" return "127.0.0.1"

View File

@ -27,9 +27,7 @@ import (
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
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"
testutil "k8s.io/kubernetes/cmd/kubeadm/test" testutil "k8s.io/kubernetes/cmd/kubeadm/test"
) )
@ -42,151 +40,73 @@ func TestComponentResources(t *testing.T) {
} }
} }
func TestComponentProbe(t *testing.T) { func TestGetAPIServerProbeAddress(t *testing.T) {
var tests = []struct { tests := []struct {
name string desc string
cfg *kubeadmapi.InitConfiguration endpoint *kubeadmapi.APIEndpoint
component string expected string
port int
path string
scheme v1.URIScheme
expected string
}{ }{
{ {
name: "default apiserver advertise address with http", desc: "nil endpoint returns 127.0.0.1",
cfg: &kubeadmapi.InitConfiguration{ expected: "127.0.0.1",
LocalAPIEndpoint: kubeadmapi.APIEndpoint{
AdvertiseAddress: "",
},
},
component: kubeadmconstants.KubeAPIServer,
port: 1,
path: "foo",
scheme: v1.URISchemeHTTP,
expected: "127.0.0.1",
}, },
{ {
name: "default apiserver advertise address with https", desc: "empty AdvertiseAddress endpoint returns 127.0.0.1",
cfg: &kubeadmapi.InitConfiguration{ endpoint: &kubeadmapi.APIEndpoint{},
LocalAPIEndpoint: kubeadmapi.APIEndpoint{ expected: "127.0.0.1",
AdvertiseAddress: "",
},
},
component: kubeadmconstants.KubeAPIServer,
port: 2,
path: "bar",
scheme: v1.URISchemeHTTPS,
expected: "127.0.0.1",
}, },
{ {
name: "valid ipv4 apiserver advertise address with http", desc: "filled in AdvertiseAddress endpoint returns it",
cfg: &kubeadmapi.InitConfiguration{ endpoint: &kubeadmapi.APIEndpoint{
LocalAPIEndpoint: kubeadmapi.APIEndpoint{ AdvertiseAddress: "10.10.10.10",
AdvertiseAddress: "1.2.3.4",
},
}, },
component: kubeadmconstants.KubeAPIServer, expected: "10.10.10.10",
port: 1,
path: "foo",
scheme: v1.URISchemeHTTP,
expected: "1.2.3.4",
},
{
name: "valid ipv6 apiserver advertise address with http",
cfg: &kubeadmapi.InitConfiguration{
LocalAPIEndpoint: kubeadmapi.APIEndpoint{
AdvertiseAddress: "2001:db8::1",
},
},
component: kubeadmconstants.KubeAPIServer,
port: 1,
path: "foo",
scheme: v1.URISchemeHTTP,
expected: "2001:db8::1",
},
{
name: "valid IPv4 controller-manager probe",
cfg: &kubeadmapi.InitConfiguration{
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
ControllerManager: kubeadmapi.ControlPlaneComponent{
ExtraArgs: map[string]string{"address": "1.2.3.4"},
},
},
},
component: kubeadmconstants.KubeControllerManager,
port: 1,
path: "foo",
scheme: v1.URISchemeHTTP,
expected: "1.2.3.4",
},
{
name: "valid IPv6 controller-manager probe",
cfg: &kubeadmapi.InitConfiguration{
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
ControllerManager: kubeadmapi.ControlPlaneComponent{
ExtraArgs: map[string]string{"address": "2001:db8::1"},
},
},
},
component: kubeadmconstants.KubeControllerManager,
port: 1,
path: "foo",
scheme: v1.URISchemeHTTP,
expected: "2001:db8::1",
},
{
name: "valid IPv4 scheduler probe",
cfg: &kubeadmapi.InitConfiguration{
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
Scheduler: kubeadmapi.ControlPlaneComponent{
ExtraArgs: map[string]string{"address": "1.2.3.4"},
},
},
},
component: kubeadmconstants.KubeScheduler,
port: 1,
path: "foo",
scheme: v1.URISchemeHTTP,
expected: "1.2.3.4",
},
{
name: "valid IPv6 scheduler probe",
cfg: &kubeadmapi.InitConfiguration{
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
Scheduler: kubeadmapi.ControlPlaneComponent{
ExtraArgs: map[string]string{"address": "2001:db8::1"},
},
},
},
component: kubeadmconstants.KubeScheduler,
port: 1,
path: "foo",
scheme: v1.URISchemeHTTP,
expected: "2001:db8::1",
}, },
} }
for _, rt := range tests {
t.Run(rt.name, func(t *testing.T) { for _, test := range tests {
actual := ComponentProbe(rt.cfg, rt.component, rt.port, rt.path, rt.scheme) t.Run(test.desc, func(t *testing.T) {
if actual.Handler.HTTPGet.Host != rt.expected { actual := GetAPIServerProbeAddress(test.endpoint)
t.Errorf("%s test case failed:\n\texpected: %s\n\t actual: %s", if actual != test.expected {
rt.name, rt.expected, t.Errorf("Unexpected result from GetAPIServerProbeAddress:\n\texpected: %s\n\tactual: %s", test.expected, actual)
actual.Handler.HTTPGet.Host)
} }
if actual.Handler.HTTPGet.Port != intstr.FromInt(rt.port) { })
t.Errorf("%s test case failed:\n\texpected: %v\n\t actual: %v", }
rt.name, rt.port, }
actual.Handler.HTTPGet.Port)
} func TestGetControllerManagerProbeAddress(t *testing.T) {
if actual.Handler.HTTPGet.Path != rt.path { tests := []struct {
t.Errorf("%s test case failed:\n\texpected: %s\n\t actual: %s", desc string
rt.name, rt.path, cfg *kubeadmapi.ClusterConfiguration
actual.Handler.HTTPGet.Path) expected string
} }{
if actual.Handler.HTTPGet.Scheme != rt.scheme { {
t.Errorf("%s test case failed:\n\texpected: %v\n\t actual: %v", desc: "no controller manager extra args leads to 127.0.0.1 being used",
rt.name, rt.scheme, cfg: &kubeadmapi.ClusterConfiguration{
actual.Handler.HTTPGet.Scheme) ControllerManager: kubeadmapi.ControlPlaneComponent{
ExtraArgs: map[string]string{},
},
},
expected: "127.0.0.1",
},
{
desc: "setting controller manager extra address arg to something acknowledges it",
cfg: &kubeadmapi.ClusterConfiguration{
ControllerManager: kubeadmapi.ControlPlaneComponent{
ExtraArgs: map[string]string{
kubeControllerManagerAddressArg: "10.10.10.10",
},
},
},
expected: "10.10.10.10",
},
}
for _, test := range tests {
t.Run(test.desc, func(t *testing.T) {
actual := GetControllerManagerProbeAddress(test.cfg)
if actual != test.expected {
t.Errorf("Unexpected result from GetControllerManagerProbeAddress:\n\texpected: %s\n\tactual: %s", test.expected, actual)
} }
}) })
} }
@ -194,150 +114,124 @@ func TestComponentProbe(t *testing.T) {
func TestEtcdProbe(t *testing.T) { func TestEtcdProbe(t *testing.T) {
var tests = []struct { var tests = []struct {
name string name string
cfg *kubeadmapi.ClusterConfiguration cfg *kubeadmapi.Etcd
component string port int
port int certsDir string
certsDir string cacert string
cacert string cert string
cert string key string
key string expected string
expected string
}{ }{
{ {
name: "valid etcd probe using listen-client-urls IPv4 addresses", name: "valid etcd probe using listen-client-urls IPv4 addresses",
cfg: &kubeadmapi.ClusterConfiguration{ cfg: &kubeadmapi.Etcd{
Etcd: kubeadmapi.Etcd{ Local: &kubeadmapi.LocalEtcd{
Local: &kubeadmapi.LocalEtcd{ ExtraArgs: map[string]string{
ExtraArgs: map[string]string{ "listen-client-urls": "http://1.2.3.4:2379,http://4.3.2.1:2379"},
"listen-client-urls": "http://1.2.3.4:2379,http://4.3.2.1:2379"},
},
}, },
}, },
component: kubeadmconstants.Etcd, port: 1,
port: 1, certsDir: "secretsA",
certsDir: "secretsA", cacert: "ca1",
cacert: "ca1", cert: "cert1",
cert: "cert1", key: "key1",
key: "key1", expected: "ETCDCTL_API=3 etcdctl --endpoints=https://[1.2.3.4]:1 --cacert=secretsA/ca1 --cert=secretsA/cert1 --key=secretsA/key1 get foo",
expected: "ETCDCTL_API=3 etcdctl --endpoints=https://[1.2.3.4]:1 --cacert=secretsA/ca1 --cert=secretsA/cert1 --key=secretsA/key1 get foo",
}, },
{ {
name: "valid etcd probe using listen-client-urls unspecified IPv6 address", name: "valid etcd probe using listen-client-urls unspecified IPv6 address",
cfg: &kubeadmapi.ClusterConfiguration{ cfg: &kubeadmapi.Etcd{
Etcd: kubeadmapi.Etcd{ Local: &kubeadmapi.LocalEtcd{
Local: &kubeadmapi.LocalEtcd{ ExtraArgs: map[string]string{
ExtraArgs: map[string]string{ "listen-client-urls": "http://[0:0:0:0:0:0:0:0]:2379"},
"listen-client-urls": "http://[0:0:0:0:0:0:0:0]:2379"},
},
}, },
}, },
component: kubeadmconstants.Etcd, port: 1,
port: 1, certsDir: "secretsB",
certsDir: "secretsB", cacert: "ca2",
cacert: "ca2", cert: "cert2",
cert: "cert2", key: "key2",
key: "key2", expected: "ETCDCTL_API=3 etcdctl --endpoints=https://[::1]:1 --cacert=secretsB/ca2 --cert=secretsB/cert2 --key=secretsB/key2 get foo",
expected: "ETCDCTL_API=3 etcdctl --endpoints=https://[::1]:1 --cacert=secretsB/ca2 --cert=secretsB/cert2 --key=secretsB/key2 get foo",
}, },
{ {
name: "valid etcd probe using listen-client-urls unspecified IPv6 address 2", name: "valid etcd probe using listen-client-urls unspecified IPv6 address 2",
cfg: &kubeadmapi.ClusterConfiguration{ cfg: &kubeadmapi.Etcd{
Etcd: kubeadmapi.Etcd{ Local: &kubeadmapi.LocalEtcd{
Local: &kubeadmapi.LocalEtcd{ ExtraArgs: map[string]string{
ExtraArgs: map[string]string{ "listen-client-urls": "http://[::0:0]:2379"},
"listen-client-urls": "http://[::0:0]:2379"},
},
}, },
}, },
component: kubeadmconstants.Etcd, port: 1,
port: 1, certsDir: "secretsB",
certsDir: "secretsB", cacert: "ca2",
cacert: "ca2", cert: "cert2",
cert: "cert2", key: "key2",
key: "key2", expected: "ETCDCTL_API=3 etcdctl --endpoints=https://[::1]:1 --cacert=secretsB/ca2 --cert=secretsB/cert2 --key=secretsB/key2 get foo",
expected: "ETCDCTL_API=3 etcdctl --endpoints=https://[::1]:1 --cacert=secretsB/ca2 --cert=secretsB/cert2 --key=secretsB/key2 get foo",
}, },
{ {
name: "valid etcd probe using listen-client-urls unspecified IPv6 address 3", name: "valid etcd probe using listen-client-urls unspecified IPv6 address 3",
cfg: &kubeadmapi.ClusterConfiguration{ cfg: &kubeadmapi.Etcd{
Etcd: kubeadmapi.Etcd{ Local: &kubeadmapi.LocalEtcd{
Local: &kubeadmapi.LocalEtcd{ ExtraArgs: map[string]string{
ExtraArgs: map[string]string{ "listen-client-urls": "http://[::]:2379"},
"listen-client-urls": "http://[::]:2379"},
},
}, },
}, },
component: kubeadmconstants.Etcd, port: 1,
port: 1, certsDir: "secretsB",
certsDir: "secretsB", cacert: "ca2",
cacert: "ca2", cert: "cert2",
cert: "cert2", key: "key2",
key: "key2", expected: "ETCDCTL_API=3 etcdctl --endpoints=https://[::1]:1 --cacert=secretsB/ca2 --cert=secretsB/cert2 --key=secretsB/key2 get foo",
expected: "ETCDCTL_API=3 etcdctl --endpoints=https://[::1]:1 --cacert=secretsB/ca2 --cert=secretsB/cert2 --key=secretsB/key2 get foo",
}, },
{ {
name: "valid etcd probe using listen-client-urls unspecified IPv4 address", name: "valid etcd probe using listen-client-urls unspecified IPv4 address",
cfg: &kubeadmapi.ClusterConfiguration{ cfg: &kubeadmapi.Etcd{
Etcd: kubeadmapi.Etcd{ Local: &kubeadmapi.LocalEtcd{
Local: &kubeadmapi.LocalEtcd{ ExtraArgs: map[string]string{
ExtraArgs: map[string]string{ "listen-client-urls": "http://1.2.3.4:2379,http://4.3.2.1:2379"},
"listen-client-urls": "http://1.2.3.4:2379,http://4.3.2.1:2379"},
},
}, },
}, },
component: kubeadmconstants.Etcd, port: 1,
port: 1, certsDir: "secretsA",
certsDir: "secretsA", cacert: "ca1",
cacert: "ca1", cert: "cert1",
cert: "cert1", key: "key1",
key: "key1", expected: "ETCDCTL_API=3 etcdctl --endpoints=https://[1.2.3.4]:1 --cacert=secretsA/ca1 --cert=secretsA/cert1 --key=secretsA/key1 get foo",
expected: "ETCDCTL_API=3 etcdctl --endpoints=https://[1.2.3.4]:1 --cacert=secretsA/ca1 --cert=secretsA/cert1 --key=secretsA/key1 get foo",
}, },
{ {
name: "valid etcd probe using listen-client-urls IPv6 addresses", name: "valid etcd probe using listen-client-urls IPv6 addresses",
cfg: &kubeadmapi.ClusterConfiguration{ cfg: &kubeadmapi.Etcd{
Etcd: kubeadmapi.Etcd{ Local: &kubeadmapi.LocalEtcd{
Local: &kubeadmapi.LocalEtcd{ ExtraArgs: map[string]string{
ExtraArgs: map[string]string{ "listen-client-urls": "http://[2001:db8::1]:2379,http://[2001:db8::2]:2379"},
"listen-client-urls": "http://[2001:db8::1]:2379,http://[2001:db8::2]:2379"},
},
}, },
}, },
component: kubeadmconstants.Etcd, port: 1,
port: 1, certsDir: "secretsB",
certsDir: "secretsB", cacert: "ca2",
cacert: "ca2", cert: "cert2",
cert: "cert2", key: "key2",
key: "key2", expected: "ETCDCTL_API=3 etcdctl --endpoints=https://[2001:db8::1]:1 --cacert=secretsB/ca2 --cert=secretsB/cert2 --key=secretsB/key2 get foo",
expected: "ETCDCTL_API=3 etcdctl --endpoints=https://[2001:db8::1]:1 --cacert=secretsB/ca2 --cert=secretsB/cert2 --key=secretsB/key2 get foo",
}, },
{ {
name: "valid IPv4 etcd probe using hostname for listen-client-urls", name: "valid IPv4 etcd probe using hostname for listen-client-urls",
cfg: &kubeadmapi.ClusterConfiguration{ cfg: &kubeadmapi.Etcd{
Etcd: kubeadmapi.Etcd{ Local: &kubeadmapi.LocalEtcd{
Local: &kubeadmapi.LocalEtcd{ ExtraArgs: map[string]string{
ExtraArgs: map[string]string{ "listen-client-urls": "http://localhost:2379"},
"listen-client-urls": "http://localhost:2379"},
},
}, },
}, },
component: kubeadmconstants.Etcd, port: 1,
port: 1, certsDir: "secretsC",
certsDir: "secretsC", cacert: "ca3",
cacert: "ca3", cert: "cert3",
cert: "cert3", key: "key3",
key: "key3", expected: "ETCDCTL_API=3 etcdctl --endpoints=https://[127.0.0.1]:1 --cacert=secretsC/ca3 --cert=secretsC/cert3 --key=secretsC/key3 get foo",
expected: "ETCDCTL_API=3 etcdctl --endpoints=https://[127.0.0.1]:1 --cacert=secretsC/ca3 --cert=secretsC/cert3 --key=secretsC/key3 get foo",
}, },
} }
for _, rt := range tests { for _, rt := range tests {
t.Run(rt.name, func(t *testing.T) { t.Run(rt.name, func(t *testing.T) {
// TODO: Make EtcdProbe accept a ClusterConfiguration object instead of InitConfiguration actual := EtcdProbe(rt.cfg, rt.port, rt.certsDir, rt.cacert, rt.cert, rt.key)
initcfg := &kubeadmapi.InitConfiguration{
ClusterConfiguration: *rt.cfg,
}
actual := EtcdProbe(initcfg, rt.component, rt.port, rt.certsDir, rt.cacert, rt.cert, rt.key)
if actual.Handler.Exec.Command[2] != rt.expected { if actual.Handler.Exec.Command[2] != rt.expected {
t.Errorf("%s test case failed:\n\texpected: %s\n\t actual: %s", t.Errorf("%s test case failed:\n\texpected: %s\n\t actual: %s",
rt.name, rt.expected, rt.name, rt.expected,