From 7a1a3aa3df78a63037f03fc6b97d08a8c8a6d07d Mon Sep 17 00:00:00 2001 From: leigh schrandt Date: Fri, 2 Mar 2018 15:25:38 -0700 Subject: [PATCH 1/2] Generate client certificates for healthchecking kubeadm etcd static pods Add new phase command: `certs etcd-healthcheck` Certs are placed at /etc/kubernetes/pki/etcd/healthcheck-client.{crt,key} --- cmd/kubeadm/app/cmd/phases/certs.go | 13 ++++++ cmd/kubeadm/app/cmd/phases/certs_test.go | 35 ++++++++++++++++ cmd/kubeadm/app/constants/constants.go | 17 ++++++-- cmd/kubeadm/app/phases/certs/certs.go | 41 +++++++++++++++++++ cmd/kubeadm/app/phases/certs/certs_test.go | 22 ++++++++++ cmd/kubeadm/app/phases/certs/doc.go | 2 + cmd/kubeadm/app/phases/upgrade/staticpods.go | 3 ++ .../app/phases/upgrade/staticpods_test.go | 1 + docs/.generated_docs | 2 + ...pha_phase_certs_etcd-healthcheck-client.md | 3 ++ ...lpha-phase-certs-etcd-healthcheck-client.1 | 3 ++ 11 files changed, 138 insertions(+), 4 deletions(-) create mode 100644 docs/admin/kubeadm_alpha_phase_certs_etcd-healthcheck-client.md create mode 100644 docs/man/man1/kubeadm-alpha-phase-certs-etcd-healthcheck-client.1 diff --git a/cmd/kubeadm/app/cmd/phases/certs.go b/cmd/kubeadm/app/cmd/phases/certs.go index d8220c5d358..7a9ffd74da9 100644 --- a/cmd/kubeadm/app/cmd/phases/certs.go +++ b/cmd/kubeadm/app/cmd/phases/certs.go @@ -98,6 +98,13 @@ var ( If both files already exist, kubeadm skips the generation step and existing files will be used. `+cmdutil.AlphaDisclaimer), kubeadmconstants.EtcdPeerCertName, kubeadmconstants.EtcdPeerKeyName) + etcdHealthcheckClientCertLongDesc = fmt.Sprintf(normalizer.LongDesc(` + Generates the client certificate for liveness probes to healthcheck etcd and the respective key, + and saves them into %s and %s files. + + If both files already exist, kubeadm skips the generation step and existing files will be used. + `+cmdutil.AlphaDisclaimer), kubeadmconstants.EtcdHealthcheckClientCertName, kubeadmconstants.EtcdHealthcheckClientKeyName) + apiServerEtcdServerCertLongDesc = fmt.Sprintf(normalizer.LongDesc(` Generates the client certificate for the API server to connect to etcd securely and the respective key, and saves them into %s and %s files. @@ -206,6 +213,12 @@ func getCertsSubCommands(defaultKubernetesVersion string) []*cobra.Command { long: etcdPeerCertLongDesc, cmdFunc: certsphase.CreateEtcdPeerCertAndKeyFiles, }, + { + use: "etcd-healthcheck-client", + short: "Generates a client certificate for liveness probes to healthcheck etcd", + long: etcdHealthcheckClientCertLongDesc, + cmdFunc: certsphase.CreateEtcdHealthcheckClientCertAndKeyFiles, + }, { use: "apiserver-etcd-client", short: "Generates a client certificate for the API server to connect to etcd securely", diff --git a/cmd/kubeadm/app/cmd/phases/certs_test.go b/cmd/kubeadm/app/cmd/phases/certs_test.go index 415e5d13890..31b9b49ce49 100644 --- a/cmd/kubeadm/app/cmd/phases/certs_test.go +++ b/cmd/kubeadm/app/cmd/phases/certs_test.go @@ -73,6 +73,21 @@ func TestCertsSubCommandsHasFlags(t *testing.T) { { command: "apiserver-kubelet-client", }, + { + command: "etcd-ca", + }, + { + command: "etcd-server", + }, + { + command: "etcd-peer", + }, + { + command: "etcd-healthcheck-client", + }, + { + command: "apiserver-etcd-client", + }, { command: "sa", }, @@ -113,6 +128,16 @@ func TestSubCmdCertsCreateFilesWithFlags(t *testing.T) { subCmds: []string{"ca", "apiserver", "apiserver-kubelet-client"}, expectedFiles: []string{kubeadmconstants.CACertName, kubeadmconstants.CAKeyName, kubeadmconstants.APIServerCertName, kubeadmconstants.APIServerKeyName, kubeadmconstants.APIServerKubeletClientCertName, kubeadmconstants.APIServerKubeletClientKeyName}, }, + { + subCmds: []string{"etcd-ca", "etcd-server", "etcd-peer", "etcd-healthcheck-client", "apiserver-etcd-client"}, + expectedFiles: []string{ + kubeadmconstants.EtcdCACertName, kubeadmconstants.EtcdCAKeyName, + kubeadmconstants.EtcdServerCertName, kubeadmconstants.EtcdServerKeyName, + kubeadmconstants.EtcdPeerCertName, kubeadmconstants.EtcdPeerKeyName, + kubeadmconstants.EtcdHealthcheckClientCertName, kubeadmconstants.EtcdHealthcheckClientKeyName, + kubeadmconstants.APIServerEtcdClientCertName, kubeadmconstants.APIServerEtcdClientKeyName, + }, + }, { subCmds: []string{"sa"}, expectedFiles: []string{kubeadmconstants.ServiceAccountPrivateKeyName, kubeadmconstants.ServiceAccountPublicKeyName}, @@ -204,6 +229,16 @@ func TestSubCmdCertsCreateFilesWithConfigFile(t *testing.T) { subCmds: []string{"ca", "apiserver", "apiserver-kubelet-client"}, expectedFiles: []string{kubeadmconstants.CACertName, kubeadmconstants.CAKeyName, kubeadmconstants.APIServerCertName, kubeadmconstants.APIServerKeyName, kubeadmconstants.APIServerKubeletClientCertName, kubeadmconstants.APIServerKubeletClientKeyName}, }, + { + subCmds: []string{"etcd-ca", "etcd-server", "etcd-peer", "etcd-healthcheck-client", "apiserver-etcd-client"}, + expectedFiles: []string{ + kubeadmconstants.EtcdCACertName, kubeadmconstants.EtcdCAKeyName, + kubeadmconstants.EtcdServerCertName, kubeadmconstants.EtcdServerKeyName, + kubeadmconstants.EtcdPeerCertName, kubeadmconstants.EtcdPeerKeyName, + kubeadmconstants.EtcdHealthcheckClientCertName, kubeadmconstants.EtcdHealthcheckClientKeyName, + kubeadmconstants.APIServerEtcdClientCertName, kubeadmconstants.APIServerEtcdClientKeyName, + }, + }, { subCmds: []string{"front-proxy-ca", "front-proxy-client"}, expectedFiles: []string{kubeadmconstants.FrontProxyCACertName, kubeadmconstants.FrontProxyCAKeyName, kubeadmconstants.FrontProxyClientCertName, kubeadmconstants.FrontProxyClientKeyName}, diff --git a/cmd/kubeadm/app/constants/constants.go b/cmd/kubeadm/app/constants/constants.go index f0acb1e25d2..66a782a86e8 100644 --- a/cmd/kubeadm/app/constants/constants.go +++ b/cmd/kubeadm/app/constants/constants.go @@ -90,13 +90,22 @@ const ( // EtcdPeerCertCommonName defines etcd's peer certificate common name (CN) EtcdPeerCertCommonName = "kube-etcd-peer" - // APIServerEtcdClientCertAndKeyBaseName defines etcd client certificate and key base name + // EtcdHealthcheckClientCertAndKeyBaseName defines etcd's healthcheck client certificate and key base name + EtcdHealthcheckClientCertAndKeyBaseName = "etcd/healthcheck-client" + // EtcdHealthcheckClientCertName defines etcd's healthcheck client certificate name + EtcdHealthcheckClientCertName = "etcd/healthcheck-client.crt" + // EtcdHealthcheckClientKeyName defines etcd's healthcheck client key name + EtcdHealthcheckClientKeyName = "etcd/healthcheck-client.key" + // EtcdHealthcheckClientCertCommonName defines etcd's healthcheck client certificate common name (CN) + EtcdHealthcheckClientCertCommonName = "kube-etcd-healthcheck-client" + + // APIServerEtcdClientCertAndKeyBaseName defines apiserver's etcd client certificate and key base name APIServerEtcdClientCertAndKeyBaseName = "apiserver-etcd-client" - // APIServerEtcdClientCertName defines etcd client certificate name + // APIServerEtcdClientCertName defines apiserver's etcd client certificate name APIServerEtcdClientCertName = "apiserver-etcd-client.crt" - // APIServerEtcdClientKeyName defines etcd client key name + // APIServerEtcdClientKeyName defines apiserver's etcd client key name APIServerEtcdClientKeyName = "apiserver-etcd-client.key" - // APIServerEtcdClientCertCommonName defines etcd client certificate common name (CN) + // APIServerEtcdClientCertCommonName defines apiserver's etcd client certificate common name (CN) APIServerEtcdClientCertCommonName = "kube-apiserver-etcd-client" // ServiceAccountKeyBaseName defines SA key base name diff --git a/cmd/kubeadm/app/phases/certs/certs.go b/cmd/kubeadm/app/phases/certs/certs.go index 2d9a1026853..f45d3247ce5 100644 --- a/cmd/kubeadm/app/phases/certs/certs.go +++ b/cmd/kubeadm/app/phases/certs/certs.go @@ -40,6 +40,7 @@ func CreatePKIAssets(cfg *kubeadmapi.MasterConfiguration) error { CreateEtcdCACertAndKeyFiles, CreateEtcdServerCertAndKeyFiles, CreateEtcdPeerCertAndKeyFiles, + CreateEtcdHealthcheckClientCertAndKeyFiles, CreateAPIServerEtcdClientCertAndKeyFiles, CreateServiceAccountKeyAndPublicKeyFiles, CreateFrontProxyCACertAndKeyFiles, @@ -190,6 +191,30 @@ func CreateEtcdPeerCertAndKeyFiles(cfg *kubeadmapi.MasterConfiguration) error { ) } +// CreateEtcdHealthcheckClientCertAndKeyFiles create a new client certificate for liveness probes to healthcheck etcd +// If the etcd-healthcheck-client certificate and key file already exist in the target folder, they are used only if evaluated equal; otherwise an error is returned. +// It assumes the etcd CA certificate and key file exist in the CertificatesDir +func CreateEtcdHealthcheckClientCertAndKeyFiles(cfg *kubeadmapi.MasterConfiguration) error { + + etcdCACert, etcdCAKey, err := loadCertificateAuthority(cfg.CertificatesDir, kubeadmconstants.EtcdCACertAndKeyBaseName) + if err != nil { + return err + } + + etcdHealthcheckClientCert, etcdHealthcheckClientKey, err := NewEtcdHealthcheckClientCertAndKey(etcdCACert, etcdCAKey) + if err != nil { + return err + } + + return writeCertificateFilesIfNotExist( + cfg.CertificatesDir, + kubeadmconstants.EtcdHealthcheckClientCertAndKeyBaseName, + etcdCACert, + etcdHealthcheckClientCert, + etcdHealthcheckClientKey, + ) +} + // CreateAPIServerEtcdClientCertAndKeyFiles create a new client certificate for the apiserver calling etcd // If the apiserver-etcd-client certificate and key file already exist in the target folder, they are used only if evaluated equal; otherwise an error is returned. // It assumes the etcd CA certificate and key file exist in the CertificatesDir @@ -375,6 +400,22 @@ func NewEtcdPeerCertAndKey(cfg *kubeadmapi.MasterConfiguration, caCert *x509.Cer return etcdPeerCert, etcdPeerKey, nil } +// NewEtcdHealthcheckClientCertAndKey generate certificate for liveness probes to healthcheck etcd, signed by the given CA. +func NewEtcdHealthcheckClientCertAndKey(caCert *x509.Certificate, caKey *rsa.PrivateKey) (*x509.Certificate, *rsa.PrivateKey, error) { + + config := certutil.Config{ + CommonName: kubeadmconstants.EtcdHealthcheckClientCertCommonName, + Organization: []string{kubeadmconstants.MastersGroup}, + Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth}, + } + etcdHealcheckClientCert, etcdHealcheckClientKey, err := pkiutil.NewCertAndKey(caCert, caKey, config) + if err != nil { + return nil, nil, fmt.Errorf("failure while creating etcd healthcheck client key and certificate: %v", err) + } + + return etcdHealcheckClientCert, etcdHealcheckClientKey, nil +} + // NewAPIServerEtcdClientCertAndKey generate certificate for the apiservers to connect to etcd securely, signed by the given CA. func NewAPIServerEtcdClientCertAndKey(caCert *x509.Certificate, caKey *rsa.PrivateKey) (*x509.Certificate, *rsa.PrivateKey, error) { diff --git a/cmd/kubeadm/app/phases/certs/certs_test.go b/cmd/kubeadm/app/phases/certs/certs_test.go index e35759e6c38..65982f135d0 100644 --- a/cmd/kubeadm/app/phases/certs/certs_test.go +++ b/cmd/kubeadm/app/phases/certs/certs_test.go @@ -382,6 +382,22 @@ func TestNewEtcdPeerCertAndKey(t *testing.T) { } } +func TestNewEtcdHealthcheckClientCertAndKey(t *testing.T) { + caCert, caKey, err := NewCACertAndKey() + if err != nil { + t.Fatalf("failed creation of ca cert and key: %v", err) + } + + etcdHealthcheckClientCert, _, err := NewEtcdHealthcheckClientCertAndKey(caCert, caKey) + if err != nil { + t.Fatalf("failed creation of cert and key: %v", err) + } + + certstestutil.AssertCertificateIsSignedByCa(t, etcdHealthcheckClientCert, caCert) + certstestutil.AssertCertificateHasClientAuthUsage(t, etcdHealthcheckClientCert) + certstestutil.AssertCertificateHasOrganizations(t, etcdHealthcheckClientCert, kubeadmconstants.MastersGroup) +} + func TestNewAPIServerEtcdClientCertAndKey(t *testing.T) { caCert, caKey, err := NewCACertAndKey() if err != nil { @@ -595,6 +611,7 @@ func TestCreateCertificateFilesMethods(t *testing.T) { kubeadmconstants.EtcdCACertName, kubeadmconstants.EtcdCAKeyName, kubeadmconstants.EtcdServerCertName, kubeadmconstants.EtcdServerKeyName, kubeadmconstants.EtcdPeerCertName, kubeadmconstants.EtcdPeerKeyName, + kubeadmconstants.EtcdHealthcheckClientCertName, kubeadmconstants.EtcdHealthcheckClientKeyName, kubeadmconstants.APIServerEtcdClientCertName, kubeadmconstants.APIServerEtcdClientKeyName, kubeadmconstants.ServiceAccountPrivateKeyName, kubeadmconstants.ServiceAccountPublicKeyName, kubeadmconstants.FrontProxyCACertName, kubeadmconstants.FrontProxyCAKeyName, @@ -629,6 +646,11 @@ func TestCreateCertificateFilesMethods(t *testing.T) { createFunc: CreateEtcdPeerCertAndKeyFiles, expectedFiles: []string{kubeadmconstants.EtcdPeerCertName, kubeadmconstants.EtcdPeerKeyName}, }, + { + setupFunc: CreateEtcdCACertAndKeyFiles, + createFunc: CreateEtcdHealthcheckClientCertAndKeyFiles, + expectedFiles: []string{kubeadmconstants.EtcdHealthcheckClientCertName, kubeadmconstants.EtcdHealthcheckClientKeyName}, + }, { setupFunc: CreateEtcdCACertAndKeyFiles, createFunc: CreateAPIServerEtcdClientCertAndKeyFiles, diff --git a/cmd/kubeadm/app/phases/certs/doc.go b/cmd/kubeadm/app/phases/certs/doc.go index ffad90b0737..0a60f992dcc 100644 --- a/cmd/kubeadm/app/phases/certs/doc.go +++ b/cmd/kubeadm/app/phases/certs/doc.go @@ -46,6 +46,8 @@ package certs - etcd/server.key - etcd/peer.crt - etcd/peer.key + - etcd/healthcheck-client.crt + - etcd/healthcheck-client.key - sa.pub - sa.key - front-proxy-ca.crt diff --git a/cmd/kubeadm/app/phases/upgrade/staticpods.go b/cmd/kubeadm/app/phases/upgrade/staticpods.go index 47718c751eb..5d45fdb5606 100644 --- a/cmd/kubeadm/app/phases/upgrade/staticpods.go +++ b/cmd/kubeadm/app/phases/upgrade/staticpods.go @@ -148,6 +148,9 @@ func upgradeComponent(component string, waiter apiclient.Waiter, pathMgr StaticP if err := certsphase.CreateEtcdPeerCertAndKeyFiles(cfg); err != nil { return fmt.Errorf("failed to upgrade the %s peer certificate and key: %v", constants.Etcd, err) } + if err := certsphase.CreateEtcdHealthcheckClientCertAndKeyFiles(cfg); err != nil { + return fmt.Errorf("failed to upgrade the %s healthcheck certificate and key: %v", constants.Etcd, err) + } } if component == constants.KubeAPIServer { if err := certsphase.CreateAPIServerEtcdClientCertAndKeyFiles(cfg); err != nil { diff --git a/cmd/kubeadm/app/phases/upgrade/staticpods_test.go b/cmd/kubeadm/app/phases/upgrade/staticpods_test.go index cea9c171d0e..e8e8f3ffafc 100644 --- a/cmd/kubeadm/app/phases/upgrade/staticpods_test.go +++ b/cmd/kubeadm/app/phases/upgrade/staticpods_test.go @@ -327,6 +327,7 @@ func TestStaticPodControlPlane(t *testing.T) { // certsphase.CreateEtcdCACertAndKeyFiles, // certsphase.CreateEtcdServerCertAndKeyFiles, // certsphase.CreateEtcdPeerCertAndKeyFiles, + // certsphase.CreateEtcdHealthcheckClientCertAndKeyFiles, // certsphase.CreateAPIServerEtcdClientCertAndKeyFiles, certsphase.CreateServiceAccountKeyAndPublicKeyFiles, certsphase.CreateFrontProxyCACertAndKeyFiles, diff --git a/docs/.generated_docs b/docs/.generated_docs index e8d3ed9bac9..c0198d7757b 100644 --- a/docs/.generated_docs +++ b/docs/.generated_docs @@ -25,6 +25,7 @@ docs/admin/kubeadm_alpha_phase_certs_apiserver-kubelet-client.md docs/admin/kubeadm_alpha_phase_certs_apiserver.md docs/admin/kubeadm_alpha_phase_certs_ca.md docs/admin/kubeadm_alpha_phase_certs_etcd-ca.md +docs/admin/kubeadm_alpha_phase_certs_etcd-healthcheck-client.md docs/admin/kubeadm_alpha_phase_certs_etcd-peer.md docs/admin/kubeadm_alpha_phase_certs_etcd-server.md docs/admin/kubeadm_alpha_phase_certs_front-proxy-ca.md @@ -92,6 +93,7 @@ docs/man/man1/kubeadm-alpha-phase-certs-apiserver-kubelet-client.1 docs/man/man1/kubeadm-alpha-phase-certs-apiserver.1 docs/man/man1/kubeadm-alpha-phase-certs-ca.1 docs/man/man1/kubeadm-alpha-phase-certs-etcd-ca.1 +docs/man/man1/kubeadm-alpha-phase-certs-etcd-healthcheck-client.1 docs/man/man1/kubeadm-alpha-phase-certs-etcd-peer.1 docs/man/man1/kubeadm-alpha-phase-certs-etcd-server.1 docs/man/man1/kubeadm-alpha-phase-certs-front-proxy-ca.1 diff --git a/docs/admin/kubeadm_alpha_phase_certs_etcd-healthcheck-client.md b/docs/admin/kubeadm_alpha_phase_certs_etcd-healthcheck-client.md new file mode 100644 index 00000000000..b6fd7a0f989 --- /dev/null +++ b/docs/admin/kubeadm_alpha_phase_certs_etcd-healthcheck-client.md @@ -0,0 +1,3 @@ +This file is autogenerated, but we've stopped checking such files into the +repository to reduce the need for rebases. Please run hack/generate-docs.sh to +populate this file. diff --git a/docs/man/man1/kubeadm-alpha-phase-certs-etcd-healthcheck-client.1 b/docs/man/man1/kubeadm-alpha-phase-certs-etcd-healthcheck-client.1 new file mode 100644 index 00000000000..b6fd7a0f989 --- /dev/null +++ b/docs/man/man1/kubeadm-alpha-phase-certs-etcd-healthcheck-client.1 @@ -0,0 +1,3 @@ +This file is autogenerated, but we've stopped checking such files into the +repository to reduce the need for rebases. Please run hack/generate-docs.sh to +populate this file. From 9bbf3fd5393455b544f6d7d0ed622d551c8e6741 Mon Sep 17 00:00:00 2001 From: leigh schrandt Date: Fri, 2 Mar 2018 16:42:34 -0700 Subject: [PATCH 2/2] Update liveness probes to exec etcdctl /w mTLS for kubeadm etcd static pods --- cmd/kubeadm/app/phases/etcd/local.go | 5 +- cmd/kubeadm/app/util/staticpod/utils.go | 18 +++ cmd/kubeadm/app/util/staticpod/utils_test.go | 113 ++++++++++++------- 3 files changed, 93 insertions(+), 43 deletions(-) diff --git a/cmd/kubeadm/app/phases/etcd/local.go b/cmd/kubeadm/app/phases/etcd/local.go index 8dfe2bd42f1..d12682cd720 100644 --- a/cmd/kubeadm/app/phases/etcd/local.go +++ b/cmd/kubeadm/app/phases/etcd/local.go @@ -65,7 +65,10 @@ func GetEtcdPodSpec(cfg *kubeadmapi.MasterConfiguration) v1.Pod { staticpodutil.NewVolumeMount(etcdVolumeName, cfg.Etcd.DataDir, false), staticpodutil.NewVolumeMount(certsVolumeName, cfg.CertificatesDir+"/etcd", false), }, - LivenessProbe: staticpodutil.ComponentProbe(cfg, kubeadmconstants.Etcd, 2379, "/health", v1.URISchemeHTTP), + LivenessProbe: staticpodutil.EtcdProbe( + cfg, kubeadmconstants.Etcd, 2379, cfg.CertificatesDir, + kubeadmconstants.EtcdCACertName, kubeadmconstants.EtcdHealthcheckClientCertName, kubeadmconstants.EtcdHealthcheckClientKeyName, + ), }, etcdMounts) } diff --git a/cmd/kubeadm/app/util/staticpod/utils.go b/cmd/kubeadm/app/util/staticpod/utils.go index 1ea1b79ad19..08291f92709 100644 --- a/cmd/kubeadm/app/util/staticpod/utils.go +++ b/cmd/kubeadm/app/util/staticpod/utils.go @@ -97,6 +97,24 @@ func ComponentProbe(cfg *kubeadmapi.MasterConfiguration, componentName string, p } } +// EtcdProbe is a helper function for building a shell-based, etcdctl v1.Probe object to healthcheck etcd +func EtcdProbe(cfg *kubeadmapi.MasterConfiguration, componentName string, 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) + // etcd pod is alive if a linearizable get succeeds. + cmd := fmt.Sprintf("ETCDCTL_API=3 etcdctl --endpoints=%s:%d %s get foo", GetProbeAddress(cfg, componentName), port, tlsFlags) + + return &v1.Probe{ + Handler: v1.Handler{ + Exec: &v1.ExecAction{ + Command: []string{"/bin/sh", "-ec", cmd}, + }, + }, + InitialDelaySeconds: 15, + TimeoutSeconds: 15, + FailureThreshold: 8, + } +} + // NewVolume creates a v1.Volume with a hostPath mount to the specified location func NewVolume(name, path string, pathType *v1.HostPathType) v1.Volume { return v1.Volume{ diff --git a/cmd/kubeadm/app/util/staticpod/utils_test.go b/cmd/kubeadm/app/util/staticpod/utils_test.go index 10a3f9ce5b4..1cf4da2b071 100644 --- a/cmd/kubeadm/app/util/staticpod/utils_test.go +++ b/cmd/kubeadm/app/util/staticpod/utils_test.go @@ -161,48 +161,6 @@ func TestComponentProbe(t *testing.T) { scheme: v1.URISchemeHTTP, expected: "2001:db8::1", }, - { - name: "valid etcd probe using listen-client-urls IPv4 addresses", - cfg: &kubeadmapi.MasterConfiguration{ - Etcd: kubeadmapi.Etcd{ - ExtraArgs: map[string]string{ - "listen-client-urls": "http://1.2.3.4:2379,http://4.3.2.1:2379"}, - }, - }, - component: kubeadmconstants.Etcd, - port: 1, - path: "foo", - scheme: v1.URISchemeHTTP, - expected: "1.2.3.4", - }, - { - name: "valid etcd probe using listen-client-urls IPv6 addresses", - cfg: &kubeadmapi.MasterConfiguration{ - Etcd: kubeadmapi.Etcd{ - ExtraArgs: map[string]string{ - "listen-client-urls": "http://[2001:db8::1]:2379,http://[2001:db8::2]:2379"}, - }, - }, - component: kubeadmconstants.Etcd, - port: 1, - path: "foo", - scheme: v1.URISchemeHTTP, - expected: "2001:db8::1", - }, - { - name: "valid IPv4 etcd probe using hostname for listen-client-urls", - cfg: &kubeadmapi.MasterConfiguration{ - Etcd: kubeadmapi.Etcd{ - ExtraArgs: map[string]string{ - "listen-client-urls": "http://localhost:2379"}, - }, - }, - component: kubeadmconstants.Etcd, - port: 1, - path: "foo", - scheme: v1.URISchemeHTTP, - expected: "127.0.0.1", - }, } for _, rt := range tests { actual := ComponentProbe(rt.cfg, rt.component, rt.port, rt.path, rt.scheme) @@ -229,6 +187,77 @@ func TestComponentProbe(t *testing.T) { } } +func TestEtcdProbe(t *testing.T) { + var tests = []struct { + name string + cfg *kubeadmapi.MasterConfiguration + component string + port int + certsDir string + cacert string + cert string + key string + expected string + }{ + { + name: "valid etcd probe using listen-client-urls IPv4 addresses", + cfg: &kubeadmapi.MasterConfiguration{ + Etcd: kubeadmapi.Etcd{ + ExtraArgs: map[string]string{ + "listen-client-urls": "http://1.2.3.4:2379,http://4.3.2.1:2379"}, + }, + }, + component: kubeadmconstants.Etcd, + port: 1, + certsDir: "secretsA", + cacert: "ca1", + cert: "cert1", + key: "key1", + expected: "ETCDCTL_API=3 etcdctl --endpoints=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", + cfg: &kubeadmapi.MasterConfiguration{ + Etcd: kubeadmapi.Etcd{ + ExtraArgs: map[string]string{ + "listen-client-urls": "http://[2001:db8::1]:2379,http://[2001:db8::2]:2379"}, + }, + }, + component: kubeadmconstants.Etcd, + port: 1, + certsDir: "secretsB", + cacert: "ca2", + cert: "cert2", + key: "key2", + expected: "ETCDCTL_API=3 etcdctl --endpoints=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", + cfg: &kubeadmapi.MasterConfiguration{ + Etcd: kubeadmapi.Etcd{ + ExtraArgs: map[string]string{ + "listen-client-urls": "http://localhost:2379"}, + }, + }, + component: kubeadmconstants.Etcd, + port: 1, + certsDir: "secretsC", + cacert: "ca3", + cert: "cert3", + key: "key3", + expected: "ETCDCTL_API=3 etcdctl --endpoints=127.0.0.1:1 --cacert=secretsC/ca3 --cert=secretsC/cert3 --key=secretsC/key3 get foo", + }, + } + for _, rt := range tests { + actual := EtcdProbe(rt.cfg, rt.component, rt.port, rt.certsDir, rt.cacert, rt.cert, rt.key) + if actual.Handler.Exec.Command[2] != rt.expected { + t.Errorf("%s test case failed:\n\texpected: %s\n\t actual: %s", + rt.name, rt.expected, + actual.Handler.Exec.Command[2]) + } + } +} + func TestComponentPod(t *testing.T) { var tests = []struct { name string