mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-14 18:53:35 +00:00
Fresh dep ensure
This commit is contained in:
31
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/dns/BUILD
generated
vendored
31
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/dns/BUILD
generated
vendored
@ -14,12 +14,12 @@ go_test(
|
||||
"//cmd/kubeadm/app/constants:go_default_library",
|
||||
"//cmd/kubeadm/app/util:go_default_library",
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes/fake:go_default_library",
|
||||
"//vendor/k8s.io/client-go/testing:go_default_library",
|
||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/testing:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@ -33,18 +33,19 @@ go_library(
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
|
||||
"//cmd/kubeadm/app/constants:go_default_library",
|
||||
"//cmd/kubeadm/app/features:go_default_library",
|
||||
"//cmd/kubeadm/app/images:go_default_library",
|
||||
"//cmd/kubeadm/app/util:go_default_library",
|
||||
"//cmd/kubeadm/app/util/apiclient:go_default_library",
|
||||
"//staging/src/k8s.io/api/apps/v1:go_default_library",
|
||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||
"//staging/src/k8s.io/api/rbac/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/kubernetes/scheme:go_default_library",
|
||||
"//vendor/github.com/mholt/caddy/caddyfile:go_default_library",
|
||||
"//vendor/k8s.io/api/apps/v1:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/api/rbac/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes/scheme:go_default_library",
|
||||
"//vendor/github.com/pkg/errors:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
|
89
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/dns/dns.go
generated
vendored
89
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/dns/dns.go
generated
vendored
@ -19,11 +19,10 @@ package dns
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/mholt/caddy/caddyfile"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
apps "k8s.io/api/apps/v1"
|
||||
"k8s.io/api/core/v1"
|
||||
rbac "k8s.io/api/rbac/v1"
|
||||
@ -34,7 +33,7 @@ import (
|
||||
clientsetscheme "k8s.io/client-go/kubernetes/scheme"
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/features"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/images"
|
||||
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
|
||||
)
|
||||
@ -48,11 +47,11 @@ const (
|
||||
)
|
||||
|
||||
// DeployedDNSAddon returns the type of DNS addon currently deployed
|
||||
func DeployedDNSAddon(client clientset.Interface) (string, string, error) {
|
||||
func DeployedDNSAddon(client clientset.Interface) (kubeadmapi.DNSAddOnType, string, error) {
|
||||
deploymentsClient := client.AppsV1().Deployments(metav1.NamespaceSystem)
|
||||
deployments, err := deploymentsClient.List(metav1.ListOptions{LabelSelector: "k8s-app=kube-dns"})
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("couldn't retrieve DNS addon deployments: %v", err)
|
||||
return "", "", errors.Wrap(err, "couldn't retrieve DNS addon deployments")
|
||||
}
|
||||
|
||||
switch len(deployments.Items) {
|
||||
@ -60,24 +59,28 @@ func DeployedDNSAddon(client clientset.Interface) (string, string, error) {
|
||||
return "", "", nil
|
||||
case 1:
|
||||
addonName := deployments.Items[0].Name
|
||||
addonType := kubeadmapi.CoreDNS
|
||||
if addonName == kubeadmconstants.KubeDNSDeploymentName {
|
||||
addonType = kubeadmapi.KubeDNS
|
||||
}
|
||||
addonImage := deployments.Items[0].Spec.Template.Spec.Containers[0].Image
|
||||
addonImageParts := strings.Split(addonImage, ":")
|
||||
addonVersion := addonImageParts[len(addonImageParts)-1]
|
||||
return addonName, addonVersion, nil
|
||||
return addonType, addonVersion, nil
|
||||
default:
|
||||
return "", "", fmt.Errorf("multiple DNS addon deployments found: %v", deployments.Items)
|
||||
return "", "", errors.Errorf("multiple DNS addon deployments found: %v", deployments.Items)
|
||||
}
|
||||
}
|
||||
|
||||
// EnsureDNSAddon creates the kube-dns or CoreDNS addon
|
||||
func EnsureDNSAddon(cfg *kubeadmapi.MasterConfiguration, client clientset.Interface) error {
|
||||
if features.Enabled(cfg.FeatureGates, features.CoreDNS) {
|
||||
func EnsureDNSAddon(cfg *kubeadmapi.InitConfiguration, client clientset.Interface) error {
|
||||
if cfg.DNS.Type == kubeadmapi.CoreDNS {
|
||||
return coreDNSAddon(cfg, client)
|
||||
}
|
||||
return kubeDNSAddon(cfg, client)
|
||||
}
|
||||
|
||||
func kubeDNSAddon(cfg *kubeadmapi.MasterConfiguration, client clientset.Interface) error {
|
||||
func kubeDNSAddon(cfg *kubeadmapi.InitConfiguration, client clientset.Interface) error {
|
||||
if err := CreateServiceAccount(client); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -97,24 +100,25 @@ func kubeDNSAddon(cfg *kubeadmapi.MasterConfiguration, client clientset.Interfac
|
||||
}
|
||||
|
||||
dnsDeploymentBytes, err := kubeadmutil.ParseTemplate(KubeDNSDeployment,
|
||||
struct{ ImageRepository, Arch, Version, DNSBindAddr, DNSProbeAddr, DNSDomain, MasterTaintKey string }{
|
||||
ImageRepository: cfg.ImageRepository,
|
||||
Arch: runtime.GOARCH,
|
||||
Version: kubeadmconstants.KubeDNSVersion,
|
||||
DNSBindAddr: dnsBindAddr,
|
||||
DNSProbeAddr: dnsProbeAddr,
|
||||
DNSDomain: cfg.Networking.DNSDomain,
|
||||
MasterTaintKey: kubeadmconstants.LabelNodeRoleMaster,
|
||||
struct{ DeploymentName, KubeDNSImage, DNSMasqImage, SidecarImage, DNSBindAddr, DNSProbeAddr, DNSDomain, MasterTaintKey string }{
|
||||
DeploymentName: kubeadmconstants.KubeDNSDeploymentName,
|
||||
KubeDNSImage: images.GetDNSImage(&cfg.ClusterConfiguration, kubeadmconstants.KubeDNSKubeDNSImageName),
|
||||
DNSMasqImage: images.GetDNSImage(&cfg.ClusterConfiguration, kubeadmconstants.KubeDNSDnsMasqNannyImageName),
|
||||
SidecarImage: images.GetDNSImage(&cfg.ClusterConfiguration, kubeadmconstants.KubeDNSSidecarImageName),
|
||||
DNSBindAddr: dnsBindAddr,
|
||||
DNSProbeAddr: dnsProbeAddr,
|
||||
DNSDomain: cfg.Networking.DNSDomain,
|
||||
MasterTaintKey: kubeadmconstants.LabelNodeRoleMaster,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("error when parsing kube-dns deployment template: %v", err)
|
||||
return errors.Wrap(err, "error when parsing kube-dns deployment template")
|
||||
}
|
||||
|
||||
dnsServiceBytes, err := kubeadmutil.ParseTemplate(KubeDNSService, struct{ DNSIP string }{
|
||||
DNSIP: dnsip.String(),
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("error when parsing kube-proxy configmap template: %v", err)
|
||||
return errors.Wrap(err, "error when parsing kube-proxy configmap template")
|
||||
}
|
||||
|
||||
if err := createKubeDNSAddon(dnsDeploymentBytes, dnsServiceBytes, client); err != nil {
|
||||
@ -138,7 +142,7 @@ func CreateServiceAccount(client clientset.Interface) error {
|
||||
func createKubeDNSAddon(deploymentBytes, serviceBytes []byte, client clientset.Interface) error {
|
||||
kubednsDeployment := &apps.Deployment{}
|
||||
if err := kuberuntime.DecodeInto(clientsetscheme.Codecs.UniversalDecoder(), deploymentBytes, kubednsDeployment); err != nil {
|
||||
return fmt.Errorf("unable to decode kube-dns deployment %v", err)
|
||||
return errors.Wrap(err, "unable to decode kube-dns deployment")
|
||||
}
|
||||
|
||||
// Create the Deployment for kube-dns or update it in case it already exists
|
||||
@ -150,19 +154,19 @@ func createKubeDNSAddon(deploymentBytes, serviceBytes []byte, client clientset.I
|
||||
return createDNSService(kubednsService, serviceBytes, client)
|
||||
}
|
||||
|
||||
func coreDNSAddon(cfg *kubeadmapi.MasterConfiguration, client clientset.Interface) error {
|
||||
func coreDNSAddon(cfg *kubeadmapi.InitConfiguration, client clientset.Interface) error {
|
||||
// Get the YAML manifest
|
||||
coreDNSDeploymentBytes, err := kubeadmutil.ParseTemplate(CoreDNSDeployment, struct{ ImageRepository, MasterTaintKey, Version string }{
|
||||
ImageRepository: cfg.ImageRepository,
|
||||
MasterTaintKey: kubeadmconstants.LabelNodeRoleMaster,
|
||||
Version: kubeadmconstants.CoreDNSVersion,
|
||||
coreDNSDeploymentBytes, err := kubeadmutil.ParseTemplate(CoreDNSDeployment, struct{ DeploymentName, Image, MasterTaintKey string }{
|
||||
DeploymentName: kubeadmconstants.CoreDNSDeploymentName,
|
||||
Image: images.GetDNSImage(&cfg.ClusterConfiguration, kubeadmconstants.CoreDNSImageName),
|
||||
MasterTaintKey: kubeadmconstants.LabelNodeRoleMaster,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("error when parsing CoreDNS deployment template: %v", err)
|
||||
return errors.Wrap(err, "error when parsing CoreDNS deployment template")
|
||||
}
|
||||
|
||||
// Get the kube-dns ConfigMap for translation to equivalent CoreDNS Config.
|
||||
kubeDNSConfigMap, err := client.CoreV1().ConfigMaps(metav1.NamespaceSystem).Get(kubeadmconstants.KubeDNS, metav1.GetOptions{})
|
||||
kubeDNSConfigMap, err := client.CoreV1().ConfigMaps(metav1.NamespaceSystem).Get(kubeadmconstants.KubeDNSConfigMap, metav1.GetOptions{})
|
||||
if err != nil && !apierrors.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
@ -190,7 +194,7 @@ func coreDNSAddon(cfg *kubeadmapi.MasterConfiguration, client clientset.Interfac
|
||||
StubDomain: stubDomain,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("error when parsing CoreDNS configMap template: %v", err)
|
||||
return errors.Wrap(err, "error when parsing CoreDNS configMap template")
|
||||
}
|
||||
|
||||
dnsip, err := kubeadmconstants.GetDNSIP(cfg.Networking.ServiceSubnet)
|
||||
@ -203,7 +207,7 @@ func coreDNSAddon(cfg *kubeadmapi.MasterConfiguration, client clientset.Interfac
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("error when parsing CoreDNS service template: %v", err)
|
||||
return errors.Wrap(err, "error when parsing CoreDNS service template")
|
||||
}
|
||||
|
||||
if err := createCoreDNSAddon(coreDNSDeploymentBytes, coreDNSServiceBytes, coreDNSConfigMapBytes, client); err != nil {
|
||||
@ -216,17 +220,17 @@ func coreDNSAddon(cfg *kubeadmapi.MasterConfiguration, client clientset.Interfac
|
||||
func createCoreDNSAddon(deploymentBytes, serviceBytes, configBytes []byte, client clientset.Interface) error {
|
||||
coreDNSConfigMap := &v1.ConfigMap{}
|
||||
if err := kuberuntime.DecodeInto(clientsetscheme.Codecs.UniversalDecoder(), configBytes, coreDNSConfigMap); err != nil {
|
||||
return fmt.Errorf("unable to decode CoreDNS configmap %v", err)
|
||||
return errors.Wrap(err, "unable to decode CoreDNS configmap")
|
||||
}
|
||||
|
||||
// Create the ConfigMap for CoreDNS or retain it in case it already exists
|
||||
if err := apiclient.CreateOrRetainConfigMap(client, coreDNSConfigMap, kubeadmconstants.CoreDNS); err != nil {
|
||||
if err := apiclient.CreateOrRetainConfigMap(client, coreDNSConfigMap, kubeadmconstants.CoreDNSConfigMap); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
coreDNSClusterRoles := &rbac.ClusterRole{}
|
||||
if err := kuberuntime.DecodeInto(clientsetscheme.Codecs.UniversalDecoder(), []byte(CoreDNSClusterRole), coreDNSClusterRoles); err != nil {
|
||||
return fmt.Errorf("unable to decode CoreDNS clusterroles %v", err)
|
||||
return errors.Wrap(err, "unable to decode CoreDNS clusterroles")
|
||||
}
|
||||
|
||||
// Create the Clusterroles for CoreDNS or update it in case it already exists
|
||||
@ -236,7 +240,7 @@ func createCoreDNSAddon(deploymentBytes, serviceBytes, configBytes []byte, clien
|
||||
|
||||
coreDNSClusterRolesBinding := &rbac.ClusterRoleBinding{}
|
||||
if err := kuberuntime.DecodeInto(clientsetscheme.Codecs.UniversalDecoder(), []byte(CoreDNSClusterRoleBinding), coreDNSClusterRolesBinding); err != nil {
|
||||
return fmt.Errorf("unable to decode CoreDNS clusterrolebindings %v", err)
|
||||
return errors.Wrap(err, "unable to decode CoreDNS clusterrolebindings")
|
||||
}
|
||||
|
||||
// Create the Clusterrolebindings for CoreDNS or update it in case it already exists
|
||||
@ -246,7 +250,7 @@ func createCoreDNSAddon(deploymentBytes, serviceBytes, configBytes []byte, clien
|
||||
|
||||
coreDNSServiceAccount := &v1.ServiceAccount{}
|
||||
if err := kuberuntime.DecodeInto(clientsetscheme.Codecs.UniversalDecoder(), []byte(CoreDNSServiceAccount), coreDNSServiceAccount); err != nil {
|
||||
return fmt.Errorf("unable to decode CoreDNS serviceaccount %v", err)
|
||||
return errors.Wrap(err, "unable to decode CoreDNS serviceaccount")
|
||||
}
|
||||
|
||||
// Create the ConfigMap for CoreDNS or update it in case it already exists
|
||||
@ -256,7 +260,7 @@ func createCoreDNSAddon(deploymentBytes, serviceBytes, configBytes []byte, clien
|
||||
|
||||
coreDNSDeployment := &apps.Deployment{}
|
||||
if err := kuberuntime.DecodeInto(clientsetscheme.Codecs.UniversalDecoder(), deploymentBytes, coreDNSDeployment); err != nil {
|
||||
return fmt.Errorf("unable to decode CoreDNS deployment %v", err)
|
||||
return errors.Wrap(err, "unable to decode CoreDNS deployment")
|
||||
}
|
||||
|
||||
// Create the Deployment for CoreDNS or update it in case it already exists
|
||||
@ -270,7 +274,7 @@ func createCoreDNSAddon(deploymentBytes, serviceBytes, configBytes []byte, clien
|
||||
|
||||
func createDNSService(dnsService *v1.Service, serviceBytes []byte, client clientset.Interface) error {
|
||||
if err := kuberuntime.DecodeInto(clientsetscheme.Codecs.UniversalDecoder(), serviceBytes, dnsService); err != nil {
|
||||
return fmt.Errorf("unable to decode the DNS service %v", err)
|
||||
return errors.Wrap(err, "unable to decode the DNS service")
|
||||
}
|
||||
|
||||
// Can't use a generic apiclient helper func here as we have to tolerate more than AlreadyExists.
|
||||
@ -279,11 +283,11 @@ func createDNSService(dnsService *v1.Service, serviceBytes []byte, client client
|
||||
// Service "kube-dns" is invalid: spec.clusterIP: Invalid value: "10.96.0.10": provided IP is already allocated
|
||||
|
||||
if !apierrors.IsAlreadyExists(err) && !apierrors.IsInvalid(err) {
|
||||
return fmt.Errorf("unable to create a new DNS service: %v", err)
|
||||
return errors.Wrap(err, "unable to create a new DNS service")
|
||||
}
|
||||
|
||||
if _, err := client.CoreV1().Services(metav1.NamespaceSystem).Update(dnsService); err != nil {
|
||||
return fmt.Errorf("unable to create/update the DNS service: %v", err)
|
||||
return errors.Wrap(err, "unable to create/update the DNS service")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@ -300,7 +304,7 @@ func translateStubDomainOfKubeDNSToProxyCoreDNS(dataField string, kubeDNSConfigM
|
||||
stubDomainData := make(map[string][]string)
|
||||
err := json.Unmarshal([]byte(proxy), &stubDomainData)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to parse JSON from 'kube-dns ConfigMap: %v", err)
|
||||
return "", errors.Wrap(err, "failed to parse JSON from 'kube-dns ConfigMap")
|
||||
}
|
||||
|
||||
var proxyStanza []interface{}
|
||||
@ -310,6 +314,7 @@ func translateStubDomainOfKubeDNSToProxyCoreDNS(dataField string, kubeDNSConfigM
|
||||
pStanza["body"] = [][]string{
|
||||
{"errors"},
|
||||
{"cache", "30"},
|
||||
{"loop"},
|
||||
append([]string{"proxy", "."}, proxyIP...),
|
||||
}
|
||||
proxyStanza = append(proxyStanza, pStanza)
|
||||
@ -341,7 +346,7 @@ func translateUpstreamNameServerOfKubeDNSToUpstreamProxyCoreDNS(dataField string
|
||||
|
||||
err := json.Unmarshal([]byte(upstreamValues), &upstreamProxyIP)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to parse JSON from 'kube-dns ConfigMap: %v", err)
|
||||
return "", errors.Wrap(err, "failed to parse JSON from 'kube-dns ConfigMap")
|
||||
}
|
||||
|
||||
coreDNSProxyStanzaList := strings.Join(upstreamProxyIP, " ")
|
||||
@ -366,7 +371,7 @@ func translateFederationsofKubeDNSToCoreDNS(dataField, coreDNSDomain string, kub
|
||||
|
||||
err := json.Unmarshal([]byte(federation), &federationData)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to parse JSON from kube-dns ConfigMap: %v", err)
|
||||
return "", errors.Wrap(err, "failed to parse JSON from kube-dns ConfigMap")
|
||||
}
|
||||
fStanza := map[string]interface{}{}
|
||||
|
||||
|
33
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/dns/dns_test.go
generated
vendored
33
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/dns/dns_test.go
generated
vendored
@ -95,14 +95,15 @@ func TestCompileManifests(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
manifest: KubeDNSDeployment,
|
||||
data: struct{ ImageRepository, Arch, Version, DNSBindAddr, DNSProbeAddr, DNSDomain, MasterTaintKey string }{
|
||||
ImageRepository: "foo",
|
||||
Arch: "foo",
|
||||
Version: "foo",
|
||||
DNSBindAddr: "foo",
|
||||
DNSProbeAddr: "foo",
|
||||
DNSDomain: "foo",
|
||||
MasterTaintKey: "foo",
|
||||
data: struct{ DeploymentName, KubeDNSImage, DNSMasqImage, SidecarImage, DNSBindAddr, DNSProbeAddr, DNSDomain, MasterTaintKey string }{
|
||||
DeploymentName: "foo",
|
||||
KubeDNSImage: "foo",
|
||||
DNSMasqImage: "foo",
|
||||
SidecarImage: "foo",
|
||||
DNSBindAddr: "foo",
|
||||
DNSProbeAddr: "foo",
|
||||
DNSDomain: "foo",
|
||||
MasterTaintKey: "foo",
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
@ -115,10 +116,10 @@ func TestCompileManifests(t *testing.T) {
|
||||
},
|
||||
{
|
||||
manifest: CoreDNSDeployment,
|
||||
data: struct{ ImageRepository, MasterTaintKey, Version string }{
|
||||
ImageRepository: "foo",
|
||||
MasterTaintKey: "foo",
|
||||
Version: "foo",
|
||||
data: struct{ DeploymentName, Image, MasterTaintKey string }{
|
||||
DeploymentName: "foo",
|
||||
Image: "foo",
|
||||
MasterTaintKey: "foo",
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
@ -204,24 +205,28 @@ func TestTranslateStubDomainKubeDNSToCoreDNS(t *testing.T) {
|
||||
foo.com:53 {
|
||||
errors
|
||||
cache 30
|
||||
loop
|
||||
proxy . 1.2.3.4:5300 3.3.3.3
|
||||
}
|
||||
|
||||
my.cluster.local:53 {
|
||||
errors
|
||||
cache 30
|
||||
loop
|
||||
proxy . 2.3.4.5
|
||||
}`,
|
||||
expectTwo: `
|
||||
my.cluster.local:53 {
|
||||
errors
|
||||
cache 30
|
||||
loop
|
||||
proxy . 2.3.4.5
|
||||
}
|
||||
|
||||
foo.com:53 {
|
||||
errors
|
||||
cache 30
|
||||
loop
|
||||
proxy . 1.2.3.4:5300 3.3.3.3
|
||||
}`,
|
||||
},
|
||||
@ -251,24 +256,28 @@ func TestTranslateStubDomainKubeDNSToCoreDNS(t *testing.T) {
|
||||
foo.com:53 {
|
||||
errors
|
||||
cache 30
|
||||
loop
|
||||
proxy . 1.2.3.4:5300
|
||||
}
|
||||
|
||||
my.cluster.local:53 {
|
||||
errors
|
||||
cache 30
|
||||
loop
|
||||
proxy . 2.3.4.5
|
||||
}`,
|
||||
expectTwo: `
|
||||
my.cluster.local:53 {
|
||||
errors
|
||||
cache 30
|
||||
loop
|
||||
proxy . 2.3.4.5
|
||||
}
|
||||
|
||||
foo.com:53 {
|
||||
errors
|
||||
cache 30
|
||||
loop
|
||||
proxy . 1.2.3.4:5300
|
||||
}`,
|
||||
},
|
||||
|
23
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/dns/manifests.go
generated
vendored
23
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/dns/manifests.go
generated
vendored
@ -22,7 +22,7 @@ const (
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: kube-dns
|
||||
name: {{ .DeploymentName }}
|
||||
namespace: kube-system
|
||||
labels:
|
||||
k8s-app: kube-dns
|
||||
@ -50,7 +50,7 @@ spec:
|
||||
optional: true
|
||||
containers:
|
||||
- name: kubedns
|
||||
image: {{ .ImageRepository }}/k8s-dns-kube-dns-{{ .Arch }}:{{ .Version }}
|
||||
image: {{ .KubeDNSImage }}
|
||||
imagePullPolicy: IfNotPresent
|
||||
resources:
|
||||
# TODO: Set memory limits when we've profiled the container for large
|
||||
@ -102,7 +102,7 @@ spec:
|
||||
- name: kube-dns-config
|
||||
mountPath: /kube-dns-config
|
||||
- name: dnsmasq
|
||||
image: {{ .ImageRepository }}/k8s-dns-dnsmasq-nanny-{{ .Arch }}:{{ .Version }}
|
||||
image: {{ .DNSMasqImage }}
|
||||
imagePullPolicy: IfNotPresent
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@ -122,6 +122,7 @@ spec:
|
||||
- -k
|
||||
- --cache-size=1000
|
||||
- --no-negcache
|
||||
- --dns-loop-detect
|
||||
- --log-facility=-
|
||||
- --server=/{{ .DNSDomain }}/{{ .DNSBindAddr }}#10053
|
||||
- --server=/in-addr.arpa/{{ .DNSBindAddr }}#10053
|
||||
@ -142,7 +143,7 @@ spec:
|
||||
- name: kube-dns-config
|
||||
mountPath: /etc/k8s/dns/dnsmasq-nanny
|
||||
- name: sidecar
|
||||
image: {{ .ImageRepository }}/k8s-dns-sidecar-{{ .Arch }}:{{ .Version }}
|
||||
image: {{ .SidecarImage }}
|
||||
imagePullPolicy: IfNotPresent
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@ -173,8 +174,6 @@ spec:
|
||||
operator: Exists
|
||||
- key: {{ .MasterTaintKey }}
|
||||
effect: NoSchedule
|
||||
nodeSelector:
|
||||
beta.kubernetes.io/arch: {{ .Arch }}
|
||||
`
|
||||
|
||||
// KubeDNSService is the kube-dns Service manifest
|
||||
@ -214,7 +213,7 @@ spec:
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: coredns
|
||||
name: {{ .DeploymentName }}
|
||||
namespace: kube-system
|
||||
labels:
|
||||
k8s-app: kube-dns
|
||||
@ -240,7 +239,7 @@ spec:
|
||||
effect: NoSchedule
|
||||
containers:
|
||||
- name: coredns
|
||||
image: {{ .ImageRepository }}/coredns:{{ .Version }}
|
||||
image: {{ .Image }}
|
||||
imagePullPolicy: IfNotPresent
|
||||
resources:
|
||||
limits:
|
||||
@ -310,7 +309,9 @@ data:
|
||||
prometheus :9153
|
||||
proxy . {{ .UpstreamNameserver }}
|
||||
cache 30
|
||||
loop
|
||||
reload
|
||||
loadbalance
|
||||
}{{ .StubDomain }}
|
||||
`
|
||||
// CoreDNSClusterRole is the CoreDNS ClusterRole manifest
|
||||
@ -330,6 +331,12 @@ rules:
|
||||
verbs:
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- nodes
|
||||
verbs:
|
||||
- get
|
||||
`
|
||||
// CoreDNSClusterRoleBinding is the CoreDNS Clusterrolebinding manifest
|
||||
CoreDNSClusterRoleBinding = `
|
||||
|
37
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/proxy/BUILD
generated
vendored
37
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/proxy/BUILD
generated
vendored
@ -11,17 +11,17 @@ go_test(
|
||||
srcs = ["proxy_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/apis/kubeadm/v1alpha2:go_default_library",
|
||||
"//cmd/kubeadm/app/apis/kubeadm/v1beta1:go_default_library",
|
||||
"//cmd/kubeadm/app/util:go_default_library",
|
||||
"//cmd/kubeadm/app/util/config:go_default_library",
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//pkg/proxy/apis/kubeproxyconfig/v1alpha1:go_default_library",
|
||||
"//pkg/util/pointer:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes/fake:go_default_library",
|
||||
"//vendor/k8s.io/client-go/testing:go_default_library",
|
||||
"//pkg/proxy/apis/config:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/testing:go_default_library",
|
||||
"//vendor/k8s.io/utils/pointer:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@ -34,17 +34,20 @@ go_library(
|
||||
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/proxy",
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
|
||||
"//cmd/kubeadm/app/componentconfigs:go_default_library",
|
||||
"//cmd/kubeadm/app/constants:go_default_library",
|
||||
"//cmd/kubeadm/app/images:go_default_library",
|
||||
"//cmd/kubeadm/app/util:go_default_library",
|
||||
"//cmd/kubeadm/app/util/apiclient:go_default_library",
|
||||
"//pkg/proxy/apis/kubeproxyconfig/scheme:go_default_library",
|
||||
"//pkg/proxy/apis/kubeproxyconfig/v1alpha1:go_default_library",
|
||||
"//vendor/k8s.io/api/apps/v1:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/api/rbac/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes/scheme:go_default_library",
|
||||
"//pkg/apis/rbac/v1:go_default_library",
|
||||
"//staging/src/k8s.io/api/apps/v1:go_default_library",
|
||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||
"//staging/src/k8s.io/api/rbac/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/kubernetes/scheme:go_default_library",
|
||||
"//vendor/github.com/pkg/errors:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
|
18
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/proxy/manifests.go
generated
vendored
18
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/proxy/manifests.go
generated
vendored
@ -22,7 +22,7 @@ const (
|
||||
kind: ConfigMap
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: kube-proxy
|
||||
name: {{ .ProxyConfigMap }}
|
||||
namespace: kube-system
|
||||
labels:
|
||||
app: kube-proxy
|
||||
@ -46,7 +46,7 @@ data:
|
||||
- name: default
|
||||
user:
|
||||
tokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
|
||||
config.conf: |-
|
||||
{{ .ProxyConfigMapKey }}: |-
|
||||
{{ .ProxyConfig}}
|
||||
`
|
||||
|
||||
@ -75,11 +75,12 @@ spec:
|
||||
priorityClassName: system-node-critical
|
||||
containers:
|
||||
- name: kube-proxy
|
||||
image: {{ if .ImageOverride }}{{ .ImageOverride }}{{ else }}{{ .ImageRepository }}/kube-proxy-{{ .Arch }}:{{ .Version }}{{ end }}
|
||||
image: {{ .Image }}
|
||||
imagePullPolicy: IfNotPresent
|
||||
command:
|
||||
- /usr/local/bin/kube-proxy
|
||||
- --config=/var/lib/kube-proxy/config.conf
|
||||
- --config=/var/lib/kube-proxy/{{ .ProxyConfigMapKey }}
|
||||
- --hostname-override=$(NODE_NAME)
|
||||
securityContext:
|
||||
privileged: true
|
||||
volumeMounts:
|
||||
@ -91,12 +92,17 @@ spec:
|
||||
- mountPath: /lib/modules
|
||||
name: lib-modules
|
||||
readOnly: true
|
||||
env:
|
||||
- name: NODE_NAME
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: spec.nodeName
|
||||
hostNetwork: true
|
||||
serviceAccountName: kube-proxy
|
||||
volumes:
|
||||
- name: kube-proxy
|
||||
configMap:
|
||||
name: kube-proxy
|
||||
name: {{ .ProxyConfigMap }}
|
||||
- name: xtables-lock
|
||||
hostPath:
|
||||
path: /run/xtables.lock
|
||||
@ -108,7 +114,5 @@ spec:
|
||||
- key: CriticalAddonsOnly
|
||||
operator: Exists
|
||||
- operator: Exists
|
||||
nodeSelector:
|
||||
beta.kubernetes.io/arch: {{ .Arch }}
|
||||
`
|
||||
)
|
||||
|
86
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/proxy/proxy.go
generated
vendored
86
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/proxy/proxy.go
generated
vendored
@ -19,8 +19,8 @@ package proxy
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"runtime"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
apps "k8s.io/api/apps/v1"
|
||||
"k8s.io/api/core/v1"
|
||||
rbac "k8s.io/api/rbac/v1"
|
||||
@ -29,10 +29,12 @@ import (
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
clientsetscheme "k8s.io/client-go/kubernetes/scheme"
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/componentconfigs"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/images"
|
||||
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
|
||||
kubeproxyconfigscheme "k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig/scheme"
|
||||
kubeproxyconfigv1alpha1 "k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig/v1alpha1"
|
||||
rbachelper "k8s.io/kubernetes/pkg/apis/rbac/v1"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -45,50 +47,52 @@ const (
|
||||
)
|
||||
|
||||
// EnsureProxyAddon creates the kube-proxy addons
|
||||
func EnsureProxyAddon(cfg *kubeadmapi.MasterConfiguration, client clientset.Interface) error {
|
||||
func EnsureProxyAddon(cfg *kubeadmapi.InitConfiguration, client clientset.Interface) error {
|
||||
if err := CreateServiceAccount(client); err != nil {
|
||||
return fmt.Errorf("error when creating kube-proxy service account: %v", err)
|
||||
return errors.Wrap(err, "error when creating kube-proxy service account")
|
||||
}
|
||||
|
||||
// Generate Master Enpoint kubeconfig file
|
||||
masterEndpoint, err := kubeadmutil.GetMasterEndpoint(&cfg.API)
|
||||
masterEndpoint, err := kubeadmutil.GetMasterEndpoint(cfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
proxyBytes, err := kubeadmutil.MarshalToYamlForCodecs(cfg.KubeProxy.Config, kubeproxyconfigv1alpha1.SchemeGroupVersion,
|
||||
kubeproxyconfigscheme.Codecs)
|
||||
proxyBytes, err := componentconfigs.Known[componentconfigs.KubeProxyConfigurationKind].Marshal(cfg.ComponentConfigs.KubeProxy)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error when marshaling: %v", err)
|
||||
return errors.Wrap(err, "error when marshaling")
|
||||
}
|
||||
var prefixBytes bytes.Buffer
|
||||
apiclient.PrintBytesWithLinePrefix(&prefixBytes, proxyBytes, " ")
|
||||
var proxyConfigMapBytes, proxyDaemonSetBytes []byte
|
||||
proxyConfigMapBytes, err = kubeadmutil.ParseTemplate(KubeProxyConfigMap19,
|
||||
struct {
|
||||
MasterEndpoint string
|
||||
ProxyConfig string
|
||||
MasterEndpoint string
|
||||
ProxyConfig string
|
||||
ProxyConfigMap string
|
||||
ProxyConfigMapKey string
|
||||
}{
|
||||
MasterEndpoint: masterEndpoint,
|
||||
ProxyConfig: prefixBytes.String(),
|
||||
MasterEndpoint: masterEndpoint,
|
||||
ProxyConfig: prefixBytes.String(),
|
||||
ProxyConfigMap: constants.KubeProxyConfigMap,
|
||||
ProxyConfigMapKey: constants.KubeProxyConfigMapKey,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("error when parsing kube-proxy configmap template: %v", err)
|
||||
return errors.Wrap(err, "error when parsing kube-proxy configmap template")
|
||||
}
|
||||
proxyDaemonSetBytes, err = kubeadmutil.ParseTemplate(KubeProxyDaemonSet19, struct{ ImageRepository, Arch, Version, ImageOverride string }{
|
||||
ImageRepository: cfg.GetControlPlaneImageRepository(),
|
||||
Arch: runtime.GOARCH,
|
||||
Version: kubeadmutil.KubernetesVersionToImageTag(cfg.KubernetesVersion),
|
||||
ImageOverride: cfg.UnifiedControlPlaneImage,
|
||||
proxyDaemonSetBytes, err = kubeadmutil.ParseTemplate(KubeProxyDaemonSet19, struct{ Image, ProxyConfigMap, ProxyConfigMapKey string }{
|
||||
Image: images.GetKubernetesImage(constants.KubeProxy, &cfg.ClusterConfiguration),
|
||||
ProxyConfigMap: constants.KubeProxyConfigMap,
|
||||
ProxyConfigMapKey: constants.KubeProxyConfigMapKey,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("error when parsing kube-proxy daemonset template: %v", err)
|
||||
return errors.Wrap(err, "error when parsing kube-proxy daemonset template")
|
||||
}
|
||||
if err := createKubeProxyAddon(proxyConfigMapBytes, proxyDaemonSetBytes, client); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := CreateRBACRules(client); err != nil {
|
||||
return fmt.Errorf("error when creating kube-proxy RBAC rules: %v", err)
|
||||
return errors.Wrap(err, "error when creating kube-proxy RBAC rules")
|
||||
}
|
||||
|
||||
fmt.Println("[addons] Applied essential addon: kube-proxy")
|
||||
@ -114,7 +118,7 @@ func CreateRBACRules(client clientset.Interface) error {
|
||||
func createKubeProxyAddon(configMapBytes, daemonSetbytes []byte, client clientset.Interface) error {
|
||||
kubeproxyConfigMap := &v1.ConfigMap{}
|
||||
if err := kuberuntime.DecodeInto(clientsetscheme.Codecs.UniversalDecoder(), configMapBytes, kubeproxyConfigMap); err != nil {
|
||||
return fmt.Errorf("unable to decode kube-proxy configmap %v", err)
|
||||
return errors.Wrap(err, "unable to decode kube-proxy configmap")
|
||||
}
|
||||
|
||||
// Create the ConfigMap for kube-proxy or update it in case it already exists
|
||||
@ -124,7 +128,7 @@ func createKubeProxyAddon(configMapBytes, daemonSetbytes []byte, client clientse
|
||||
|
||||
kubeproxyDaemonSet := &apps.DaemonSet{}
|
||||
if err := kuberuntime.DecodeInto(clientsetscheme.Codecs.UniversalDecoder(), daemonSetbytes, kubeproxyDaemonSet); err != nil {
|
||||
return fmt.Errorf("unable to decode kube-proxy daemonset %v", err)
|
||||
return errors.Wrap(err, "unable to decode kube-proxy daemonset")
|
||||
}
|
||||
|
||||
// Create the DaemonSet for kube-proxy or update it in case it already exists
|
||||
@ -132,7 +136,7 @@ func createKubeProxyAddon(configMapBytes, daemonSetbytes []byte, client clientse
|
||||
}
|
||||
|
||||
func createClusterRoleBindings(client clientset.Interface) error {
|
||||
return apiclient.CreateOrUpdateClusterRoleBinding(client, &rbac.ClusterRoleBinding{
|
||||
if err := apiclient.CreateOrUpdateClusterRoleBinding(client, &rbac.ClusterRoleBinding{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "kubeadm:node-proxier",
|
||||
},
|
||||
@ -148,5 +152,39 @@ func createClusterRoleBindings(client clientset.Interface) error {
|
||||
Namespace: metav1.NamespaceSystem,
|
||||
},
|
||||
},
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create a role for granting read only access to the kube-proxy component config ConfigMap
|
||||
if err := apiclient.CreateOrUpdateRole(client, &rbac.Role{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: constants.KubeProxyConfigMap,
|
||||
Namespace: metav1.NamespaceSystem,
|
||||
},
|
||||
Rules: []rbac.PolicyRule{
|
||||
rbachelper.NewRule("get").Groups("").Resources("configmaps").Names(constants.KubeProxyConfigMap).RuleOrDie(),
|
||||
},
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Bind the role to bootstrap tokens for allowing fetchConfiguration during join
|
||||
return apiclient.CreateOrUpdateRoleBinding(client, &rbac.RoleBinding{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: constants.KubeProxyConfigMap,
|
||||
Namespace: metav1.NamespaceSystem,
|
||||
},
|
||||
RoleRef: rbac.RoleRef{
|
||||
APIGroup: rbac.GroupName,
|
||||
Kind: "Role",
|
||||
Name: constants.KubeProxyConfigMap,
|
||||
},
|
||||
Subjects: []rbac.Subject{
|
||||
{
|
||||
Kind: rbac.GroupKind,
|
||||
Name: constants.NodeBootstrapTokenAuthGroup,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
90
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/proxy/proxy_test.go
generated
vendored
90
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/proxy/proxy_test.go
generated
vendored
@ -26,12 +26,12 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
clientsetfake "k8s.io/client-go/kubernetes/fake"
|
||||
core "k8s.io/client-go/testing"
|
||||
kubeadmapiv1alpha2 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha2"
|
||||
kubeadmapiv1beta1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta1"
|
||||
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
|
||||
cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/util/config"
|
||||
configutil "k8s.io/kubernetes/cmd/kubeadm/app/util/config"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
kubeproxyconfigv1alpha1 "k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig/v1alpha1"
|
||||
"k8s.io/kubernetes/pkg/util/pointer"
|
||||
kubeproxyconfig "k8s.io/kubernetes/pkg/proxy/apis/config"
|
||||
"k8s.io/utils/pointer"
|
||||
)
|
||||
|
||||
func TestCreateServiceAccount(t *testing.T) {
|
||||
@ -99,22 +99,21 @@ func TestCompileManifests(t *testing.T) {
|
||||
{
|
||||
manifest: KubeProxyConfigMap19,
|
||||
data: struct {
|
||||
MasterEndpoint, ProxyConfig string
|
||||
MasterEndpoint, ProxyConfig, ProxyConfigMap, ProxyConfigMapKey string
|
||||
}{
|
||||
MasterEndpoint: "foo",
|
||||
ProxyConfig: " bindAddress: 0.0.0.0\n clusterCIDR: 192.168.1.1\n enableProfiling: false",
|
||||
MasterEndpoint: "foo",
|
||||
ProxyConfig: " bindAddress: 0.0.0.0\n clusterCIDR: 192.168.1.1\n enableProfiling: false",
|
||||
ProxyConfigMap: "bar",
|
||||
ProxyConfigMapKey: "baz",
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
manifest: KubeProxyDaemonSet19,
|
||||
data: struct{ ImageRepository, Arch, Version, ImageOverride, MasterTaintKey, CloudTaintKey string }{
|
||||
ImageRepository: "foo",
|
||||
Arch: "foo",
|
||||
Version: "foo",
|
||||
ImageOverride: "foo",
|
||||
MasterTaintKey: "foo",
|
||||
CloudTaintKey: "foo",
|
||||
data: struct{ Image, ProxyConfigMap, ProxyConfigMapKey string }{
|
||||
Image: "foo",
|
||||
ProxyConfigMap: "bar",
|
||||
ProxyConfigMapKey: "baz",
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
@ -173,32 +172,19 @@ func TestEnsureProxyAddon(t *testing.T) {
|
||||
|
||||
// Create a fake client and set up default test configuration
|
||||
client := clientsetfake.NewSimpleClientset()
|
||||
|
||||
masterConfig := &kubeadmapiv1alpha2.MasterConfiguration{
|
||||
API: kubeadmapiv1alpha2.API{
|
||||
// TODO: Consider using a YAML file instead for this that makes it possible to specify YAML documents for the ComponentConfigs
|
||||
masterConfig := &kubeadmapiv1beta1.InitConfiguration{
|
||||
LocalAPIEndpoint: kubeadmapiv1beta1.APIEndpoint{
|
||||
AdvertiseAddress: "1.2.3.4",
|
||||
BindPort: 1234,
|
||||
},
|
||||
KubeProxy: kubeadmapiv1alpha2.KubeProxy{
|
||||
Config: &kubeproxyconfigv1alpha1.KubeProxyConfiguration{
|
||||
BindAddress: "",
|
||||
HealthzBindAddress: "0.0.0.0:10256",
|
||||
MetricsBindAddress: "127.0.0.1:10249",
|
||||
Conntrack: kubeproxyconfigv1alpha1.KubeProxyConntrackConfiguration{
|
||||
Max: pointer.Int32Ptr(2),
|
||||
MaxPerCore: pointer.Int32Ptr(1),
|
||||
Min: pointer.Int32Ptr(1),
|
||||
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||
},
|
||||
ClusterConfiguration: kubeadmapiv1beta1.ClusterConfiguration{
|
||||
Networking: kubeadmapiv1beta1.Networking{
|
||||
PodSubnet: "5.6.7.8/24",
|
||||
},
|
||||
ImageRepository: "someRepo",
|
||||
KubernetesVersion: "v1.12.0",
|
||||
},
|
||||
Networking: kubeadmapiv1alpha2.Networking{
|
||||
PodSubnet: "5.6.7.8/24",
|
||||
},
|
||||
ImageRepository: "someRepo",
|
||||
KubernetesVersion: "v1.10.0",
|
||||
UnifiedControlPlaneImage: "someImage",
|
||||
}
|
||||
|
||||
// Simulate an error if necessary
|
||||
@ -208,16 +194,32 @@ func TestEnsureProxyAddon(t *testing.T) {
|
||||
return true, nil, apierrors.NewUnauthorized("")
|
||||
})
|
||||
case InvalidMasterEndpoint:
|
||||
masterConfig.API.AdvertiseAddress = "1.2.3"
|
||||
masterConfig.LocalAPIEndpoint.AdvertiseAddress = "1.2.3"
|
||||
case IPv6SetBindAddress:
|
||||
masterConfig.API.AdvertiseAddress = "1:2::3:4"
|
||||
masterConfig.LocalAPIEndpoint.AdvertiseAddress = "1:2::3:4"
|
||||
masterConfig.Networking.PodSubnet = "2001:101::/96"
|
||||
}
|
||||
|
||||
kubeadmapiv1alpha2.SetDefaults_MasterConfiguration(masterConfig)
|
||||
intMaster, err := cmdutil.ConfigFileAndDefaultsToInternalConfig("", masterConfig)
|
||||
intMaster, err := configutil.ConfigFileAndDefaultsToInternalConfig("", masterConfig)
|
||||
if err != nil {
|
||||
t.Errorf(" test failed to convert v1alpha1 to internal version")
|
||||
t.Errorf("test failed to convert external to internal version")
|
||||
break
|
||||
}
|
||||
intMaster.ComponentConfigs.KubeProxy = &kubeproxyconfig.KubeProxyConfiguration{
|
||||
BindAddress: "",
|
||||
HealthzBindAddress: "0.0.0.0:10256",
|
||||
MetricsBindAddress: "127.0.0.1:10249",
|
||||
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
|
||||
Max: pointer.Int32Ptr(2),
|
||||
MaxPerCore: pointer.Int32Ptr(1),
|
||||
Min: pointer.Int32Ptr(1),
|
||||
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||
},
|
||||
}
|
||||
// Run dynamic defaulting again as we changed the internal cfg
|
||||
if err := configutil.SetInitDynamicDefaults(intMaster); err != nil {
|
||||
t.Errorf("test failed to set dynamic defaults: %v", err)
|
||||
break
|
||||
}
|
||||
err = EnsureProxyAddon(intMaster, client)
|
||||
@ -238,17 +240,17 @@ func TestEnsureProxyAddon(t *testing.T) {
|
||||
expErr,
|
||||
actErr)
|
||||
}
|
||||
if intMaster.KubeProxy.Config.BindAddress != tc.expBindAddr {
|
||||
if intMaster.ComponentConfigs.KubeProxy.BindAddress != tc.expBindAddr {
|
||||
t.Errorf("%s test failed, expected: %s, got: %s",
|
||||
tc.name,
|
||||
tc.expBindAddr,
|
||||
intMaster.KubeProxy.Config.BindAddress)
|
||||
intMaster.ComponentConfigs.KubeProxy.BindAddress)
|
||||
}
|
||||
if intMaster.KubeProxy.Config.ClusterCIDR != tc.expClusterCIDR {
|
||||
if intMaster.ComponentConfigs.KubeProxy.ClusterCIDR != tc.expClusterCIDR {
|
||||
t.Errorf("%s test failed, expected: %s, got: %s",
|
||||
tc.name,
|
||||
tc.expClusterCIDR,
|
||||
intMaster.KubeProxy.Config.ClusterCIDR)
|
||||
intMaster.ComponentConfigs.KubeProxy.ClusterCIDR)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
27
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/bootstraptoken/clusterinfo/BUILD
generated
vendored
27
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/bootstraptoken/clusterinfo/BUILD
generated
vendored
@ -12,10 +12,10 @@ go_test(
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes/fake:go_default_library",
|
||||
"//vendor/k8s.io/client-go/testing:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/testing:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@ -26,15 +26,16 @@ go_library(
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/util/apiclient:go_default_library",
|
||||
"//pkg/apis/rbac/v1:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/api/rbac/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/authentication/user:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/bootstrap/token/api:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/clientcmd:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/clientcmd/api:go_default_library",
|
||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||
"//staging/src/k8s.io/api/rbac/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/authentication/user:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/tools/clientcmd:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/tools/clientcmd/api:go_default_library",
|
||||
"//staging/src/k8s.io/cluster-bootstrap/token/api:go_default_library",
|
||||
"//vendor/github.com/pkg/errors:go_default_library",
|
||||
"//vendor/k8s.io/klog:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
|
@ -19,15 +19,16 @@ package clusterinfo
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/pkg/errors"
|
||||
"k8s.io/api/core/v1"
|
||||
rbac "k8s.io/api/rbac/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apiserver/pkg/authentication/user"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
bootstrapapi "k8s.io/client-go/tools/bootstrap/token/api"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||
bootstrapapi "k8s.io/cluster-bootstrap/token/api"
|
||||
"k8s.io/klog"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
|
||||
rbachelper "k8s.io/kubernetes/pkg/apis/rbac/v1"
|
||||
)
|
||||
@ -42,15 +43,15 @@ func CreateBootstrapConfigMapIfNotExists(client clientset.Interface, file string
|
||||
|
||||
fmt.Printf("[bootstraptoken] creating the %q ConfigMap in the %q namespace\n", bootstrapapi.ConfigMapClusterInfo, metav1.NamespacePublic)
|
||||
|
||||
glog.V(1).Infoln("[bootstraptoken] loading admin kubeconfig")
|
||||
klog.V(1).Infoln("[bootstraptoken] loading admin kubeconfig")
|
||||
adminConfig, err := clientcmd.LoadFromFile(file)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load admin kubeconfig [%v]", err)
|
||||
return errors.Wrap(err, "failed to load admin kubeconfig")
|
||||
}
|
||||
|
||||
adminCluster := adminConfig.Contexts[adminConfig.CurrentContext].Cluster
|
||||
// Copy the cluster from admin.conf to the bootstrap kubeconfig, contains the CA cert and the server URL
|
||||
glog.V(1).Infoln("[bootstraptoken] copying the cluster from admin.conf to the bootstrap kubeconfig")
|
||||
klog.V(1).Infoln("[bootstraptoken] copying the cluster from admin.conf to the bootstrap kubeconfig")
|
||||
bootstrapConfig := &clientcmdapi.Config{
|
||||
Clusters: map[string]*clientcmdapi.Cluster{
|
||||
"": adminConfig.Clusters[adminCluster],
|
||||
@ -62,7 +63,7 @@ func CreateBootstrapConfigMapIfNotExists(client clientset.Interface, file string
|
||||
}
|
||||
|
||||
// Create or update the ConfigMap in the kube-public namespace
|
||||
glog.V(1).Infoln("[bootstraptoken] creating/updating ConfigMap in kube-public namespace")
|
||||
klog.V(1).Infoln("[bootstraptoken] creating/updating ConfigMap in kube-public namespace")
|
||||
return apiclient.CreateOrUpdateConfigMap(client, &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: bootstrapapi.ConfigMapClusterInfo,
|
||||
@ -76,7 +77,7 @@ func CreateBootstrapConfigMapIfNotExists(client clientset.Interface, file string
|
||||
|
||||
// CreateClusterInfoRBACRules creates the RBAC rules for exposing the cluster-info ConfigMap in the kube-public namespace to unauthenticated users
|
||||
func CreateClusterInfoRBACRules(client clientset.Interface) error {
|
||||
glog.V(1).Infoln("creating the RBAC rules for exposing the cluster-info ConfigMap in the kube-public namespace")
|
||||
klog.V(1).Infoln("creating the RBAC rules for exposing the cluster-info ConfigMap in the kube-public namespace")
|
||||
err := apiclient.CreateOrUpdateRole(client, &rbac.Role{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: BootstrapSignerClusterRoleName,
|
||||
|
9
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/bootstraptoken/node/BUILD
generated
vendored
9
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/bootstraptoken/node/BUILD
generated
vendored
@ -16,10 +16,11 @@ go_library(
|
||||
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
|
||||
"//cmd/kubeadm/app/constants:go_default_library",
|
||||
"//cmd/kubeadm/app/util/apiclient:go_default_library",
|
||||
"//vendor/k8s.io/api/rbac/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/bootstrap/token/util:go_default_library",
|
||||
"//staging/src/k8s.io/api/rbac/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//staging/src/k8s.io/cluster-bootstrap/token/util:go_default_library",
|
||||
"//vendor/github.com/pkg/errors:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
|
8
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/bootstraptoken/node/token.go
generated
vendored
8
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/bootstraptoken/node/token.go
generated
vendored
@ -17,11 +17,11 @@ limitations under the License.
|
||||
package node
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
bootstraputil "k8s.io/client-go/tools/bootstrap/token/util"
|
||||
bootstraputil "k8s.io/cluster-bootstrap/token/util"
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
|
||||
)
|
||||
@ -41,14 +41,14 @@ func UpdateOrCreateTokens(client clientset.Interface, failIfExists bool, tokens
|
||||
secretName := bootstraputil.BootstrapTokenSecretName(token.Token.ID)
|
||||
secret, err := client.CoreV1().Secrets(metav1.NamespaceSystem).Get(secretName, metav1.GetOptions{})
|
||||
if secret != nil && err == nil && failIfExists {
|
||||
return fmt.Errorf("a token with id %q already exists", token.Token.ID)
|
||||
return errors.Errorf("a token with id %q already exists", token.Token.ID)
|
||||
}
|
||||
|
||||
updatedOrNewSecret := token.ToSecret()
|
||||
// Try to create or update the token with an exponential backoff
|
||||
err = apiclient.TryRunCommand(func() error {
|
||||
if err := apiclient.CreateOrUpdateSecret(client, updatedOrNewSecret); err != nil {
|
||||
return fmt.Errorf("failed to create or update bootstrap token with name %s: %v", secretName, err)
|
||||
return errors.Wrapf(err, "failed to create or update bootstrap token with name %s", secretName)
|
||||
}
|
||||
return nil
|
||||
}, 5)
|
||||
|
20
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/BUILD
generated
vendored
20
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/BUILD
generated
vendored
@ -8,20 +8,27 @@ load(
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["certs_test.go"],
|
||||
srcs = [
|
||||
"certlist_test.go",
|
||||
"certs_test.go",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
|
||||
"//cmd/kubeadm/app/constants:go_default_library",
|
||||
"//cmd/kubeadm/app/phases/certs/pkiutil:go_default_library",
|
||||
"//cmd/kubeadm/app/util/pkiutil:go_default_library",
|
||||
"//cmd/kubeadm/test:go_default_library",
|
||||
"//cmd/kubeadm/test/certs:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/util/cert:go_default_library",
|
||||
"//vendor/github.com/pkg/errors:go_default_library",
|
||||
"//vendor/github.com/stretchr/testify/assert:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"certlist.go",
|
||||
"certs.go",
|
||||
"doc.go",
|
||||
],
|
||||
@ -29,9 +36,10 @@ go_library(
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
|
||||
"//cmd/kubeadm/app/constants:go_default_library",
|
||||
"//cmd/kubeadm/app/phases/certs/pkiutil:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/k8s.io/client-go/util/cert:go_default_library",
|
||||
"//cmd/kubeadm/app/util/pkiutil:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/util/cert:go_default_library",
|
||||
"//vendor/github.com/pkg/errors:go_default_library",
|
||||
"//vendor/k8s.io/klog:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@ -46,7 +54,7 @@ filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//cmd/kubeadm/app/phases/certs/pkiutil:all-srcs",
|
||||
"//cmd/kubeadm/app/phases/certs/renewal:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
|
377
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/certlist.go
generated
vendored
Normal file
377
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/certlist.go
generated
vendored
Normal file
@ -0,0 +1,377 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package certs
|
||||
|
||||
import (
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
certutil "k8s.io/client-go/util/cert"
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/util/pkiutil"
|
||||
)
|
||||
|
||||
type configMutatorsFunc func(*kubeadmapi.InitConfiguration, *certutil.Config) error
|
||||
|
||||
// KubeadmCert represents a certificate that Kubeadm will create to function properly.
|
||||
type KubeadmCert struct {
|
||||
Name string
|
||||
LongName string
|
||||
BaseName string
|
||||
CAName string
|
||||
// Some attributes will depend on the InitConfiguration, only known at runtime.
|
||||
// These functions will be run in series, passed both the InitConfiguration and a cert Config.
|
||||
configMutators []configMutatorsFunc
|
||||
config certutil.Config
|
||||
}
|
||||
|
||||
// GetConfig returns the definition for the given cert given the provided InitConfiguration
|
||||
func (k *KubeadmCert) GetConfig(ic *kubeadmapi.InitConfiguration) (*certutil.Config, error) {
|
||||
for _, f := range k.configMutators {
|
||||
if err := f(ic, &k.config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return &k.config, nil
|
||||
}
|
||||
|
||||
// CreateFromCA makes and writes a certificate using the given CA cert and key.
|
||||
func (k *KubeadmCert) CreateFromCA(ic *kubeadmapi.InitConfiguration, caCert *x509.Certificate, caKey *rsa.PrivateKey) error {
|
||||
cfg, err := k.GetConfig(ic)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "couldn't create %q certificate", k.Name)
|
||||
}
|
||||
cert, key, err := pkiutil.NewCertAndKey(caCert, caKey, cfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = writeCertificateFilesIfNotExist(
|
||||
ic.CertificatesDir,
|
||||
k.BaseName,
|
||||
caCert,
|
||||
cert,
|
||||
key,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to write certificate %q", k.Name)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateAsCA creates a certificate authority, writing the files to disk and also returning the created CA so it can be used to sign child certs.
|
||||
func (k *KubeadmCert) CreateAsCA(ic *kubeadmapi.InitConfiguration) (*x509.Certificate, *rsa.PrivateKey, error) {
|
||||
cfg, err := k.GetConfig(ic)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrapf(err, "couldn't get configuration for %q CA certificate", k.Name)
|
||||
}
|
||||
caCert, caKey, err := NewCACertAndKey(cfg)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrapf(err, "couldn't generate %q CA certificate", k.Name)
|
||||
}
|
||||
|
||||
err = writeCertificateAuthorithyFilesIfNotExist(
|
||||
ic.CertificatesDir,
|
||||
k.BaseName,
|
||||
caCert,
|
||||
caKey,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrapf(err, "couldn't write out %q CA certificate", k.Name)
|
||||
}
|
||||
|
||||
return caCert, caKey, nil
|
||||
}
|
||||
|
||||
// CertificateTree is represents a one-level-deep tree, mapping a CA to the certs that depend on it.
|
||||
type CertificateTree map[*KubeadmCert]Certificates
|
||||
|
||||
// CreateTree creates the CAs, certs signed by the CAs, and writes them all to disk.
|
||||
func (t CertificateTree) CreateTree(ic *kubeadmapi.InitConfiguration) error {
|
||||
for ca, leaves := range t {
|
||||
cfg, err := ca.GetConfig(ic)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var caKey *rsa.PrivateKey
|
||||
|
||||
caCert, err := pkiutil.TryLoadCertFromDisk(ic.CertificatesDir, ca.BaseName)
|
||||
if err == nil {
|
||||
// Cert exists already, make sure it's valid
|
||||
if !caCert.IsCA {
|
||||
return errors.Errorf("certificate %q is not a CA", ca.Name)
|
||||
}
|
||||
// Try and load a CA Key
|
||||
caKey, err = pkiutil.TryLoadKeyFromDisk(ic.CertificatesDir, ca.BaseName)
|
||||
if err != nil {
|
||||
// If there's no CA key, make sure every certificate exists.
|
||||
for _, leaf := range leaves {
|
||||
cl := certKeyLocation{
|
||||
pkiDir: ic.CertificatesDir,
|
||||
baseName: leaf.BaseName,
|
||||
uxName: leaf.Name,
|
||||
}
|
||||
if err := validateSignedCertWithCA(cl, caCert); err != nil {
|
||||
return errors.Wrapf(err, "could not load expected certificate %q or validate the existence of key %q for it", leaf.Name, ca.Name)
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
// CA key exists; just use that to create new certificates.
|
||||
} else {
|
||||
// CACert doesn't already exist, create a new cert and key.
|
||||
caCert, caKey, err = NewCACertAndKey(cfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = writeCertificateAuthorithyFilesIfNotExist(
|
||||
ic.CertificatesDir,
|
||||
ca.BaseName,
|
||||
caCert,
|
||||
caKey,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for _, leaf := range leaves {
|
||||
if err := leaf.CreateFromCA(ic, caCert, caKey); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CertificateMap is a flat map of certificates, keyed by Name.
|
||||
type CertificateMap map[string]*KubeadmCert
|
||||
|
||||
// CertTree returns a one-level-deep tree, mapping a CA cert to an array of certificates that should be signed by it.
|
||||
func (m CertificateMap) CertTree() (CertificateTree, error) {
|
||||
caMap := make(CertificateTree)
|
||||
|
||||
for _, cert := range m {
|
||||
if cert.CAName == "" {
|
||||
if _, ok := caMap[cert]; !ok {
|
||||
caMap[cert] = []*KubeadmCert{}
|
||||
}
|
||||
} else {
|
||||
ca, ok := m[cert.CAName]
|
||||
if !ok {
|
||||
return nil, errors.Errorf("certificate %q references unknown CA %q", cert.Name, cert.CAName)
|
||||
}
|
||||
caMap[ca] = append(caMap[ca], cert)
|
||||
}
|
||||
}
|
||||
|
||||
return caMap, nil
|
||||
}
|
||||
|
||||
// Certificates is a list of Certificates that Kubeadm should create.
|
||||
type Certificates []*KubeadmCert
|
||||
|
||||
// AsMap returns the list of certificates as a map, keyed by name.
|
||||
func (c Certificates) AsMap() CertificateMap {
|
||||
certMap := make(map[string]*KubeadmCert)
|
||||
for _, cert := range c {
|
||||
certMap[cert.Name] = cert
|
||||
}
|
||||
|
||||
return certMap
|
||||
}
|
||||
|
||||
// GetDefaultCertList returns all of the certificates kubeadm requires to function.
|
||||
func GetDefaultCertList() Certificates {
|
||||
return Certificates{
|
||||
&KubeadmCertRootCA,
|
||||
&KubeadmCertAPIServer,
|
||||
&KubeadmCertKubeletClient,
|
||||
// Front Proxy certs
|
||||
&KubeadmCertFrontProxyCA,
|
||||
&KubeadmCertFrontProxyClient,
|
||||
// etcd certs
|
||||
&KubeadmCertEtcdCA,
|
||||
&KubeadmCertEtcdServer,
|
||||
&KubeadmCertEtcdPeer,
|
||||
&KubeadmCertEtcdHealthcheck,
|
||||
&KubeadmCertEtcdAPIClient,
|
||||
}
|
||||
}
|
||||
|
||||
// GetCertsWithoutEtcd returns all of the certificates kubeadm needs when etcd is hosted externally.
|
||||
func GetCertsWithoutEtcd() Certificates {
|
||||
return Certificates{
|
||||
&KubeadmCertRootCA,
|
||||
&KubeadmCertAPIServer,
|
||||
&KubeadmCertKubeletClient,
|
||||
// Front Proxy certs
|
||||
&KubeadmCertFrontProxyCA,
|
||||
&KubeadmCertFrontProxyClient,
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
// KubeadmCertRootCA is the definition of the Kubernetes Root CA for the API Server and kubelet.
|
||||
KubeadmCertRootCA = KubeadmCert{
|
||||
Name: "ca",
|
||||
LongName: "self-signed Kubernetes CA to provision identities for other Kubernetes components",
|
||||
BaseName: kubeadmconstants.CACertAndKeyBaseName,
|
||||
config: certutil.Config{
|
||||
CommonName: "kubernetes",
|
||||
},
|
||||
}
|
||||
// KubeadmCertAPIServer is the definition of the cert used to serve the Kubernetes API.
|
||||
KubeadmCertAPIServer = KubeadmCert{
|
||||
Name: "apiserver",
|
||||
LongName: "certificate for serving the Kubernetes API",
|
||||
BaseName: kubeadmconstants.APIServerCertAndKeyBaseName,
|
||||
CAName: "ca",
|
||||
config: certutil.Config{
|
||||
CommonName: kubeadmconstants.APIServerCertCommonName,
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
||||
},
|
||||
configMutators: []configMutatorsFunc{
|
||||
makeAltNamesMutator(pkiutil.GetAPIServerAltNames),
|
||||
},
|
||||
}
|
||||
// KubeadmCertKubeletClient is the definition of the cert used by the API server to access the kubelet.
|
||||
KubeadmCertKubeletClient = KubeadmCert{
|
||||
Name: "apiserver-kubelet-client",
|
||||
LongName: "Client certificate for the API server to connect to kubelet",
|
||||
BaseName: kubeadmconstants.APIServerKubeletClientCertAndKeyBaseName,
|
||||
CAName: "ca",
|
||||
config: certutil.Config{
|
||||
CommonName: kubeadmconstants.APIServerKubeletClientCertCommonName,
|
||||
Organization: []string{kubeadmconstants.MastersGroup},
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
},
|
||||
}
|
||||
|
||||
// KubeadmCertFrontProxyCA is the definition of the CA used for the front end proxy.
|
||||
KubeadmCertFrontProxyCA = KubeadmCert{
|
||||
Name: "front-proxy-ca",
|
||||
LongName: "self-signed CA to provision identities for front proxy",
|
||||
BaseName: kubeadmconstants.FrontProxyCACertAndKeyBaseName,
|
||||
config: certutil.Config{
|
||||
CommonName: "front-proxy-ca",
|
||||
},
|
||||
}
|
||||
|
||||
// KubeadmCertFrontProxyClient is the definition of the cert used by the API server to access the front proxy.
|
||||
KubeadmCertFrontProxyClient = KubeadmCert{
|
||||
Name: "front-proxy-client",
|
||||
BaseName: kubeadmconstants.FrontProxyClientCertAndKeyBaseName,
|
||||
LongName: "client for the front proxy",
|
||||
CAName: "front-proxy-ca",
|
||||
config: certutil.Config{
|
||||
CommonName: kubeadmconstants.FrontProxyClientCertCommonName,
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
},
|
||||
}
|
||||
|
||||
// KubeadmCertEtcdCA is the definition of the root CA used by the hosted etcd server.
|
||||
KubeadmCertEtcdCA = KubeadmCert{
|
||||
Name: "etcd-ca",
|
||||
LongName: "self-signed CA to provision identities for etcd",
|
||||
BaseName: kubeadmconstants.EtcdCACertAndKeyBaseName,
|
||||
config: certutil.Config{
|
||||
CommonName: "etcd-ca",
|
||||
},
|
||||
}
|
||||
// KubeadmCertEtcdServer is the definition of the cert used to serve etcd to clients.
|
||||
KubeadmCertEtcdServer = KubeadmCert{
|
||||
Name: "etcd-server",
|
||||
LongName: "certificate for serving etcd",
|
||||
BaseName: kubeadmconstants.EtcdServerCertAndKeyBaseName,
|
||||
CAName: "etcd-ca",
|
||||
config: certutil.Config{
|
||||
// TODO: etcd 3.2 introduced an undocumented requirement for ClientAuth usage on the
|
||||
// server cert: https://github.com/coreos/etcd/issues/9785#issuecomment-396715692
|
||||
// Once the upstream issue is resolved, this should be returned to only allowing
|
||||
// ServerAuth usage.
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
|
||||
},
|
||||
configMutators: []configMutatorsFunc{
|
||||
makeAltNamesMutator(pkiutil.GetEtcdAltNames),
|
||||
setCommonNameToNodeName(),
|
||||
},
|
||||
}
|
||||
// KubeadmCertEtcdPeer is the definition of the cert used by etcd peers to access each other.
|
||||
KubeadmCertEtcdPeer = KubeadmCert{
|
||||
Name: "etcd-peer",
|
||||
LongName: "credentials for etcd nodes to communicate with each other",
|
||||
BaseName: kubeadmconstants.EtcdPeerCertAndKeyBaseName,
|
||||
CAName: "etcd-ca",
|
||||
config: certutil.Config{
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
|
||||
},
|
||||
configMutators: []configMutatorsFunc{
|
||||
makeAltNamesMutator(pkiutil.GetEtcdPeerAltNames),
|
||||
setCommonNameToNodeName(),
|
||||
},
|
||||
}
|
||||
// KubeadmCertEtcdHealthcheck is the definition of the cert used by Kubernetes to check the health of the etcd server.
|
||||
KubeadmCertEtcdHealthcheck = KubeadmCert{
|
||||
Name: "etcd-healthcheck-client",
|
||||
LongName: "client certificate for liveness probes to healtcheck etcd",
|
||||
BaseName: kubeadmconstants.EtcdHealthcheckClientCertAndKeyBaseName,
|
||||
CAName: "etcd-ca",
|
||||
config: certutil.Config{
|
||||
CommonName: kubeadmconstants.EtcdHealthcheckClientCertCommonName,
|
||||
Organization: []string{kubeadmconstants.MastersGroup},
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
},
|
||||
}
|
||||
// KubeadmCertEtcdAPIClient is the definition of the cert used by the API server to access etcd.
|
||||
KubeadmCertEtcdAPIClient = KubeadmCert{
|
||||
Name: "apiserver-etcd-client",
|
||||
LongName: "client apiserver uses to access etcd",
|
||||
BaseName: kubeadmconstants.APIServerEtcdClientCertAndKeyBaseName,
|
||||
CAName: "etcd-ca",
|
||||
config: certutil.Config{
|
||||
CommonName: kubeadmconstants.APIServerEtcdClientCertCommonName,
|
||||
Organization: []string{kubeadmconstants.MastersGroup},
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func makeAltNamesMutator(f func(*kubeadmapi.InitConfiguration) (*certutil.AltNames, error)) configMutatorsFunc {
|
||||
return func(mc *kubeadmapi.InitConfiguration, cc *certutil.Config) error {
|
||||
altNames, err := f(mc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cc.AltNames = *altNames
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func setCommonNameToNodeName() configMutatorsFunc {
|
||||
return func(mc *kubeadmapi.InitConfiguration, cc *certutil.Config) error {
|
||||
cc.CommonName = mc.NodeRegistration.Name
|
||||
return nil
|
||||
}
|
||||
}
|
187
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/certlist_test.go
generated
vendored
Normal file
187
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/certlist_test.go
generated
vendored
Normal file
@ -0,0 +1,187 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package certs
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
certutil "k8s.io/client-go/util/cert"
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
)
|
||||
|
||||
func TestCAPointersValid(t *testing.T) {
|
||||
tests := []struct {
|
||||
certs Certificates
|
||||
name string
|
||||
}{
|
||||
{
|
||||
name: "Default Certificate List",
|
||||
certs: GetDefaultCertList(),
|
||||
},
|
||||
{
|
||||
name: "Cert list less etcd",
|
||||
certs: GetCertsWithoutEtcd(),
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
|
||||
certMap := test.certs.AsMap()
|
||||
|
||||
for _, cert := range test.certs {
|
||||
if cert.CAName != "" && certMap[cert.CAName] == nil {
|
||||
t.Errorf("Certificate %q references nonexistent CA %q", cert.Name, cert.CAName)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMakeCertTree(t *testing.T) {
|
||||
rootCert := &KubeadmCert{
|
||||
Name: "root",
|
||||
}
|
||||
leaf0 := &KubeadmCert{
|
||||
Name: "leaf0",
|
||||
CAName: "root",
|
||||
}
|
||||
leaf1 := &KubeadmCert{
|
||||
Name: "leaf1",
|
||||
CAName: "root",
|
||||
}
|
||||
selfSigned := &KubeadmCert{
|
||||
Name: "self-signed",
|
||||
}
|
||||
|
||||
certMap := CertificateMap{
|
||||
"root": rootCert,
|
||||
"leaf0": leaf0,
|
||||
"leaf1": leaf1,
|
||||
"self-signed": selfSigned,
|
||||
}
|
||||
|
||||
orphanCertMap := CertificateMap{
|
||||
"leaf0": leaf0,
|
||||
}
|
||||
|
||||
if _, err := orphanCertMap.CertTree(); err == nil {
|
||||
t.Error("expected orphan cert map to error, but got nil")
|
||||
}
|
||||
|
||||
certTree, err := certMap.CertTree()
|
||||
t.Logf("cert tree: %v", certTree)
|
||||
if err != nil {
|
||||
t.Errorf("expected no error, but got %v", err)
|
||||
}
|
||||
|
||||
if len(certTree) != 2 {
|
||||
t.Errorf("Expected tree to have 2 roots, got %d", len(certTree))
|
||||
}
|
||||
|
||||
if len(certTree[rootCert]) != 2 {
|
||||
t.Errorf("Expected root to have 2 leaves, got %d", len(certTree[rootCert]))
|
||||
}
|
||||
|
||||
if _, ok := certTree[selfSigned]; !ok {
|
||||
t.Error("Expected selfSigned to be present in tree, but missing")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateCertificateChain(t *testing.T) {
|
||||
dir, err := ioutil.TempDir("", t.Name())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
ic := &kubeadmapi.InitConfiguration{
|
||||
NodeRegistration: kubeadmapi.NodeRegistrationOptions{
|
||||
Name: "test-node",
|
||||
},
|
||||
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
|
||||
CertificatesDir: dir,
|
||||
},
|
||||
}
|
||||
|
||||
caCfg := Certificates{
|
||||
{
|
||||
config: certutil.Config{},
|
||||
Name: "test-ca",
|
||||
BaseName: "test-ca",
|
||||
},
|
||||
{
|
||||
config: certutil.Config{
|
||||
AltNames: certutil.AltNames{
|
||||
DNSNames: []string{"test-domain.space"},
|
||||
},
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
},
|
||||
configMutators: []configMutatorsFunc{
|
||||
setCommonNameToNodeName(),
|
||||
},
|
||||
CAName: "test-ca",
|
||||
Name: "test-daughter",
|
||||
BaseName: "test-daughter",
|
||||
},
|
||||
}
|
||||
|
||||
certTree, err := caCfg.AsMap().CertTree()
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error getting tree: %v", err)
|
||||
}
|
||||
|
||||
if certTree.CreateTree(ic); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
caCert, _ := parseCertAndKey(path.Join(dir, "test-ca"), t)
|
||||
daughterCert, _ := parseCertAndKey(path.Join(dir, "test-daughter"), t)
|
||||
|
||||
pool := x509.NewCertPool()
|
||||
pool.AddCert(caCert)
|
||||
|
||||
_, err = daughterCert.Verify(x509.VerifyOptions{
|
||||
DNSName: "test-domain.space",
|
||||
Roots: pool,
|
||||
KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf("couldn't verify daughter cert: %v", err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func parseCertAndKey(basePath string, t *testing.T) (*x509.Certificate, crypto.PrivateKey) {
|
||||
certPair, err := tls.LoadX509KeyPair(basePath+".crt", basePath+".key")
|
||||
if err != nil {
|
||||
t.Fatalf("couldn't parse certificate and key: %v", err)
|
||||
}
|
||||
|
||||
parsedCert, err := x509.ParseCertificate(certPair.Certificate[0])
|
||||
if err != nil {
|
||||
t.Fatalf("couldn't parse certificate: %v", err)
|
||||
}
|
||||
|
||||
return parsedCert, certPair.PrivateKey
|
||||
}
|
631
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/certs.go
generated
vendored
631
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/certs.go
generated
vendored
@ -23,234 +23,53 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
certutil "k8s.io/client-go/util/cert"
|
||||
"k8s.io/klog"
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/pkiutil"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/util/pkiutil"
|
||||
)
|
||||
|
||||
// CreatePKIAssets will create and write to disk all PKI assets necessary to establish the control plane.
|
||||
// If the PKI assets already exists in the target folder, they are used only if evaluated equal; otherwise an error is returned.
|
||||
func CreatePKIAssets(cfg *kubeadmapi.MasterConfiguration) error {
|
||||
glog.V(1).Infoln("creating PKI assets")
|
||||
certActions := []func(cfg *kubeadmapi.MasterConfiguration) error{
|
||||
CreateCACertAndKeyFiles,
|
||||
CreateAPIServerCertAndKeyFiles,
|
||||
CreateAPIServerKubeletClientCertAndKeyFiles,
|
||||
CreateServiceAccountKeyAndPublicKeyFiles,
|
||||
CreateFrontProxyCACertAndKeyFiles,
|
||||
CreateFrontProxyClientCertAndKeyFiles,
|
||||
}
|
||||
etcdCertActions := []func(cfg *kubeadmapi.MasterConfiguration) error{
|
||||
CreateEtcdCACertAndKeyFiles,
|
||||
CreateEtcdServerCertAndKeyFiles,
|
||||
CreateEtcdPeerCertAndKeyFiles,
|
||||
CreateEtcdHealthcheckClientCertAndKeyFiles,
|
||||
CreateAPIServerEtcdClientCertAndKeyFiles,
|
||||
func CreatePKIAssets(cfg *kubeadmapi.InitConfiguration) error {
|
||||
klog.V(1).Infoln("creating PKI assets")
|
||||
|
||||
// This structure cannot handle multilevel CA hierarchies.
|
||||
// This isn't a problem right now, but may become one in the future.
|
||||
|
||||
var certList Certificates
|
||||
|
||||
if cfg.Etcd.Local == nil {
|
||||
certList = GetCertsWithoutEtcd()
|
||||
} else {
|
||||
certList = GetDefaultCertList()
|
||||
}
|
||||
|
||||
if cfg.Etcd.Local != nil {
|
||||
certActions = append(certActions, etcdCertActions...)
|
||||
certTree, err := certList.AsMap().CertTree()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, action := range certActions {
|
||||
err := action(cfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := certTree.CreateTree(cfg); err != nil {
|
||||
return errors.Wrap(err, "error creating PKI assets")
|
||||
}
|
||||
|
||||
fmt.Printf("[certificates] valid certificates and keys now exist in %q\n", cfg.CertificatesDir)
|
||||
fmt.Printf("[certs] valid certificates and keys now exist in %q\n", cfg.CertificatesDir)
|
||||
|
||||
// Service accounts are not x509 certs, so handled separately
|
||||
if err := CreateServiceAccountKeyAndPublicKeyFiles(cfg); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateCACertAndKeyFiles create a new self signed cluster CA certificate and key files.
|
||||
// If the CA certificate and key files already exists in the target folder, they are used only if evaluated equal; otherwise an error is returned.
|
||||
func CreateCACertAndKeyFiles(cfg *kubeadmapi.MasterConfiguration) error {
|
||||
glog.V(1).Infoln("create a new self signed cluster CA certificate and key files")
|
||||
caCert, caKey, err := NewCACertAndKey()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return writeCertificateAuthorithyFilesIfNotExist(
|
||||
cfg.CertificatesDir,
|
||||
kubeadmconstants.CACertAndKeyBaseName,
|
||||
caCert,
|
||||
caKey,
|
||||
)
|
||||
}
|
||||
|
||||
// CreateAPIServerCertAndKeyFiles create a new certificate and key files for the apiserver.
|
||||
// If the apiserver certificate and key files already exists in the target folder, they are used only if evaluated equal; otherwise an error is returned.
|
||||
// It assumes the cluster CA certificate and key files exist in the CertificatesDir.
|
||||
func CreateAPIServerCertAndKeyFiles(cfg *kubeadmapi.MasterConfiguration) error {
|
||||
glog.V(1).Infoln("creating a new certificate and key files for the apiserver")
|
||||
caCert, caKey, err := loadCertificateAuthority(cfg.CertificatesDir, kubeadmconstants.CACertAndKeyBaseName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
apiCert, apiKey, err := NewAPIServerCertAndKey(cfg, caCert, caKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return writeCertificateFilesIfNotExist(
|
||||
cfg.CertificatesDir,
|
||||
kubeadmconstants.APIServerCertAndKeyBaseName,
|
||||
caCert,
|
||||
apiCert,
|
||||
apiKey,
|
||||
)
|
||||
}
|
||||
|
||||
// CreateAPIServerKubeletClientCertAndKeyFiles create a new certificate for kubelets calling apiserver.
|
||||
// If the apiserver-kubelet-client certificate and key files already exists in the target folder, they are used only if evaluated equals; otherwise an error is returned.
|
||||
// It assumes the cluster CA certificate and key files exist in the CertificatesDir.
|
||||
func CreateAPIServerKubeletClientCertAndKeyFiles(cfg *kubeadmapi.MasterConfiguration) error {
|
||||
glog.V(1).Infoln("creating a new certificate for kubelets calling apiserver")
|
||||
caCert, caKey, err := loadCertificateAuthority(cfg.CertificatesDir, kubeadmconstants.CACertAndKeyBaseName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
apiKubeletClientCert, apiKubeletClientKey, err := NewAPIServerKubeletClientCertAndKey(caCert, caKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return writeCertificateFilesIfNotExist(
|
||||
cfg.CertificatesDir,
|
||||
kubeadmconstants.APIServerKubeletClientCertAndKeyBaseName,
|
||||
caCert,
|
||||
apiKubeletClientCert,
|
||||
apiKubeletClientKey,
|
||||
)
|
||||
}
|
||||
|
||||
// CreateEtcdCACertAndKeyFiles create a self signed etcd CA certificate and key files.
|
||||
// The etcd CA and client certs are used to secure communication between etcd peers and connections to etcd from the API server.
|
||||
// This is a separate CA, so that kubernetes client identities cannot connect to etcd directly or peer with the etcd cluster.
|
||||
// If the etcd CA certificate and key files already exists in the target folder, they are used only if evaluated equals; otherwise an error is returned.
|
||||
func CreateEtcdCACertAndKeyFiles(cfg *kubeadmapi.MasterConfiguration) error {
|
||||
glog.V(1).Infoln("creating a self signed etcd CA certificate and key files")
|
||||
etcdCACert, etcdCAKey, err := NewEtcdCACertAndKey()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return writeCertificateAuthorithyFilesIfNotExist(
|
||||
cfg.CertificatesDir,
|
||||
kubeadmconstants.EtcdCACertAndKeyBaseName,
|
||||
etcdCACert,
|
||||
etcdCAKey,
|
||||
)
|
||||
}
|
||||
|
||||
// CreateEtcdServerCertAndKeyFiles create a new certificate and key file for etcd.
|
||||
// If the etcd serving 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 CreateEtcdServerCertAndKeyFiles(cfg *kubeadmapi.MasterConfiguration) error {
|
||||
glog.V(1).Infoln("creating a new server certificate and key files for etcd")
|
||||
etcdCACert, etcdCAKey, err := loadCertificateAuthority(cfg.CertificatesDir, kubeadmconstants.EtcdCACertAndKeyBaseName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
etcdServerCert, etcdServerKey, err := NewEtcdServerCertAndKey(cfg, etcdCACert, etcdCAKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return writeCertificateFilesIfNotExist(
|
||||
cfg.CertificatesDir,
|
||||
kubeadmconstants.EtcdServerCertAndKeyBaseName,
|
||||
etcdCACert,
|
||||
etcdServerCert,
|
||||
etcdServerKey,
|
||||
)
|
||||
}
|
||||
|
||||
// CreateEtcdPeerCertAndKeyFiles create a new certificate and key file for etcd peering.
|
||||
// If the etcd peer 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 CreateEtcdPeerCertAndKeyFiles(cfg *kubeadmapi.MasterConfiguration) error {
|
||||
glog.V(1).Infoln("creating a new certificate and key files for etcd peering")
|
||||
etcdCACert, etcdCAKey, err := loadCertificateAuthority(cfg.CertificatesDir, kubeadmconstants.EtcdCACertAndKeyBaseName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
etcdPeerCert, etcdPeerKey, err := NewEtcdPeerCertAndKey(cfg, etcdCACert, etcdCAKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return writeCertificateFilesIfNotExist(
|
||||
cfg.CertificatesDir,
|
||||
kubeadmconstants.EtcdPeerCertAndKeyBaseName,
|
||||
etcdCACert,
|
||||
etcdPeerCert,
|
||||
etcdPeerKey,
|
||||
)
|
||||
}
|
||||
|
||||
// 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
|
||||
func CreateAPIServerEtcdClientCertAndKeyFiles(cfg *kubeadmapi.MasterConfiguration) error {
|
||||
glog.V(1).Infoln("creating a new client certificate for the apiserver calling etcd")
|
||||
etcdCACert, etcdCAKey, err := loadCertificateAuthority(cfg.CertificatesDir, kubeadmconstants.EtcdCACertAndKeyBaseName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
apiEtcdClientCert, apiEtcdClientKey, err := NewAPIServerEtcdClientCertAndKey(etcdCACert, etcdCAKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return writeCertificateFilesIfNotExist(
|
||||
cfg.CertificatesDir,
|
||||
kubeadmconstants.APIServerEtcdClientCertAndKeyBaseName,
|
||||
etcdCACert,
|
||||
apiEtcdClientCert,
|
||||
apiEtcdClientKey,
|
||||
)
|
||||
}
|
||||
|
||||
// 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.
|
||||
func CreateServiceAccountKeyAndPublicKeyFiles(cfg *kubeadmapi.MasterConfiguration) error {
|
||||
glog.V(1).Infoln("creating a new public/private key files for signing service account users")
|
||||
func CreateServiceAccountKeyAndPublicKeyFiles(cfg *kubeadmapi.InitConfiguration) error {
|
||||
klog.V(1).Infoln("creating a new public/private key files for signing service account users")
|
||||
saSigningKey, err := NewServiceAccountSigningKey()
|
||||
if err != nil {
|
||||
return err
|
||||
@ -263,237 +82,104 @@ func CreateServiceAccountKeyAndPublicKeyFiles(cfg *kubeadmapi.MasterConfiguratio
|
||||
)
|
||||
}
|
||||
|
||||
// CreateFrontProxyCACertAndKeyFiles create a self signed front proxy CA certificate and key files.
|
||||
// Front proxy CA and client certs are used to secure a front proxy authenticator which is used to assert identity
|
||||
// without the client cert; This is a separate CA, so that front proxy identities cannot hit the API and normal client certs cannot be used
|
||||
// as front proxies.
|
||||
// If the front proxy CA certificate and key files already exists in the target folder, they are used only if evaluated equals; otherwise an error is returned.
|
||||
func CreateFrontProxyCACertAndKeyFiles(cfg *kubeadmapi.MasterConfiguration) error {
|
||||
glog.V(1).Infoln("creating a self signed front proxy CA certificate and key files")
|
||||
frontProxyCACert, frontProxyCAKey, err := NewFrontProxyCACertAndKey()
|
||||
// NewServiceAccountSigningKey generate public/private key pairs for signing service account tokens.
|
||||
func NewServiceAccountSigningKey() (*rsa.PrivateKey, error) {
|
||||
// The key does NOT exist, let's generate it now
|
||||
saSigningKey, err := certutil.NewPrivateKey()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failure while creating service account token signing key")
|
||||
}
|
||||
|
||||
return saSigningKey, nil
|
||||
}
|
||||
|
||||
// NewCACertAndKey will generate a self signed CA.
|
||||
func NewCACertAndKey(certSpec *certutil.Config) (*x509.Certificate, *rsa.PrivateKey, error) {
|
||||
|
||||
caCert, caKey, err := pkiutil.NewCertificateAuthority(certSpec)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "failure while generating CA certificate and key")
|
||||
}
|
||||
|
||||
return caCert, caKey, nil
|
||||
}
|
||||
|
||||
// CreateCACertAndKeyFiles generates and writes out a given certificate authority.
|
||||
// The certSpec should be one of the variables from this package.
|
||||
func CreateCACertAndKeyFiles(certSpec *KubeadmCert, cfg *kubeadmapi.InitConfiguration) error {
|
||||
if certSpec.CAName != "" {
|
||||
return errors.Errorf("this function should only be used for CAs, but cert %s has CA %s", certSpec.Name, certSpec.CAName)
|
||||
}
|
||||
klog.V(1).Infof("creating a new certificate authority for %s", certSpec.Name)
|
||||
|
||||
certConfig, err := certSpec.GetConfig(cfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
caCert, caKey, err := NewCACertAndKey(certConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return writeCertificateAuthorithyFilesIfNotExist(
|
||||
cfg.CertificatesDir,
|
||||
kubeadmconstants.FrontProxyCACertAndKeyBaseName,
|
||||
frontProxyCACert,
|
||||
frontProxyCAKey,
|
||||
certSpec.BaseName,
|
||||
caCert,
|
||||
caKey,
|
||||
)
|
||||
}
|
||||
|
||||
// CreateFrontProxyClientCertAndKeyFiles create a new certificate for proxy server client.
|
||||
// If the front-proxy-client certificate and key files already exists in the target folder, they are used only if evaluated equals; otherwise an error is returned.
|
||||
// It assumes the front proxy CA certificate and key files exist in the CertificatesDir.
|
||||
func CreateFrontProxyClientCertAndKeyFiles(cfg *kubeadmapi.MasterConfiguration) error {
|
||||
glog.V(1).Infoln("creating a new certificate for proxy server client")
|
||||
frontProxyCACert, frontProxyCAKey, err := loadCertificateAuthority(cfg.CertificatesDir, kubeadmconstants.FrontProxyCACertAndKeyBaseName)
|
||||
// NewCSR will generate a new CSR and accompanying key
|
||||
func NewCSR(certSpec *KubeadmCert, cfg *kubeadmapi.InitConfiguration) (*x509.CertificateRequest, *rsa.PrivateKey, error) {
|
||||
certConfig, err := certSpec.GetConfig(cfg)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to retrieve cert configuration: %v", err)
|
||||
}
|
||||
|
||||
return pkiutil.NewCSRAndKey(certConfig)
|
||||
}
|
||||
|
||||
// CreateCSR creates a certificate signing request
|
||||
func CreateCSR(certSpec *KubeadmCert, cfg *kubeadmapi.InitConfiguration, path string) error {
|
||||
csr, key, err := NewCSR(certSpec, cfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
frontProxyClientCert, frontProxyClientKey, err := NewFrontProxyClientCertAndKey(frontProxyCACert, frontProxyCAKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return writeCertificateFilesIfNotExist(
|
||||
cfg.CertificatesDir,
|
||||
kubeadmconstants.FrontProxyClientCertAndKeyBaseName,
|
||||
frontProxyCACert,
|
||||
frontProxyClientCert,
|
||||
frontProxyClientKey,
|
||||
)
|
||||
return writeCSRFilesIfNotExist(path, certSpec.BaseName, csr, key)
|
||||
}
|
||||
|
||||
// NewCACertAndKey will generate a self signed CA.
|
||||
func NewCACertAndKey() (*x509.Certificate, *rsa.PrivateKey, error) {
|
||||
|
||||
caCert, caKey, err := pkiutil.NewCertificateAuthority()
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failure while generating CA certificate and key: %v", err)
|
||||
// CreateCertAndKeyFilesWithCA loads the given certificate authority from disk, then generates and writes out the given certificate and key.
|
||||
// The certSpec and caCertSpec should both be one of the variables from this package.
|
||||
func CreateCertAndKeyFilesWithCA(certSpec *KubeadmCert, caCertSpec *KubeadmCert, cfg *kubeadmapi.InitConfiguration) error {
|
||||
if certSpec.CAName != caCertSpec.Name {
|
||||
return errors.Errorf("expected CAname for %s to be %q, but was %s", certSpec.Name, certSpec.CAName, caCertSpec.Name)
|
||||
}
|
||||
|
||||
return caCert, caKey, nil
|
||||
caCert, caKey, err := LoadCertificateAuthority(cfg.CertificatesDir, caCertSpec.BaseName)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "couldn't load CA certificate %s", caCertSpec.Name)
|
||||
}
|
||||
|
||||
return certSpec.CreateFromCA(cfg, caCert, caKey)
|
||||
}
|
||||
|
||||
// NewAPIServerCertAndKey generate certificate for apiserver, signed by the given CA.
|
||||
func NewAPIServerCertAndKey(cfg *kubeadmapi.MasterConfiguration, caCert *x509.Certificate, caKey *rsa.PrivateKey) (*x509.Certificate, *rsa.PrivateKey, error) {
|
||||
|
||||
altNames, err := pkiutil.GetAPIServerAltNames(cfg)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failure while composing altnames for API server: %v", err)
|
||||
}
|
||||
|
||||
config := certutil.Config{
|
||||
CommonName: kubeadmconstants.APIServerCertCommonName,
|
||||
AltNames: *altNames,
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
||||
}
|
||||
apiCert, apiKey, err := pkiutil.NewCertAndKey(caCert, caKey, config)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failure while creating API server key and certificate: %v", err)
|
||||
}
|
||||
|
||||
return apiCert, apiKey, nil
|
||||
}
|
||||
|
||||
// NewAPIServerKubeletClientCertAndKey generate certificate for the apiservers to connect to the kubelets securely, signed by the given CA.
|
||||
func NewAPIServerKubeletClientCertAndKey(caCert *x509.Certificate, caKey *rsa.PrivateKey) (*x509.Certificate, *rsa.PrivateKey, error) {
|
||||
|
||||
config := certutil.Config{
|
||||
CommonName: kubeadmconstants.APIServerKubeletClientCertCommonName,
|
||||
Organization: []string{kubeadmconstants.MastersGroup},
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
}
|
||||
apiClientCert, apiClientKey, err := pkiutil.NewCertAndKey(caCert, caKey, config)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failure while creating API server kubelet client key and certificate: %v", err)
|
||||
}
|
||||
|
||||
return apiClientCert, apiClientKey, nil
|
||||
}
|
||||
|
||||
// NewEtcdCACertAndKey generate a self signed etcd CA.
|
||||
func NewEtcdCACertAndKey() (*x509.Certificate, *rsa.PrivateKey, error) {
|
||||
|
||||
etcdCACert, etcdCAKey, err := pkiutil.NewCertificateAuthority()
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failure while generating etcd CA certificate and key: %v", err)
|
||||
}
|
||||
|
||||
return etcdCACert, etcdCAKey, nil
|
||||
}
|
||||
|
||||
// NewEtcdServerCertAndKey generate certificate for etcd, signed by the given CA.
|
||||
func NewEtcdServerCertAndKey(cfg *kubeadmapi.MasterConfiguration, caCert *x509.Certificate, caKey *rsa.PrivateKey) (*x509.Certificate, *rsa.PrivateKey, error) {
|
||||
|
||||
altNames, err := pkiutil.GetEtcdAltNames(cfg)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failure while composing altnames for etcd: %v", err)
|
||||
}
|
||||
|
||||
config := certutil.Config{
|
||||
CommonName: cfg.NodeRegistration.Name,
|
||||
AltNames: *altNames,
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
|
||||
}
|
||||
etcdServerCert, etcdServerKey, err := pkiutil.NewCertAndKey(caCert, caKey, config)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failure while creating etcd key and certificate: %v", err)
|
||||
}
|
||||
|
||||
return etcdServerCert, etcdServerKey, nil
|
||||
}
|
||||
|
||||
// NewEtcdPeerCertAndKey generate certificate for etcd peering, signed by the given CA.
|
||||
func NewEtcdPeerCertAndKey(cfg *kubeadmapi.MasterConfiguration, caCert *x509.Certificate, caKey *rsa.PrivateKey) (*x509.Certificate, *rsa.PrivateKey, error) {
|
||||
|
||||
altNames, err := pkiutil.GetEtcdPeerAltNames(cfg)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failure while composing altnames for etcd peering: %v", err)
|
||||
}
|
||||
|
||||
config := certutil.Config{
|
||||
CommonName: cfg.NodeRegistration.Name,
|
||||
AltNames: *altNames,
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
|
||||
}
|
||||
etcdPeerCert, etcdPeerKey, err := pkiutil.NewCertAndKey(caCert, caKey, config)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failure while creating etcd peer key and certificate: %v", err)
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
config := certutil.Config{
|
||||
CommonName: kubeadmconstants.APIServerEtcdClientCertCommonName,
|
||||
Organization: []string{kubeadmconstants.MastersGroup},
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
}
|
||||
apiClientCert, apiClientKey, err := pkiutil.NewCertAndKey(caCert, caKey, config)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failure while creating API server etcd client key and certificate: %v", err)
|
||||
}
|
||||
|
||||
return apiClientCert, apiClientKey, nil
|
||||
}
|
||||
|
||||
// NewServiceAccountSigningKey generate public/private key pairs for signing service account tokens.
|
||||
func NewServiceAccountSigningKey() (*rsa.PrivateKey, error) {
|
||||
|
||||
// The key does NOT exist, let's generate it now
|
||||
saSigningKey, err := certutil.NewPrivateKey()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failure while creating service account token signing key: %v", err)
|
||||
}
|
||||
|
||||
return saSigningKey, nil
|
||||
}
|
||||
|
||||
// NewFrontProxyCACertAndKey generate a self signed front proxy CA.
|
||||
func NewFrontProxyCACertAndKey() (*x509.Certificate, *rsa.PrivateKey, error) {
|
||||
|
||||
frontProxyCACert, frontProxyCAKey, err := pkiutil.NewCertificateAuthority()
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failure while generating front-proxy CA certificate and key: %v", err)
|
||||
}
|
||||
|
||||
return frontProxyCACert, frontProxyCAKey, nil
|
||||
}
|
||||
|
||||
// NewFrontProxyClientCertAndKey generate certificate for proxy server client, signed by the given front proxy CA.
|
||||
func NewFrontProxyClientCertAndKey(frontProxyCACert *x509.Certificate, frontProxyCAKey *rsa.PrivateKey) (*x509.Certificate, *rsa.PrivateKey, error) {
|
||||
|
||||
config := certutil.Config{
|
||||
CommonName: kubeadmconstants.FrontProxyClientCertCommonName,
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
}
|
||||
frontProxyClientCert, frontProxyClientKey, err := pkiutil.NewCertAndKey(frontProxyCACert, frontProxyCAKey, config)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failure while creating front-proxy client key and certificate: %v", err)
|
||||
}
|
||||
|
||||
return frontProxyClientCert, frontProxyClientKey, nil
|
||||
}
|
||||
|
||||
// loadCertificateAuthority loads certificate authority
|
||||
func loadCertificateAuthority(pkiDir string, baseName string) (*x509.Certificate, *rsa.PrivateKey, error) {
|
||||
// LoadCertificateAuthority tries to load a CA in the given directory with the given name.
|
||||
func LoadCertificateAuthority(pkiDir string, baseName string) (*x509.Certificate, *rsa.PrivateKey, error) {
|
||||
// Checks if certificate authority exists in the PKI directory
|
||||
if !pkiutil.CertOrKeyExist(pkiDir, baseName) {
|
||||
return nil, nil, fmt.Errorf("couldn't load %s certificate authority from %s", baseName, pkiDir)
|
||||
return nil, nil, errors.Errorf("couldn't load %s certificate authority from %s", baseName, pkiDir)
|
||||
}
|
||||
|
||||
// Try to load certificate authority .crt and .key from the PKI directory
|
||||
caCert, caKey, err := pkiutil.TryLoadCertAndKeyFromDisk(pkiDir, baseName)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failure loading %s certificate authority: %v", baseName, err)
|
||||
return nil, nil, errors.Wrapf(err, "failure loading %s certificate authority", baseName)
|
||||
}
|
||||
|
||||
// Make sure the loaded CA cert actually is a CA
|
||||
if !caCert.IsCA {
|
||||
return nil, nil, fmt.Errorf("%s certificate is not a certificate authority", baseName)
|
||||
return nil, nil, errors.Errorf("%s certificate is not a certificate authority", baseName)
|
||||
}
|
||||
|
||||
return caCert, caKey, nil
|
||||
@ -501,7 +187,7 @@ func loadCertificateAuthority(pkiDir string, baseName string) (*x509.Certificate
|
||||
|
||||
// writeCertificateAuthorithyFilesIfNotExist write a new certificate Authority to the given path.
|
||||
// If there already is a certificate file at the given path; kubeadm tries to load it and check if the values in the
|
||||
// existing and the expected certificate equals. If they do; kubeadm will just skip writing the file as it's up-to-date,
|
||||
// existing and the eexpected certificate equals. If they do; kubeadm will just skip writing the file as it's up-to-date,
|
||||
// otherwise this function returns an error.
|
||||
func writeCertificateAuthorithyFilesIfNotExist(pkiDir string, baseName string, caCert *x509.Certificate, caKey *rsa.PrivateKey) error {
|
||||
|
||||
@ -511,26 +197,25 @@ func writeCertificateAuthorithyFilesIfNotExist(pkiDir string, baseName string, c
|
||||
// Try to load .crt and .key from the PKI directory
|
||||
caCert, _, err := pkiutil.TryLoadCertAndKeyFromDisk(pkiDir, baseName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failure loading %s certificate: %v", baseName, err)
|
||||
return errors.Wrapf(err, "failure loading %s certificate", baseName)
|
||||
}
|
||||
|
||||
// Check if the existing cert is a CA
|
||||
if !caCert.IsCA {
|
||||
return fmt.Errorf("certificate %s is not a CA", baseName)
|
||||
return errors.Errorf("certificate %s is not a CA", baseName)
|
||||
}
|
||||
|
||||
// kubeadm doesn't validate the existing certificate Authority more than this;
|
||||
// Basically, if we find a certificate file with the same path; and it is a CA
|
||||
// kubeadm thinks those files are equal and doesn't bother writing a new file
|
||||
fmt.Printf("[certificates] Using the existing %s certificate and key.\n", baseName)
|
||||
fmt.Printf("[certs] Using the existing %q certificate and key\n", baseName)
|
||||
} else {
|
||||
|
||||
// Write .crt and .key files to disk
|
||||
if err := pkiutil.WriteCertAndKey(pkiDir, baseName, caCert, caKey); err != nil {
|
||||
return fmt.Errorf("failure while saving %s certificate and key: %v", baseName, err)
|
||||
}
|
||||
fmt.Printf("[certs] Generating %q certificate and key\n", baseName)
|
||||
|
||||
fmt.Printf("[certificates] Generated %s certificate and key.\n", baseName)
|
||||
if err := pkiutil.WriteCertAndKey(pkiDir, baseName, caCert, caKey); err != nil {
|
||||
return errors.Wrapf(err, "failure while saving %s certificate and key", baseName)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -546,29 +231,28 @@ func writeCertificateFilesIfNotExist(pkiDir string, baseName string, signingCert
|
||||
// Try to load signed certificate .crt and .key from the PKI directory
|
||||
signedCert, _, err := pkiutil.TryLoadCertAndKeyFromDisk(pkiDir, baseName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failure loading %s certificate: %v", baseName, err)
|
||||
return errors.Wrapf(err, "failure loading %s certificate", baseName)
|
||||
}
|
||||
|
||||
// Check if the existing cert is signed by the given CA
|
||||
if err := signedCert.CheckSignatureFrom(signingCert); err != nil {
|
||||
return fmt.Errorf("certificate %s is not signed by corresponding CA", baseName)
|
||||
return errors.Errorf("certificate %s is not signed by corresponding CA", baseName)
|
||||
}
|
||||
|
||||
// kubeadm doesn't validate the existing certificate more than this;
|
||||
// Basically, if we find a certificate file with the same path; and it is signed by
|
||||
// the expected certificate authority, kubeadm thinks those files are equal and
|
||||
// doesn't bother writing a new file
|
||||
fmt.Printf("[certificates] Using the existing %s certificate and key.\n", baseName)
|
||||
fmt.Printf("[certs] Using the existing %q certificate and key\n", baseName)
|
||||
} else {
|
||||
|
||||
// Write .crt and .key files to disk
|
||||
if err := pkiutil.WriteCertAndKey(pkiDir, baseName, cert, key); err != nil {
|
||||
return fmt.Errorf("failure while saving %s certificate and key: %v", baseName, err)
|
||||
}
|
||||
fmt.Printf("[certs] Generating %q certificate and key\n", baseName)
|
||||
|
||||
fmt.Printf("[certificates] Generated %s certificate and key.\n", baseName)
|
||||
if err := pkiutil.WriteCertAndKey(pkiDir, baseName, cert, key); err != nil {
|
||||
return errors.Wrapf(err, "failure while saving %s certificate and key", baseName)
|
||||
}
|
||||
if pkiutil.HasServerAuth(cert) {
|
||||
fmt.Printf("[certificates] %s serving cert is signed for DNS names %v and IPs %v\n", baseName, cert.DNSNames, cert.IPAddresses)
|
||||
fmt.Printf("[certs] %s serving cert is signed for DNS names %v and IPs %v\n", baseName, cert.DNSNames, cert.IPAddresses)
|
||||
}
|
||||
}
|
||||
|
||||
@ -587,24 +271,52 @@ func writeKeyFilesIfNotExist(pkiDir string, baseName string, key *rsa.PrivateKey
|
||||
// Try to load .key from the PKI directory
|
||||
_, err := pkiutil.TryLoadKeyFromDisk(pkiDir, baseName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s key existed but it could not be loaded properly: %v", baseName, err)
|
||||
return errors.Wrapf(err, "%s key existed but it could not be loaded properly", baseName)
|
||||
}
|
||||
|
||||
// kubeadm doesn't validate the existing certificate key more than this;
|
||||
// Basically, if we find a key file with the same path kubeadm thinks those files
|
||||
// are equal and doesn't bother writing a new file
|
||||
fmt.Printf("[certificates] Using the existing %s key.\n", baseName)
|
||||
fmt.Printf("[certs] Using the existing %q key\n", baseName)
|
||||
} else {
|
||||
|
||||
// Write .key and .pub files to disk
|
||||
fmt.Printf("[certs] Generating %q key and public key\n", baseName)
|
||||
|
||||
if err := pkiutil.WriteKey(pkiDir, baseName, key); err != nil {
|
||||
return fmt.Errorf("failure while saving %s key: %v", baseName, err)
|
||||
return errors.Wrapf(err, "failure while saving %s key", baseName)
|
||||
}
|
||||
|
||||
if err := pkiutil.WritePublicKey(pkiDir, baseName, &key.PublicKey); err != nil {
|
||||
return fmt.Errorf("failure while saving %s public key: %v", baseName, err)
|
||||
return errors.Wrapf(err, "failure while saving %s public key", baseName)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// writeCertificateAuthorithyFilesIfNotExist write a new CSR to the given path.
|
||||
// If there already is a CSR file at the given path; kubeadm tries to load it and check if it's a valid certificate.
|
||||
// otherwise this function returns an error.
|
||||
func writeCSRFilesIfNotExist(csrDir string, baseName string, csr *x509.CertificateRequest, key *rsa.PrivateKey) error {
|
||||
if pkiutil.CSROrKeyExist(csrDir, baseName) {
|
||||
_, _, err := pkiutil.TryLoadCSRAndKeyFromDisk(csrDir, baseName)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "%s CSR existed but it could not be loaded properly", baseName)
|
||||
}
|
||||
|
||||
fmt.Printf("[certs] Using the existing %q CSR\n", baseName)
|
||||
} else {
|
||||
// Write .key and .csr files to disk
|
||||
fmt.Printf("[certs] Generating %q key and CSR\n", baseName)
|
||||
|
||||
if err := pkiutil.WriteKey(csrDir, baseName, key); err != nil {
|
||||
return errors.Wrapf(err, "failure while saving %s key", baseName)
|
||||
}
|
||||
|
||||
if err := pkiutil.WriteCSR(csrDir, baseName, csr); err != nil {
|
||||
return errors.Wrapf(err, "failure while saving %s CSR", baseName)
|
||||
}
|
||||
fmt.Printf("[certificates] Generated %s key and public key.\n", baseName)
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -617,10 +329,36 @@ type certKeyLocation struct {
|
||||
uxName string
|
||||
}
|
||||
|
||||
// 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
|
||||
func SharedCertificateExists(cfg *kubeadmapi.InitConfiguration) (bool, error) {
|
||||
|
||||
if err := validateCACertAndKey(certKeyLocation{cfg.CertificatesDir, kubeadmconstants.CACertAndKeyBaseName, "", "CA"}); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if err := validatePrivatePublicKey(certKeyLocation{cfg.CertificatesDir, "", kubeadmconstants.ServiceAccountKeyBaseName, "service account"}); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if err := validateCACertAndKey(certKeyLocation{cfg.CertificatesDir, kubeadmconstants.FrontProxyCACertAndKeyBaseName, "", "front-proxy CA"}); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// in case of local/stacked etcd
|
||||
if cfg.Etcd.External == nil {
|
||||
if err := validateCACertAndKey(certKeyLocation{cfg.CertificatesDir, kubeadmconstants.EtcdCACertAndKeyBaseName, "", "etcd CA"}); err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// 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.
|
||||
// This allows us to, e.g., skip generating certs or not start the csr signing controller.
|
||||
func UsingExternalCA(cfg *kubeadmapi.MasterConfiguration) (bool, error) {
|
||||
func UsingExternalCA(cfg *kubeadmapi.InitConfiguration) (bool, error) {
|
||||
|
||||
if err := validateCACert(certKeyLocation{cfg.CertificatesDir, kubeadmconstants.CACertAndKeyBaseName, "", "CA"}); err != nil {
|
||||
return false, err
|
||||
@ -628,7 +366,7 @@ func UsingExternalCA(cfg *kubeadmapi.MasterConfiguration) (bool, error) {
|
||||
|
||||
caKeyPath := filepath.Join(cfg.CertificatesDir, kubeadmconstants.CAKeyName)
|
||||
if _, err := os.Stat(caKeyPath); !os.IsNotExist(err) {
|
||||
return false, fmt.Errorf("%s exists", kubeadmconstants.CAKeyName)
|
||||
return false, errors.Errorf("%s exists", kubeadmconstants.CAKeyName)
|
||||
}
|
||||
|
||||
if err := validateSignedCert(certKeyLocation{cfg.CertificatesDir, kubeadmconstants.CACertAndKeyBaseName, kubeadmconstants.APIServerCertAndKeyBaseName, "API server"}); err != nil {
|
||||
@ -649,7 +387,7 @@ func UsingExternalCA(cfg *kubeadmapi.MasterConfiguration) (bool, error) {
|
||||
|
||||
frontProxyCAKeyPath := filepath.Join(cfg.CertificatesDir, kubeadmconstants.FrontProxyCAKeyName)
|
||||
if _, err := os.Stat(frontProxyCAKeyPath); !os.IsNotExist(err) {
|
||||
return false, fmt.Errorf("%s exists", kubeadmconstants.FrontProxyCAKeyName)
|
||||
return false, errors.Errorf("%s exists", kubeadmconstants.FrontProxyCAKeyName)
|
||||
}
|
||||
|
||||
if err := validateSignedCert(certKeyLocation{cfg.CertificatesDir, kubeadmconstants.FrontProxyCACertAndKeyBaseName, kubeadmconstants.FrontProxyClientCertAndKeyBaseName, "front-proxy client"}); err != nil {
|
||||
@ -664,12 +402,12 @@ func validateCACert(l certKeyLocation) error {
|
||||
// Check CA Cert
|
||||
caCert, err := pkiutil.TryLoadCertFromDisk(l.pkiDir, l.caBaseName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failure loading certificate for %s: %v", l.uxName, err)
|
||||
return errors.Wrapf(err, "failure loading certificate for %s", l.uxName)
|
||||
}
|
||||
|
||||
// Check if cert is a CA
|
||||
if !caCert.IsCA {
|
||||
return fmt.Errorf("certificate %s is not a CA", l.uxName)
|
||||
return errors.Errorf("certificate %s is not a CA", l.uxName)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -683,7 +421,7 @@ func validateCACertAndKey(l certKeyLocation) error {
|
||||
|
||||
_, err := pkiutil.TryLoadKeyFromDisk(l.pkiDir, l.caBaseName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failure loading key for %s: %v", l.uxName, err)
|
||||
return errors.Wrapf(err, "failure loading key for %s", l.uxName)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -694,18 +432,23 @@ func validateSignedCert(l certKeyLocation) error {
|
||||
// Try to load CA
|
||||
caCert, err := pkiutil.TryLoadCertFromDisk(l.pkiDir, l.caBaseName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failure loading certificate authority for %s: %v", l.uxName, err)
|
||||
return errors.Wrapf(err, "failure loading certificate authority for %s", l.uxName)
|
||||
}
|
||||
|
||||
return validateSignedCertWithCA(l, caCert)
|
||||
}
|
||||
|
||||
// validateSignedCertWithCA tries to load a certificate and validate it with the given caCert
|
||||
func validateSignedCertWithCA(l certKeyLocation, caCert *x509.Certificate) error {
|
||||
// Try to load key and signed certificate
|
||||
signedCert, _, err := pkiutil.TryLoadCertAndKeyFromDisk(l.pkiDir, l.baseName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failure loading certificate for %s: %v", l.uxName, err)
|
||||
return errors.Wrapf(err, "failure loading certificate for %s", l.uxName)
|
||||
}
|
||||
|
||||
// Check if the cert is signed by the CA
|
||||
if err := signedCert.CheckSignatureFrom(caCert); err != nil {
|
||||
return fmt.Errorf("certificate %s is not signed by corresponding CA", l.uxName)
|
||||
return errors.Wrapf(err, "certificate %s is not signed by corresponding CA", l.uxName)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -715,7 +458,7 @@ func validatePrivatePublicKey(l certKeyLocation) error {
|
||||
// Try to load key
|
||||
_, _, err := pkiutil.TryLoadPrivatePublicKeyFromDisk(l.pkiDir, l.baseName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failure loading key for %s: %v", l.uxName, err)
|
||||
return errors.Wrapf(err, "failure loading key for %s", l.uxName)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
625
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/certs_test.go
generated
vendored
625
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/certs_test.go
generated
vendored
@ -18,24 +18,40 @@ package certs
|
||||
|
||||
import (
|
||||
"crypto/rsa"
|
||||
"crypto/sha256"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"net"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
certutil "k8s.io/client-go/util/cert"
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/pkiutil"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/util/pkiutil"
|
||||
testutil "k8s.io/kubernetes/cmd/kubeadm/test"
|
||||
certstestutil "k8s.io/kubernetes/cmd/kubeadm/test/certs"
|
||||
)
|
||||
|
||||
func TestWriteCertificateAuthorithyFilesIfNotExist(t *testing.T) {
|
||||
func createTestCSR(t *testing.T) (*x509.CertificateRequest, *rsa.PrivateKey) {
|
||||
csr, key, err := pkiutil.NewCSRAndKey(
|
||||
&certutil.Config{
|
||||
CommonName: "testCert",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("couldn't create test cert: %v", err)
|
||||
}
|
||||
|
||||
setupCert, setupKey, _ := NewCACertAndKey()
|
||||
caCert, caKey, _ := NewCACertAndKey()
|
||||
return csr, key
|
||||
}
|
||||
|
||||
func TestWriteCertificateAuthorithyFilesIfNotExist(t *testing.T) {
|
||||
setupCert, setupKey := certstestutil.CreateCACert(t)
|
||||
caCert, caKey := certstestutil.CreateCACert(t)
|
||||
|
||||
var tests = []struct {
|
||||
setupFunc func(pkiDir string) error
|
||||
@ -60,7 +76,7 @@ func TestWriteCertificateAuthorithyFilesIfNotExist(t *testing.T) {
|
||||
},
|
||||
{ // cert exists, but it is not a ca > err
|
||||
setupFunc: func(pkiDir string) error {
|
||||
cert, key, _ := NewFrontProxyClientCertAndKey(setupCert, setupKey)
|
||||
cert, key := certstestutil.CreateTestCert(t, setupCert, setupKey)
|
||||
return writeCertificateFilesIfNotExist(pkiDir, "dummy", setupCert, cert, key)
|
||||
},
|
||||
expectedError: true,
|
||||
@ -110,9 +126,9 @@ func TestWriteCertificateAuthorithyFilesIfNotExist(t *testing.T) {
|
||||
|
||||
func TestWriteCertificateFilesIfNotExist(t *testing.T) {
|
||||
|
||||
caCert, caKey, _ := NewFrontProxyCACertAndKey()
|
||||
setupCert, setupKey, _ := NewFrontProxyClientCertAndKey(caCert, caKey)
|
||||
cert, key, _ := NewFrontProxyClientCertAndKey(caCert, caKey)
|
||||
caCert, caKey := certstestutil.CreateCACert(t)
|
||||
setupCert, setupKey := certstestutil.CreateTestCert(t, caCert, caKey)
|
||||
cert, key := certstestutil.CreateTestCert(t, caCert, caKey)
|
||||
|
||||
var tests = []struct {
|
||||
setupFunc func(pkiDir string) error
|
||||
@ -137,8 +153,8 @@ func TestWriteCertificateFilesIfNotExist(t *testing.T) {
|
||||
},
|
||||
{ // cert exists, is signed by another ca > err
|
||||
setupFunc: func(pkiDir string) error {
|
||||
anotherCaCert, anotherCaKey, _ := NewFrontProxyCACertAndKey()
|
||||
anotherCert, anotherKey, _ := NewFrontProxyClientCertAndKey(anotherCaCert, anotherCaKey)
|
||||
anotherCaCert, anotherCaKey := certstestutil.CreateCACert(t)
|
||||
anotherCert, anotherKey := certstestutil.CreateTestCert(t, anotherCaCert, anotherCaKey)
|
||||
|
||||
return writeCertificateFilesIfNotExist(pkiDir, "dummy", anotherCaCert, anotherCert, anotherKey)
|
||||
},
|
||||
@ -187,6 +203,75 @@ func TestWriteCertificateFilesIfNotExist(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestWriteCSRFilesIfNotExist(t *testing.T) {
|
||||
csr, key := createTestCSR(t)
|
||||
csr2, key2 := createTestCSR(t)
|
||||
|
||||
var tests = []struct {
|
||||
name string
|
||||
setupFunc func(csrPath string) error
|
||||
expectedError bool
|
||||
expectedCSR *x509.CertificateRequest
|
||||
}{
|
||||
{
|
||||
name: "no files exist",
|
||||
expectedCSR: csr,
|
||||
},
|
||||
{
|
||||
name: "other key exists",
|
||||
setupFunc: func(csrPath string) error {
|
||||
if err := pkiutil.WriteCSR(csrPath, "dummy", csr2); err != nil {
|
||||
return err
|
||||
}
|
||||
return pkiutil.WriteKey(csrPath, "dummy", key2)
|
||||
},
|
||||
expectedCSR: csr2,
|
||||
},
|
||||
{
|
||||
name: "existing CSR is garbage",
|
||||
setupFunc: func(csrPath string) error {
|
||||
return ioutil.WriteFile(path.Join(csrPath, "dummy.csr"), []byte("a--bunch--of-garbage"), os.ModePerm)
|
||||
},
|
||||
expectedError: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
tmpdir := testutil.SetupTempDir(t)
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
if test.setupFunc != nil {
|
||||
if err := test.setupFunc(tmpdir); err != nil {
|
||||
t.Fatalf("couldn't set up test: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := writeCSRFilesIfNotExist(tmpdir, "dummy", csr, key); err != nil {
|
||||
if test.expectedError {
|
||||
return
|
||||
}
|
||||
t.Fatalf("unexpected error %v: ", err)
|
||||
}
|
||||
|
||||
if test.expectedError {
|
||||
t.Fatal("Expected error, but got none")
|
||||
}
|
||||
|
||||
parsedCSR, _, err := pkiutil.TryLoadCSRAndKeyFromDisk(tmpdir, "dummy")
|
||||
if err != nil {
|
||||
t.Fatalf("couldn't load csr and key: %v", err)
|
||||
}
|
||||
|
||||
if sha256.Sum256(test.expectedCSR.Raw) != sha256.Sum256(parsedCSR.Raw) {
|
||||
t.Error("expected csr's fingerprint does not match ")
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestWriteKeyFilesIfNotExist(t *testing.T) {
|
||||
|
||||
setupKey, _ := NewServiceAccountSigningKey()
|
||||
@ -259,7 +344,8 @@ func TestWriteKeyFilesIfNotExist(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestNewCACertAndKey(t *testing.T) {
|
||||
caCert, _, err := NewCACertAndKey()
|
||||
certCfg := &certutil.Config{CommonName: "kubernetes"}
|
||||
caCert, _, err := NewCACertAndKey(certCfg)
|
||||
if err != nil {
|
||||
t.Fatalf("failed call NewCACertAndKey: %v", err)
|
||||
}
|
||||
@ -267,210 +353,153 @@ func TestNewCACertAndKey(t *testing.T) {
|
||||
certstestutil.AssertCertificateIsCa(t, caCert)
|
||||
}
|
||||
|
||||
func TestNewAPIServerCertAndKey(t *testing.T) {
|
||||
hostname := "valid-hostname"
|
||||
func TestSharedCertificateExists(t *testing.T) {
|
||||
caCert, caKey := certstestutil.CreateCACert(t)
|
||||
_, key := certstestutil.CreateTestCert(t, caCert, caKey)
|
||||
publicKey := &key.PublicKey
|
||||
|
||||
advertiseAddresses := []string{"1.2.3.4", "1:2:3::4"}
|
||||
for _, addr := range advertiseAddresses {
|
||||
cfg := &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadmapi.API{AdvertiseAddress: addr},
|
||||
Networking: kubeadmapi.Networking{ServiceSubnet: "10.96.0.0/12", DNSDomain: "cluster.local"},
|
||||
NodeRegistration: kubeadmapi.NodeRegistrationOptions{Name: hostname},
|
||||
}
|
||||
caCert, caKey, err := NewCACertAndKey()
|
||||
if err != nil {
|
||||
t.Fatalf("failed creation of ca cert and key: %v", err)
|
||||
}
|
||||
|
||||
apiServerCert, _, err := NewAPIServerCertAndKey(cfg, caCert, caKey)
|
||||
if err != nil {
|
||||
t.Fatalf("failed creation of cert and key: %v", err)
|
||||
}
|
||||
|
||||
certstestutil.AssertCertificateIsSignedByCa(t, apiServerCert, caCert)
|
||||
certstestutil.AssertCertificateHasServerAuthUsage(t, apiServerCert)
|
||||
certstestutil.AssertCertificateHasDNSNames(t, apiServerCert, hostname, "kubernetes", "kubernetes.default", "kubernetes.default.svc", "kubernetes.default.svc.cluster.local")
|
||||
certstestutil.AssertCertificateHasIPAddresses(t, apiServerCert, net.ParseIP("10.96.0.1"), net.ParseIP(addr))
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewAPIServerKubeletClientCertAndKey(t *testing.T) {
|
||||
caCert, caKey, err := NewCACertAndKey()
|
||||
if err != nil {
|
||||
t.Fatalf("failed creation of ca cert and key: %v", err)
|
||||
}
|
||||
|
||||
apiKubeletClientCert, _, err := NewAPIServerKubeletClientCertAndKey(caCert, caKey)
|
||||
if err != nil {
|
||||
t.Fatalf("failed creation of cert and key: %v", err)
|
||||
}
|
||||
|
||||
certstestutil.AssertCertificateIsSignedByCa(t, apiKubeletClientCert, caCert)
|
||||
certstestutil.AssertCertificateHasClientAuthUsage(t, apiKubeletClientCert)
|
||||
certstestutil.AssertCertificateHasOrganizations(t, apiKubeletClientCert, kubeadmconstants.MastersGroup)
|
||||
}
|
||||
|
||||
func TestNewEtcdCACertAndKey(t *testing.T) {
|
||||
etcdCACert, _, err := NewEtcdCACertAndKey()
|
||||
if err != nil {
|
||||
t.Fatalf("failed creation of cert and key: %v", err)
|
||||
}
|
||||
|
||||
certstestutil.AssertCertificateIsCa(t, etcdCACert)
|
||||
}
|
||||
|
||||
func TestNewEtcdServerCertAndKey(t *testing.T) {
|
||||
proxy := "user-etcd-proxy"
|
||||
proxyIP := "10.10.10.100"
|
||||
|
||||
cfg := &kubeadmapi.MasterConfiguration{
|
||||
NodeRegistration: kubeadmapi.NodeRegistrationOptions{
|
||||
Name: "etcd-server-cert",
|
||||
},
|
||||
Etcd: kubeadmapi.Etcd{
|
||||
Local: &kubeadmapi.LocalEtcd{
|
||||
ServerCertSANs: []string{
|
||||
proxy,
|
||||
proxyIP,
|
||||
},
|
||||
var tests = []struct {
|
||||
name string
|
||||
files certstestutil.PKIFiles
|
||||
expectedError bool
|
||||
}{
|
||||
{
|
||||
name: "success",
|
||||
files: certstestutil.PKIFiles{
|
||||
"ca.crt": caCert,
|
||||
"ca.key": caKey,
|
||||
"front-proxy-ca.crt": caCert,
|
||||
"front-proxy-ca.key": caKey,
|
||||
"sa.pub": publicKey,
|
||||
"sa.key": key,
|
||||
"etcd/ca.crt": caCert,
|
||||
"etcd/ca.key": caKey,
|
||||
},
|
||||
},
|
||||
}
|
||||
caCert, caKey, err := NewCACertAndKey()
|
||||
if err != nil {
|
||||
t.Fatalf("failed creation of ca cert and key: %v", err)
|
||||
}
|
||||
|
||||
etcdServerCert, _, err := NewEtcdServerCertAndKey(cfg, caCert, caKey)
|
||||
if err != nil {
|
||||
t.Fatalf("failed creation of cert and key: %v", err)
|
||||
}
|
||||
|
||||
certstestutil.AssertCertificateIsSignedByCa(t, etcdServerCert, caCert)
|
||||
certstestutil.AssertCertificateHasServerAuthUsage(t, etcdServerCert)
|
||||
certstestutil.AssertCertificateHasDNSNames(t, etcdServerCert, "localhost", proxy)
|
||||
certstestutil.AssertCertificateHasIPAddresses(t, etcdServerCert, net.ParseIP("127.0.0.1"), net.ParseIP(proxyIP))
|
||||
}
|
||||
|
||||
func TestNewEtcdPeerCertAndKey(t *testing.T) {
|
||||
hostname := "valid-hostname"
|
||||
proxy := "user-etcd-proxy"
|
||||
proxyIP := "10.10.10.100"
|
||||
|
||||
advertiseAddresses := []string{"1.2.3.4", "1:2:3::4"}
|
||||
for _, addr := range advertiseAddresses {
|
||||
cfg := &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadmapi.API{AdvertiseAddress: addr},
|
||||
NodeRegistration: kubeadmapi.NodeRegistrationOptions{Name: hostname},
|
||||
Etcd: kubeadmapi.Etcd{
|
||||
Local: &kubeadmapi.LocalEtcd{
|
||||
PeerCertSANs: []string{
|
||||
proxy,
|
||||
proxyIP,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "missing ca.crt",
|
||||
files: certstestutil.PKIFiles{
|
||||
"ca.key": caKey,
|
||||
"front-proxy-ca.crt": caCert,
|
||||
"front-proxy-ca.key": caKey,
|
||||
"sa.pub": publicKey,
|
||||
"sa.key": key,
|
||||
"etcd/ca.crt": caCert,
|
||||
"etcd/ca.key": caKey,
|
||||
},
|
||||
}
|
||||
caCert, caKey, err := NewCACertAndKey()
|
||||
if err != nil {
|
||||
t.Fatalf("failed creation of ca cert and key: %v", err)
|
||||
}
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
name: "missing sa.key",
|
||||
files: certstestutil.PKIFiles{
|
||||
"ca.crt": caCert,
|
||||
"ca.key": caKey,
|
||||
"front-proxy-ca.crt": caCert,
|
||||
"front-proxy-ca.key": caKey,
|
||||
"sa.pub": publicKey,
|
||||
"etcd/ca.crt": caCert,
|
||||
"etcd/ca.key": caKey,
|
||||
},
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
name: "missing front-proxy.crt",
|
||||
files: certstestutil.PKIFiles{
|
||||
"ca.crt": caCert,
|
||||
"ca.key": caKey,
|
||||
"front-proxy-ca.key": caKey,
|
||||
"sa.pub": publicKey,
|
||||
"sa.key": key,
|
||||
"etcd/ca.crt": caCert,
|
||||
"etcd/ca.key": caKey,
|
||||
},
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
name: "missing etcd/ca.crt",
|
||||
files: certstestutil.PKIFiles{
|
||||
"ca.crt": caCert,
|
||||
"ca.key": caKey,
|
||||
"front-proxy-ca.key": caKey,
|
||||
"sa.pub": publicKey,
|
||||
"sa.key": key,
|
||||
"etcd/ca.crt": caCert,
|
||||
"etcd/ca.key": caKey,
|
||||
},
|
||||
expectedError: true,
|
||||
},
|
||||
}
|
||||
|
||||
etcdPeerCert, _, err := NewEtcdPeerCertAndKey(cfg, caCert, caKey)
|
||||
if err != nil {
|
||||
t.Fatalf("failed creation of cert and key: %v", err)
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run("", func(t *testing.T) {
|
||||
tmpdir := testutil.SetupTempDir(t)
|
||||
os.MkdirAll(tmpdir+"/etcd", os.ModePerm)
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
certstestutil.AssertCertificateIsSignedByCa(t, etcdPeerCert, caCert)
|
||||
certstestutil.AssertCertificateHasServerAuthUsage(t, etcdPeerCert)
|
||||
certstestutil.AssertCertificateHasClientAuthUsage(t, etcdPeerCert)
|
||||
certstestutil.AssertCertificateHasDNSNames(t, etcdPeerCert, hostname, proxy)
|
||||
certstestutil.AssertCertificateHasIPAddresses(t, etcdPeerCert, net.ParseIP(addr), net.ParseIP(proxyIP))
|
||||
cfg := &kubeadmapi.InitConfiguration{
|
||||
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
|
||||
CertificatesDir: tmpdir,
|
||||
},
|
||||
}
|
||||
|
||||
// created expected keys
|
||||
certstestutil.WritePKIFiles(t, tmpdir, test.files)
|
||||
|
||||
// executes create func
|
||||
ret, err := SharedCertificateExists(cfg)
|
||||
|
||||
switch {
|
||||
case !test.expectedError && err != nil:
|
||||
t.Errorf("error SharedCertificateExists failed when not expected to fail: %v", err)
|
||||
case test.expectedError && err == nil:
|
||||
t.Errorf("error SharedCertificateExists didn't failed when expected")
|
||||
case ret != (err == nil):
|
||||
t.Errorf("error SharedCertificateExists returned %v when expected to return %v", ret, err == nil)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewEtcdHealthcheckClientCertAndKey(t *testing.T) {
|
||||
caCert, caKey, err := NewCACertAndKey()
|
||||
if err != nil {
|
||||
t.Fatalf("failed creation of ca cert and key: %v", err)
|
||||
func TestCreatePKIAssetsWithSparseCerts(t *testing.T) {
|
||||
for _, test := range certstestutil.GetSparseCertTestCases(t) {
|
||||
t.Run(test.Name, func(t *testing.T) {
|
||||
tmpdir := testutil.SetupTempDir(t)
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
cfg := testutil.GetDefaultInternalConfig(t)
|
||||
cfg.ClusterConfiguration.CertificatesDir = tmpdir
|
||||
|
||||
certstestutil.WritePKIFiles(t, tmpdir, test.Files)
|
||||
|
||||
err := CreatePKIAssets(cfg)
|
||||
if err != nil {
|
||||
if test.ExpectError {
|
||||
return
|
||||
}
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
if test.ExpectError {
|
||||
t.Fatal("Expected error from CreatePKIAssets, got none")
|
||||
}
|
||||
assertCertsExist(t, tmpdir)
|
||||
})
|
||||
}
|
||||
|
||||
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 {
|
||||
t.Fatalf("failed creation of ca cert and key: %v", err)
|
||||
}
|
||||
|
||||
apiEtcdClientCert, _, err := NewAPIServerEtcdClientCertAndKey(caCert, caKey)
|
||||
if err != nil {
|
||||
t.Fatalf("failed creation of cert and key: %v", err)
|
||||
}
|
||||
|
||||
certstestutil.AssertCertificateIsSignedByCa(t, apiEtcdClientCert, caCert)
|
||||
certstestutil.AssertCertificateHasClientAuthUsage(t, apiEtcdClientCert)
|
||||
certstestutil.AssertCertificateHasOrganizations(t, apiEtcdClientCert, kubeadmconstants.MastersGroup)
|
||||
}
|
||||
|
||||
func TestNewNewServiceAccountSigningKey(t *testing.T) {
|
||||
|
||||
key, err := NewServiceAccountSigningKey()
|
||||
if err != nil {
|
||||
t.Fatalf("failed creation of key: %v", err)
|
||||
}
|
||||
|
||||
if key.N.BitLen() < 2048 {
|
||||
t.Error("Service account signing key has less than 2048 bits size")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewFrontProxyCACertAndKey(t *testing.T) {
|
||||
frontProxyCACert, _, err := NewFrontProxyCACertAndKey()
|
||||
if err != nil {
|
||||
t.Fatalf("failed creation of cert and key: %v", err)
|
||||
}
|
||||
|
||||
certstestutil.AssertCertificateIsCa(t, frontProxyCACert)
|
||||
}
|
||||
|
||||
func TestNewFrontProxyClientCertAndKey(t *testing.T) {
|
||||
frontProxyCACert, frontProxyCAKey, err := NewFrontProxyCACertAndKey()
|
||||
if err != nil {
|
||||
t.Fatalf("failed creation of ca cert and key: %v", err)
|
||||
}
|
||||
|
||||
frontProxyClientCert, _, err := NewFrontProxyClientCertAndKey(frontProxyCACert, frontProxyCAKey)
|
||||
if err != nil {
|
||||
t.Fatalf("failed creation of cert and key: %v", err)
|
||||
}
|
||||
|
||||
certstestutil.AssertCertificateIsSignedByCa(t, frontProxyClientCert, frontProxyCACert)
|
||||
certstestutil.AssertCertificateHasClientAuthUsage(t, frontProxyClientCert)
|
||||
}
|
||||
|
||||
func TestUsingExternalCA(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
setupFuncs []func(cfg *kubeadmapi.MasterConfiguration) error
|
||||
setupFuncs []func(cfg *kubeadmapi.InitConfiguration) error
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
setupFuncs: []func(cfg *kubeadmapi.MasterConfiguration) error{
|
||||
setupFuncs: []func(cfg *kubeadmapi.InitConfiguration) error{
|
||||
CreatePKIAssets,
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
setupFuncs: []func(cfg *kubeadmapi.MasterConfiguration) error{
|
||||
setupFuncs: []func(cfg *kubeadmapi.InitConfiguration) error{
|
||||
CreatePKIAssets,
|
||||
deleteCAKey,
|
||||
deleteFrontProxyCAKey,
|
||||
@ -483,11 +512,13 @@ func TestUsingExternalCA(t *testing.T) {
|
||||
dir := testutil.SetupTempDir(t)
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
cfg := &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadmapi.API{AdvertiseAddress: "1.2.3.4"},
|
||||
Networking: kubeadmapi.Networking{ServiceSubnet: "10.96.0.0/12", DNSDomain: "cluster.local"},
|
||||
cfg := &kubeadmapi.InitConfiguration{
|
||||
LocalAPIEndpoint: kubeadmapi.APIEndpoint{AdvertiseAddress: "1.2.3.4"},
|
||||
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
|
||||
Networking: kubeadmapi.Networking{ServiceSubnet: "10.96.0.0/12", DNSDomain: "cluster.local"},
|
||||
CertificatesDir: dir,
|
||||
},
|
||||
NodeRegistration: kubeadmapi.NodeRegistrationOptions{Name: "valid-hostname"},
|
||||
CertificatesDir: dir,
|
||||
}
|
||||
|
||||
for _, f := range test.setupFuncs {
|
||||
@ -504,17 +535,20 @@ func TestUsingExternalCA(t *testing.T) {
|
||||
|
||||
func TestValidateMethods(t *testing.T) {
|
||||
|
||||
caCert, caKey := certstestutil.CreateCACert(t)
|
||||
cert, key := certstestutil.CreateTestCert(t, caCert, caKey)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
setupFuncs []func(cfg *kubeadmapi.MasterConfiguration) error
|
||||
files certstestutil.PKIFiles
|
||||
validateFunc func(l certKeyLocation) error
|
||||
loc certKeyLocation
|
||||
expectedSuccess bool
|
||||
}{
|
||||
{
|
||||
name: "validateCACert",
|
||||
setupFuncs: []func(cfg *kubeadmapi.MasterConfiguration) error{
|
||||
CreateCACertAndKeyFiles,
|
||||
files: certstestutil.PKIFiles{
|
||||
"ca.crt": caCert,
|
||||
},
|
||||
validateFunc: validateCACert,
|
||||
loc: certKeyLocation{caBaseName: "ca", baseName: "", uxName: "CA"},
|
||||
@ -522,28 +556,30 @@ func TestValidateMethods(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "validateCACertAndKey (files present)",
|
||||
setupFuncs: []func(cfg *kubeadmapi.MasterConfiguration) error{
|
||||
CreateCACertAndKeyFiles,
|
||||
files: certstestutil.PKIFiles{
|
||||
"ca.crt": caCert,
|
||||
"ca.key": caKey,
|
||||
},
|
||||
validateFunc: validateCACertAndKey,
|
||||
loc: certKeyLocation{caBaseName: "ca", baseName: "", uxName: "CA"},
|
||||
expectedSuccess: true,
|
||||
},
|
||||
{
|
||||
name: "validateCACertAndKey (key missing)",
|
||||
setupFuncs: []func(cfg *kubeadmapi.MasterConfiguration) error{
|
||||
CreatePKIAssets,
|
||||
deleteCAKey,
|
||||
files: certstestutil.PKIFiles{
|
||||
"ca.crt": caCert,
|
||||
},
|
||||
name: "validateCACertAndKey (key missing)",
|
||||
validateFunc: validateCACertAndKey,
|
||||
loc: certKeyLocation{caBaseName: "ca", baseName: "", uxName: "CA"},
|
||||
expectedSuccess: false,
|
||||
},
|
||||
{
|
||||
name: "validateSignedCert",
|
||||
setupFuncs: []func(cfg *kubeadmapi.MasterConfiguration) error{
|
||||
CreateCACertAndKeyFiles,
|
||||
CreateAPIServerCertAndKeyFiles,
|
||||
files: certstestutil.PKIFiles{
|
||||
"ca.crt": caCert,
|
||||
"ca.key": caKey,
|
||||
"apiserver.crt": cert,
|
||||
"apiserver.key": key,
|
||||
},
|
||||
validateFunc: validateSignedCert,
|
||||
loc: certKeyLocation{caBaseName: "ca", baseName: "apiserver", uxName: "apiserver"},
|
||||
@ -551,8 +587,9 @@ func TestValidateMethods(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "validatePrivatePublicKey",
|
||||
setupFuncs: []func(cfg *kubeadmapi.MasterConfiguration) error{
|
||||
CreateServiceAccountKeyAndPublicKeyFiles,
|
||||
files: certstestutil.PKIFiles{
|
||||
"sa.pub": &key.PublicKey,
|
||||
"sa.key": key,
|
||||
},
|
||||
validateFunc: validatePrivatePublicKey,
|
||||
loc: certKeyLocation{baseName: "sa", uxName: "service account"},
|
||||
@ -561,25 +598,11 @@ func TestValidateMethods(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
|
||||
dir := testutil.SetupTempDir(t)
|
||||
defer os.RemoveAll(dir)
|
||||
test.loc.pkiDir = dir
|
||||
|
||||
cfg := &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadmapi.API{AdvertiseAddress: "1.2.3.4"},
|
||||
Networking: kubeadmapi.Networking{ServiceSubnet: "10.96.0.0/12", DNSDomain: "cluster.local"},
|
||||
NodeRegistration: kubeadmapi.NodeRegistrationOptions{Name: "valid-hostname"},
|
||||
CertificatesDir: dir,
|
||||
}
|
||||
|
||||
fmt.Println("Testing", test.name)
|
||||
|
||||
for _, f := range test.setupFuncs {
|
||||
if err := f(cfg); err != nil {
|
||||
t.Errorf("error executing setup function: %v", err)
|
||||
}
|
||||
}
|
||||
certstestutil.WritePKIFiles(t, dir, test.files)
|
||||
|
||||
err := test.validateFunc(test.loc)
|
||||
if test.expectedSuccess && err != nil {
|
||||
@ -590,25 +613,43 @@ func TestValidateMethods(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func deleteCAKey(cfg *kubeadmapi.MasterConfiguration) error {
|
||||
if err := os.Remove(filepath.Join(cfg.CertificatesDir, kubeadmconstants.CAKeyName)); err != nil {
|
||||
return fmt.Errorf("failed removing %s: %v", kubeadmconstants.CAKeyName, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func TestNewCSR(t *testing.T) {
|
||||
kubeadmCert := KubeadmCertAPIServer
|
||||
cfg := testutil.GetDefaultInternalConfig(t)
|
||||
|
||||
func deleteFrontProxyCAKey(cfg *kubeadmapi.MasterConfiguration) error {
|
||||
if err := os.Remove(filepath.Join(cfg.CertificatesDir, kubeadmconstants.FrontProxyCAKeyName)); err != nil {
|
||||
return fmt.Errorf("failed removing %s: %v", kubeadmconstants.FrontProxyCAKeyName, err)
|
||||
certConfig, err := kubeadmCert.GetConfig(cfg)
|
||||
if err != nil {
|
||||
t.Fatalf("couldn't get cert config: %v", err)
|
||||
}
|
||||
|
||||
csr, _, err := NewCSR(&kubeadmCert, cfg)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("invalid signature on CSR: %v", err)
|
||||
}
|
||||
|
||||
assert.ElementsMatch(t, certConfig.Organization, csr.Subject.Organization, "organizations not equal")
|
||||
|
||||
if csr.Subject.CommonName != certConfig.CommonName {
|
||||
t.Errorf("expected common name %q, got %q", certConfig.CommonName, csr.Subject.CommonName)
|
||||
}
|
||||
|
||||
assert.ElementsMatch(t, certConfig.AltNames.DNSNames, csr.DNSNames, "dns names not equal")
|
||||
|
||||
assert.Len(t, csr.IPAddresses, len(certConfig.AltNames.IPs))
|
||||
|
||||
for i, ip := range csr.IPAddresses {
|
||||
if !ip.Equal(certConfig.AltNames.IPs[i]) {
|
||||
t.Errorf("[%d]: %v != %v", i, ip, certConfig.AltNames.IPs[i])
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestCreateCertificateFilesMethods(t *testing.T) {
|
||||
|
||||
var tests = []struct {
|
||||
setupFunc func(cfg *kubeadmapi.MasterConfiguration) error
|
||||
createFunc func(cfg *kubeadmapi.MasterConfiguration) error
|
||||
setupFunc func(cfg *kubeadmapi.InitConfiguration) error
|
||||
createFunc func(cfg *kubeadmapi.InitConfiguration) error
|
||||
expectedFiles []string
|
||||
externalEtcd bool
|
||||
}{
|
||||
@ -640,57 +681,6 @@ func TestCreateCertificateFilesMethods(t *testing.T) {
|
||||
kubeadmconstants.FrontProxyClientCertName, kubeadmconstants.FrontProxyClientKeyName,
|
||||
},
|
||||
},
|
||||
{
|
||||
createFunc: CreateCACertAndKeyFiles,
|
||||
expectedFiles: []string{kubeadmconstants.CACertName, kubeadmconstants.CAKeyName},
|
||||
},
|
||||
{
|
||||
setupFunc: CreateCACertAndKeyFiles,
|
||||
createFunc: CreateAPIServerCertAndKeyFiles,
|
||||
expectedFiles: []string{kubeadmconstants.APIServerCertName, kubeadmconstants.APIServerKeyName},
|
||||
},
|
||||
{
|
||||
setupFunc: CreateCACertAndKeyFiles,
|
||||
createFunc: CreateAPIServerKubeletClientCertAndKeyFiles,
|
||||
expectedFiles: []string{kubeadmconstants.APIServerKubeletClientCertName, kubeadmconstants.APIServerKubeletClientKeyName},
|
||||
},
|
||||
{
|
||||
createFunc: CreateEtcdCACertAndKeyFiles,
|
||||
expectedFiles: []string{kubeadmconstants.EtcdCACertName, kubeadmconstants.EtcdCAKeyName},
|
||||
},
|
||||
{
|
||||
setupFunc: CreateEtcdCACertAndKeyFiles,
|
||||
createFunc: CreateEtcdServerCertAndKeyFiles,
|
||||
expectedFiles: []string{kubeadmconstants.EtcdServerCertName, kubeadmconstants.EtcdServerKeyName},
|
||||
},
|
||||
{
|
||||
setupFunc: CreateEtcdCACertAndKeyFiles,
|
||||
createFunc: CreateEtcdPeerCertAndKeyFiles,
|
||||
expectedFiles: []string{kubeadmconstants.EtcdPeerCertName, kubeadmconstants.EtcdPeerKeyName},
|
||||
},
|
||||
{
|
||||
setupFunc: CreateEtcdCACertAndKeyFiles,
|
||||
createFunc: CreateEtcdHealthcheckClientCertAndKeyFiles,
|
||||
expectedFiles: []string{kubeadmconstants.EtcdHealthcheckClientCertName, kubeadmconstants.EtcdHealthcheckClientKeyName},
|
||||
},
|
||||
{
|
||||
setupFunc: CreateEtcdCACertAndKeyFiles,
|
||||
createFunc: CreateAPIServerEtcdClientCertAndKeyFiles,
|
||||
expectedFiles: []string{kubeadmconstants.APIServerEtcdClientCertName, kubeadmconstants.APIServerEtcdClientKeyName},
|
||||
},
|
||||
{
|
||||
createFunc: CreateServiceAccountKeyAndPublicKeyFiles,
|
||||
expectedFiles: []string{kubeadmconstants.ServiceAccountPrivateKeyName, kubeadmconstants.ServiceAccountPublicKeyName},
|
||||
},
|
||||
{
|
||||
createFunc: CreateFrontProxyCACertAndKeyFiles,
|
||||
expectedFiles: []string{kubeadmconstants.FrontProxyCACertName, kubeadmconstants.FrontProxyCAKeyName},
|
||||
},
|
||||
{
|
||||
setupFunc: CreateFrontProxyCACertAndKeyFiles,
|
||||
createFunc: CreateFrontProxyClientCertAndKeyFiles,
|
||||
expectedFiles: []string{kubeadmconstants.FrontProxyCACertName, kubeadmconstants.FrontProxyCAKeyName},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
@ -698,12 +688,14 @@ func TestCreateCertificateFilesMethods(t *testing.T) {
|
||||
tmpdir := testutil.SetupTempDir(t)
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
cfg := &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadmapi.API{AdvertiseAddress: "1.2.3.4"},
|
||||
Etcd: kubeadmapi.Etcd{Local: &kubeadmapi.LocalEtcd{}},
|
||||
Networking: kubeadmapi.Networking{ServiceSubnet: "10.96.0.0/12", DNSDomain: "cluster.local"},
|
||||
cfg := &kubeadmapi.InitConfiguration{
|
||||
LocalAPIEndpoint: kubeadmapi.APIEndpoint{AdvertiseAddress: "1.2.3.4"},
|
||||
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
|
||||
Etcd: kubeadmapi.Etcd{Local: &kubeadmapi.LocalEtcd{}},
|
||||
Networking: kubeadmapi.Networking{ServiceSubnet: "10.96.0.0/12", DNSDomain: "cluster.local"},
|
||||
CertificatesDir: tmpdir,
|
||||
},
|
||||
NodeRegistration: kubeadmapi.NodeRegistrationOptions{Name: "valid-hostname"},
|
||||
CertificatesDir: tmpdir,
|
||||
}
|
||||
|
||||
if test.externalEtcd {
|
||||
@ -714,14 +706,6 @@ func TestCreateCertificateFilesMethods(t *testing.T) {
|
||||
cfg.Etcd.External.Endpoints = []string{"192.168.1.1:2379"}
|
||||
}
|
||||
|
||||
// executes setup func (if necessary)
|
||||
if test.setupFunc != nil {
|
||||
if err := test.setupFunc(cfg); err != nil {
|
||||
t.Errorf("error executing setupFunc: %v", err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// executes create func
|
||||
if err := test.createFunc(cfg); err != nil {
|
||||
t.Errorf("error executing createFunc: %v", err)
|
||||
@ -732,3 +716,38 @@ func TestCreateCertificateFilesMethods(t *testing.T) {
|
||||
testutil.AssertFileExists(t, tmpdir, test.expectedFiles...)
|
||||
}
|
||||
}
|
||||
|
||||
func deleteCAKey(cfg *kubeadmapi.InitConfiguration) error {
|
||||
if err := os.Remove(filepath.Join(cfg.CertificatesDir, kubeadmconstants.CAKeyName)); err != nil {
|
||||
return errors.Wrapf(err, "failed removing %s", kubeadmconstants.CAKeyName)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func deleteFrontProxyCAKey(cfg *kubeadmapi.InitConfiguration) error {
|
||||
if err := os.Remove(filepath.Join(cfg.CertificatesDir, kubeadmconstants.FrontProxyCAKeyName)); err != nil {
|
||||
return errors.Wrapf(err, "failed removing %s", kubeadmconstants.FrontProxyCAKeyName)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func assertCertsExist(t *testing.T, dir string) {
|
||||
tree, err := GetDefaultCertList().AsMap().CertTree()
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error getting certificates: %v", err)
|
||||
}
|
||||
|
||||
for caCert, certs := range tree {
|
||||
if err := validateCACert(certKeyLocation{dir, caCert.BaseName, "", caCert.Name}); err != nil {
|
||||
t.Errorf("couldn't validate CA certificate %v: %v", caCert.Name, err)
|
||||
// Don't bother validating child certs, but do try the other CAs
|
||||
continue
|
||||
}
|
||||
|
||||
for _, cert := range certs {
|
||||
if err := validateSignedCert(certKeyLocation{dir, caCert.BaseName, cert.BaseName, cert.Name}); err != nil {
|
||||
t.Errorf("couldn't validate certificate %v: %v", cert.Name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
8
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/doc.go
generated
vendored
8
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/doc.go
generated
vendored
@ -21,13 +21,13 @@ package certs
|
||||
PHASE: CERTIFICATES
|
||||
|
||||
INPUTS:
|
||||
From MasterConfiguration
|
||||
From InitConfiguration
|
||||
.API.AdvertiseAddress is an optional parameter that can be passed for an extra addition to the SAN IPs
|
||||
.APIServerCertSANs is an optional parameter for adding DNS names and IPs to the API Server serving cert SAN
|
||||
.APIServer.CertSANs is an optional parameter for adding DNS names and IPs to the API Server serving cert SAN
|
||||
.Etcd.Local.ServerCertSANs is an optional parameter for adding DNS names and IPs to the etcd serving cert SAN
|
||||
.Etcd.Local.PeerCertSANs is an optional parameter for adding DNS names and IPs to the etcd peer cert SAN
|
||||
.Networking.DNSDomain is needed for knowing which DNS name the internal kubernetes service has
|
||||
.Networking.ServiceSubnet is needed for knowing which IP the internal kubernetes service is going to point to
|
||||
.Networking.DNSDomain is needed for knowing which DNS name the internal Kubernetes service has
|
||||
.Networking.ServiceSubnet is needed for knowing which IP the internal Kubernetes service is going to point to
|
||||
.CertificatesDir is required for knowing where all certificates should be stored
|
||||
|
||||
OUTPUTS:
|
||||
|
44
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/pkiutil/BUILD
generated
vendored
44
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/pkiutil/BUILD
generated
vendored
@ -1,44 +0,0 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["pki_helpers_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
|
||||
"//vendor/k8s.io/client-go/util/cert:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["pki_helpers.go"],
|
||||
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/pkiutil",
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
|
||||
"//cmd/kubeadm/app/constants:go_default_library",
|
||||
"//cmd/kubeadm/app/util:go_default_library",
|
||||
"//pkg/registry/core/service/ipallocator:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/validation:go_default_library",
|
||||
"//vendor/k8s.io/client-go/util/cert:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
369
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/pkiutil/pki_helpers.go
generated
vendored
369
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/pkiutil/pki_helpers.go
generated
vendored
@ -1,369 +0,0 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package pkiutil
|
||||
|
||||
import (
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/validation"
|
||||
certutil "k8s.io/client-go/util/cert"
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
|
||||
"k8s.io/kubernetes/pkg/registry/core/service/ipallocator"
|
||||
)
|
||||
|
||||
// NewCertificateAuthority creates new certificate and private key for the certificate authority
|
||||
func NewCertificateAuthority() (*x509.Certificate, *rsa.PrivateKey, error) {
|
||||
key, err := certutil.NewPrivateKey()
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("unable to create private key [%v]", err)
|
||||
}
|
||||
|
||||
config := certutil.Config{
|
||||
CommonName: "kubernetes",
|
||||
}
|
||||
cert, err := certutil.NewSelfSignedCACert(config, key)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("unable to create self-signed certificate [%v]", err)
|
||||
}
|
||||
|
||||
return cert, key, nil
|
||||
}
|
||||
|
||||
// NewCertAndKey creates new certificate and key by passing the certificate authority certificate and key
|
||||
func NewCertAndKey(caCert *x509.Certificate, caKey *rsa.PrivateKey, config certutil.Config) (*x509.Certificate, *rsa.PrivateKey, error) {
|
||||
key, err := certutil.NewPrivateKey()
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("unable to create private key [%v]", err)
|
||||
}
|
||||
|
||||
cert, err := certutil.NewSignedCert(config, key, caCert, caKey)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("unable to sign certificate [%v]", err)
|
||||
}
|
||||
|
||||
return cert, key, nil
|
||||
}
|
||||
|
||||
// HasServerAuth returns true if the given certificate is a ServerAuth
|
||||
func HasServerAuth(cert *x509.Certificate) bool {
|
||||
for i := range cert.ExtKeyUsage {
|
||||
if cert.ExtKeyUsage[i] == x509.ExtKeyUsageServerAuth {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// WriteCertAndKey stores certificate and key at the specified location
|
||||
func WriteCertAndKey(pkiPath string, name string, cert *x509.Certificate, key *rsa.PrivateKey) error {
|
||||
if err := WriteKey(pkiPath, name, key); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return WriteCert(pkiPath, name, cert)
|
||||
}
|
||||
|
||||
// WriteCert stores the given certificate at the given location
|
||||
func WriteCert(pkiPath, name string, cert *x509.Certificate) error {
|
||||
if cert == nil {
|
||||
return fmt.Errorf("certificate cannot be nil when writing to file")
|
||||
}
|
||||
|
||||
certificatePath := pathForCert(pkiPath, name)
|
||||
if err := certutil.WriteCert(certificatePath, certutil.EncodeCertPEM(cert)); err != nil {
|
||||
return fmt.Errorf("unable to write certificate to file %q: [%v]", certificatePath, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// WriteKey stores the given key at the given location
|
||||
func WriteKey(pkiPath, name string, key *rsa.PrivateKey) error {
|
||||
if key == nil {
|
||||
return fmt.Errorf("private key cannot be nil when writing to file")
|
||||
}
|
||||
|
||||
privateKeyPath := pathForKey(pkiPath, name)
|
||||
if err := certutil.WriteKey(privateKeyPath, certutil.EncodePrivateKeyPEM(key)); err != nil {
|
||||
return fmt.Errorf("unable to write private key to file %q: [%v]", privateKeyPath, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// WritePublicKey stores the given public key at the given location
|
||||
func WritePublicKey(pkiPath, name string, key *rsa.PublicKey) error {
|
||||
if key == nil {
|
||||
return fmt.Errorf("public key cannot be nil when writing to file")
|
||||
}
|
||||
|
||||
publicKeyBytes, err := certutil.EncodePublicKeyPEM(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
publicKeyPath := pathForPublicKey(pkiPath, name)
|
||||
if err := certutil.WriteKey(publicKeyPath, publicKeyBytes); err != nil {
|
||||
return fmt.Errorf("unable to write public key to file %q: [%v]", publicKeyPath, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CertOrKeyExist returns a boolean whether the cert or the key exists
|
||||
func CertOrKeyExist(pkiPath, name string) bool {
|
||||
certificatePath, privateKeyPath := pathsForCertAndKey(pkiPath, name)
|
||||
|
||||
_, certErr := os.Stat(certificatePath)
|
||||
_, keyErr := os.Stat(privateKeyPath)
|
||||
if os.IsNotExist(certErr) && os.IsNotExist(keyErr) {
|
||||
// The cert or the key did not exist
|
||||
return false
|
||||
}
|
||||
|
||||
// Both files exist or one of them
|
||||
return true
|
||||
}
|
||||
|
||||
// TryLoadCertAndKeyFromDisk tries to load a cert and a key from the disk and validates that they are valid
|
||||
func TryLoadCertAndKeyFromDisk(pkiPath, name string) (*x509.Certificate, *rsa.PrivateKey, error) {
|
||||
cert, err := TryLoadCertFromDisk(pkiPath, name)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
key, err := TryLoadKeyFromDisk(pkiPath, name)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return cert, key, nil
|
||||
}
|
||||
|
||||
// TryLoadCertFromDisk tries to load the cert from the disk and validates that it is valid
|
||||
func TryLoadCertFromDisk(pkiPath, name string) (*x509.Certificate, error) {
|
||||
certificatePath := pathForCert(pkiPath, name)
|
||||
|
||||
certs, err := certutil.CertsFromFile(certificatePath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't load the certificate file %s: %v", certificatePath, err)
|
||||
}
|
||||
|
||||
// We are only putting one certificate in the certificate pem file, so it's safe to just pick the first one
|
||||
// TODO: Support multiple certs here in order to be able to rotate certs
|
||||
cert := certs[0]
|
||||
|
||||
// Check so that the certificate is valid now
|
||||
now := time.Now()
|
||||
if now.Before(cert.NotBefore) {
|
||||
return nil, fmt.Errorf("the certificate is not valid yet")
|
||||
}
|
||||
if now.After(cert.NotAfter) {
|
||||
return nil, fmt.Errorf("the certificate has expired")
|
||||
}
|
||||
|
||||
return cert, nil
|
||||
}
|
||||
|
||||
// TryLoadKeyFromDisk tries to load the key from the disk and validates that it is valid
|
||||
func TryLoadKeyFromDisk(pkiPath, name string) (*rsa.PrivateKey, error) {
|
||||
privateKeyPath := pathForKey(pkiPath, name)
|
||||
|
||||
// Parse the private key from a file
|
||||
privKey, err := certutil.PrivateKeyFromFile(privateKeyPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't load the private key file %s: %v", privateKeyPath, err)
|
||||
}
|
||||
|
||||
// Allow RSA format only
|
||||
var key *rsa.PrivateKey
|
||||
switch k := privKey.(type) {
|
||||
case *rsa.PrivateKey:
|
||||
key = k
|
||||
default:
|
||||
return nil, fmt.Errorf("the private key file %s isn't in RSA format", privateKeyPath)
|
||||
}
|
||||
|
||||
return key, nil
|
||||
}
|
||||
|
||||
// TryLoadPrivatePublicKeyFromDisk tries to load the key from the disk and validates that it is valid
|
||||
func TryLoadPrivatePublicKeyFromDisk(pkiPath, name string) (*rsa.PrivateKey, *rsa.PublicKey, error) {
|
||||
privateKeyPath := pathForKey(pkiPath, name)
|
||||
|
||||
// Parse the private key from a file
|
||||
privKey, err := certutil.PrivateKeyFromFile(privateKeyPath)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("couldn't load the private key file %s: %v", privateKeyPath, err)
|
||||
}
|
||||
|
||||
publicKeyPath := pathForPublicKey(pkiPath, name)
|
||||
|
||||
// Parse the public key from a file
|
||||
pubKeys, err := certutil.PublicKeysFromFile(publicKeyPath)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("couldn't load the public key file %s: %v", publicKeyPath, err)
|
||||
}
|
||||
|
||||
// Allow RSA format only
|
||||
k, ok := privKey.(*rsa.PrivateKey)
|
||||
if !ok {
|
||||
return nil, nil, fmt.Errorf("the private key file %s isn't in RSA format", privateKeyPath)
|
||||
}
|
||||
|
||||
p := pubKeys[0].(*rsa.PublicKey)
|
||||
|
||||
return k, p, nil
|
||||
}
|
||||
|
||||
func pathsForCertAndKey(pkiPath, name string) (string, string) {
|
||||
return pathForCert(pkiPath, name), pathForKey(pkiPath, name)
|
||||
}
|
||||
|
||||
func pathForCert(pkiPath, name string) string {
|
||||
return filepath.Join(pkiPath, fmt.Sprintf("%s.crt", name))
|
||||
}
|
||||
|
||||
func pathForKey(pkiPath, name string) string {
|
||||
return filepath.Join(pkiPath, fmt.Sprintf("%s.key", name))
|
||||
}
|
||||
|
||||
func pathForPublicKey(pkiPath, name string) string {
|
||||
return filepath.Join(pkiPath, fmt.Sprintf("%s.pub", name))
|
||||
}
|
||||
|
||||
// GetAPIServerAltNames builds an AltNames object for to be used when generating apiserver certificate
|
||||
func GetAPIServerAltNames(cfg *kubeadmapi.MasterConfiguration) (*certutil.AltNames, error) {
|
||||
// advertise address
|
||||
advertiseAddress := net.ParseIP(cfg.API.AdvertiseAddress)
|
||||
if advertiseAddress == nil {
|
||||
return nil, fmt.Errorf("error parsing API AdvertiseAddress %v: is not a valid textual representation of an IP address", cfg.API.AdvertiseAddress)
|
||||
}
|
||||
|
||||
// internal IP address for the API server
|
||||
_, svcSubnet, err := net.ParseCIDR(cfg.Networking.ServiceSubnet)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing CIDR %q: %v", cfg.Networking.ServiceSubnet, err)
|
||||
}
|
||||
|
||||
internalAPIServerVirtualIP, err := ipallocator.GetIndexedIP(svcSubnet, 1)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to get first IP address from the given CIDR (%s): %v", svcSubnet.String(), err)
|
||||
}
|
||||
|
||||
// create AltNames with defaults DNSNames/IPs
|
||||
altNames := &certutil.AltNames{
|
||||
DNSNames: []string{
|
||||
cfg.NodeRegistration.Name,
|
||||
"kubernetes",
|
||||
"kubernetes.default",
|
||||
"kubernetes.default.svc",
|
||||
fmt.Sprintf("kubernetes.default.svc.%s", cfg.Networking.DNSDomain),
|
||||
},
|
||||
IPs: []net.IP{
|
||||
internalAPIServerVirtualIP,
|
||||
advertiseAddress,
|
||||
},
|
||||
}
|
||||
|
||||
// add api server controlPlaneEndpoint if present (dns or ip)
|
||||
if len(cfg.API.ControlPlaneEndpoint) > 0 {
|
||||
if host, _, err := kubeadmutil.ParseHostPort(cfg.API.ControlPlaneEndpoint); err == nil {
|
||||
if ip := net.ParseIP(host); ip != nil {
|
||||
altNames.IPs = append(altNames.IPs, ip)
|
||||
} else {
|
||||
altNames.DNSNames = append(altNames.DNSNames, host)
|
||||
}
|
||||
} else {
|
||||
return nil, fmt.Errorf("error parsing API api.controlPlaneEndpoint %q: %s", cfg.API.ControlPlaneEndpoint, err)
|
||||
}
|
||||
}
|
||||
|
||||
appendSANsToAltNames(altNames, cfg.APIServerCertSANs, kubeadmconstants.APIServerCertName)
|
||||
|
||||
return altNames, nil
|
||||
}
|
||||
|
||||
// GetEtcdAltNames builds an AltNames object for generating the etcd server certificate.
|
||||
// `localhost` is included in the SAN since this is the interface the etcd static pod listens on.
|
||||
// Hostname and `API.AdvertiseAddress` are excluded since etcd does not listen on this interface by default.
|
||||
// The user can override the listen address with `Etcd.ExtraArgs` and add SANs with `Etcd.ServerCertSANs`.
|
||||
func GetEtcdAltNames(cfg *kubeadmapi.MasterConfiguration) (*certutil.AltNames, error) {
|
||||
// create AltNames with defaults DNSNames/IPs
|
||||
altNames := &certutil.AltNames{
|
||||
DNSNames: []string{cfg.NodeRegistration.Name, "localhost"},
|
||||
IPs: []net.IP{net.IPv4(127, 0, 0, 1), net.IPv6loopback},
|
||||
}
|
||||
|
||||
if cfg.Etcd.Local != nil {
|
||||
appendSANsToAltNames(altNames, cfg.Etcd.Local.ServerCertSANs, kubeadmconstants.EtcdServerCertName)
|
||||
}
|
||||
|
||||
return altNames, nil
|
||||
}
|
||||
|
||||
// GetEtcdPeerAltNames builds an AltNames object for generating the etcd peer certificate.
|
||||
// `localhost` is excluded from the SAN since etcd will not refer to itself as a peer.
|
||||
// Hostname and `API.AdvertiseAddress` are included if the user chooses to promote the single node etcd cluster into a multi-node one.
|
||||
// The user can override the listen address with `Etcd.ExtraArgs` and add SANs with `Etcd.PeerCertSANs`.
|
||||
func GetEtcdPeerAltNames(cfg *kubeadmapi.MasterConfiguration) (*certutil.AltNames, error) {
|
||||
// advertise address
|
||||
advertiseAddress := net.ParseIP(cfg.API.AdvertiseAddress)
|
||||
if advertiseAddress == nil {
|
||||
return nil, fmt.Errorf("error parsing API AdvertiseAddress %v: is not a valid textual representation of an IP address", cfg.API.AdvertiseAddress)
|
||||
}
|
||||
|
||||
// create AltNames with defaults DNSNames/IPs
|
||||
altNames := &certutil.AltNames{
|
||||
DNSNames: []string{cfg.NodeRegistration.Name, "localhost"},
|
||||
IPs: []net.IP{advertiseAddress, net.IPv4(127, 0, 0, 1), net.IPv6loopback},
|
||||
}
|
||||
|
||||
if cfg.Etcd.Local != nil {
|
||||
appendSANsToAltNames(altNames, cfg.Etcd.Local.PeerCertSANs, kubeadmconstants.EtcdPeerCertName)
|
||||
}
|
||||
|
||||
return altNames, nil
|
||||
}
|
||||
|
||||
// appendSANsToAltNames parses SANs from as list of strings and adds them to altNames for use on a specific cert
|
||||
// altNames is passed in with a pointer, and the struct is modified
|
||||
// valid IP address strings are parsed and added to altNames.IPs as net.IP's
|
||||
// RFC-1123 compliant DNS strings are added to altNames.DNSNames as strings
|
||||
// certNames is used to print user facing warnings and should be the name of the cert the altNames will be used for
|
||||
func appendSANsToAltNames(altNames *certutil.AltNames, SANs []string, certName string) {
|
||||
for _, altname := range SANs {
|
||||
if ip := net.ParseIP(altname); ip != nil {
|
||||
altNames.IPs = append(altNames.IPs, ip)
|
||||
} else if len(validation.IsDNS1123Subdomain(altname)) == 0 {
|
||||
altNames.DNSNames = append(altNames.DNSNames, altname)
|
||||
} else {
|
||||
fmt.Printf(
|
||||
"[certificates] WARNING: '%s' was not added to the '%s' SAN, because it is not a valid IP or RFC-1123 compliant DNS entry\n",
|
||||
altname,
|
||||
certName,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
612
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/pkiutil/pki_helpers_test.go
generated
vendored
612
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/pkiutil/pki_helpers_test.go
generated
vendored
@ -1,612 +0,0 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package pkiutil
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
certutil "k8s.io/client-go/util/cert"
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
)
|
||||
|
||||
func TestNewCertificateAuthority(t *testing.T) {
|
||||
cert, key, err := NewCertificateAuthority()
|
||||
|
||||
if cert == nil {
|
||||
t.Errorf(
|
||||
"failed NewCertificateAuthority, cert == nil",
|
||||
)
|
||||
}
|
||||
if key == nil {
|
||||
t.Errorf(
|
||||
"failed NewCertificateAuthority, key == nil",
|
||||
)
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf(
|
||||
"failed NewCertificateAuthority with an error: %v",
|
||||
err,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewCertAndKey(t *testing.T) {
|
||||
var tests = []struct {
|
||||
caKeySize int
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
// RSA key too small
|
||||
caKeySize: 128,
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
// Should succeed
|
||||
caKeySize: 2048,
|
||||
expected: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, rt := range tests {
|
||||
caKey, err := rsa.GenerateKey(rand.Reader, rt.caKeySize)
|
||||
if err != nil {
|
||||
t.Fatalf("Couldn't create rsa Private Key")
|
||||
}
|
||||
caCert := &x509.Certificate{}
|
||||
config := certutil.Config{
|
||||
CommonName: "test",
|
||||
Organization: []string{"test"},
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
}
|
||||
_, _, actual := NewCertAndKey(caCert, caKey, config)
|
||||
if (actual == nil) != rt.expected {
|
||||
t.Errorf(
|
||||
"failed NewCertAndKey:\n\texpected: %t\n\t actual: %t",
|
||||
rt.expected,
|
||||
(actual == nil),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestHasServerAuth(t *testing.T) {
|
||||
caCert, caKey, _ := NewCertificateAuthority()
|
||||
|
||||
var tests = []struct {
|
||||
config certutil.Config
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
config: certutil.Config{
|
||||
CommonName: "test",
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
config: certutil.Config{
|
||||
CommonName: "test",
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, rt := range tests {
|
||||
cert, _, err := NewCertAndKey(caCert, caKey, rt.config)
|
||||
if err != nil {
|
||||
t.Fatalf("Couldn't create cert: %v", err)
|
||||
}
|
||||
actual := HasServerAuth(cert)
|
||||
if actual != rt.expected {
|
||||
t.Errorf(
|
||||
"failed HasServerAuth:\n\texpected: %t\n\t actual: %t",
|
||||
rt.expected,
|
||||
actual,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestWriteCertAndKey(t *testing.T) {
|
||||
tmpdir, err := ioutil.TempDir("", "")
|
||||
if err != nil {
|
||||
t.Fatalf("Couldn't create tmpdir")
|
||||
}
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
caKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
if err != nil {
|
||||
t.Fatalf("Couldn't create rsa Private Key")
|
||||
}
|
||||
caCert := &x509.Certificate{}
|
||||
actual := WriteCertAndKey(tmpdir, "foo", caCert, caKey)
|
||||
if actual != nil {
|
||||
t.Errorf(
|
||||
"failed WriteCertAndKey with an error: %v",
|
||||
actual,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWriteCert(t *testing.T) {
|
||||
tmpdir, err := ioutil.TempDir("", "")
|
||||
if err != nil {
|
||||
t.Fatalf("Couldn't create tmpdir")
|
||||
}
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
caCert := &x509.Certificate{}
|
||||
actual := WriteCert(tmpdir, "foo", caCert)
|
||||
if actual != nil {
|
||||
t.Errorf(
|
||||
"failed WriteCertAndKey with an error: %v",
|
||||
actual,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWriteKey(t *testing.T) {
|
||||
tmpdir, err := ioutil.TempDir("", "")
|
||||
if err != nil {
|
||||
t.Fatalf("Couldn't create tmpdir")
|
||||
}
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
caKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
if err != nil {
|
||||
t.Fatalf("Couldn't create rsa Private Key")
|
||||
}
|
||||
actual := WriteKey(tmpdir, "foo", caKey)
|
||||
if actual != nil {
|
||||
t.Errorf(
|
||||
"failed WriteCertAndKey with an error: %v",
|
||||
actual,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWritePublicKey(t *testing.T) {
|
||||
tmpdir, err := ioutil.TempDir("", "")
|
||||
if err != nil {
|
||||
t.Fatalf("Couldn't create tmpdir")
|
||||
}
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
caKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
if err != nil {
|
||||
t.Fatalf("Couldn't create rsa Private Key")
|
||||
}
|
||||
actual := WritePublicKey(tmpdir, "foo", &caKey.PublicKey)
|
||||
if actual != nil {
|
||||
t.Errorf(
|
||||
"failed WriteCertAndKey with an error: %v",
|
||||
actual,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCertOrKeyExist(t *testing.T) {
|
||||
tmpdir, err := ioutil.TempDir("", "")
|
||||
if err != nil {
|
||||
t.Fatalf("Couldn't create tmpdir")
|
||||
}
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
caKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
if err != nil {
|
||||
t.Fatalf("Couldn't create rsa Private Key")
|
||||
}
|
||||
caCert := &x509.Certificate{}
|
||||
actual := WriteCertAndKey(tmpdir, "foo", caCert, caKey)
|
||||
if actual != nil {
|
||||
t.Errorf(
|
||||
"failed WriteCertAndKey with an error: %v",
|
||||
actual,
|
||||
)
|
||||
}
|
||||
|
||||
var tests = []struct {
|
||||
path string
|
||||
name string
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
path: "",
|
||||
name: "",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
path: tmpdir,
|
||||
name: "foo",
|
||||
expected: true,
|
||||
},
|
||||
}
|
||||
for _, rt := range tests {
|
||||
actual := CertOrKeyExist(rt.path, rt.name)
|
||||
if actual != rt.expected {
|
||||
t.Errorf(
|
||||
"failed CertOrKeyExist:\n\texpected: %t\n\t actual: %t",
|
||||
rt.expected,
|
||||
actual,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTryLoadCertAndKeyFromDisk(t *testing.T) {
|
||||
tmpdir, err := ioutil.TempDir("", "")
|
||||
if err != nil {
|
||||
t.Fatalf("Couldn't create tmpdir")
|
||||
}
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
caCert, caKey, err := NewCertificateAuthority()
|
||||
if err != nil {
|
||||
t.Errorf(
|
||||
"failed to create cert and key with an error: %v",
|
||||
err,
|
||||
)
|
||||
}
|
||||
err = WriteCertAndKey(tmpdir, "foo", caCert, caKey)
|
||||
if err != nil {
|
||||
t.Errorf(
|
||||
"failed to write cert and key with an error: %v",
|
||||
err,
|
||||
)
|
||||
}
|
||||
|
||||
var tests = []struct {
|
||||
path string
|
||||
name string
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
path: "",
|
||||
name: "",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
path: tmpdir,
|
||||
name: "foo",
|
||||
expected: true,
|
||||
},
|
||||
}
|
||||
for _, rt := range tests {
|
||||
_, _, actual := TryLoadCertAndKeyFromDisk(rt.path, rt.name)
|
||||
if (actual == nil) != rt.expected {
|
||||
t.Errorf(
|
||||
"failed TryLoadCertAndKeyFromDisk:\n\texpected: %t\n\t actual: %t",
|
||||
rt.expected,
|
||||
(actual == nil),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTryLoadCertFromDisk(t *testing.T) {
|
||||
tmpdir, err := ioutil.TempDir("", "")
|
||||
if err != nil {
|
||||
t.Fatalf("Couldn't create tmpdir")
|
||||
}
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
caCert, _, err := NewCertificateAuthority()
|
||||
if err != nil {
|
||||
t.Errorf(
|
||||
"failed to create cert and key with an error: %v",
|
||||
err,
|
||||
)
|
||||
}
|
||||
err = WriteCert(tmpdir, "foo", caCert)
|
||||
if err != nil {
|
||||
t.Errorf(
|
||||
"failed to write cert and key with an error: %v",
|
||||
err,
|
||||
)
|
||||
}
|
||||
|
||||
var tests = []struct {
|
||||
path string
|
||||
name string
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
path: "",
|
||||
name: "",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
path: tmpdir,
|
||||
name: "foo",
|
||||
expected: true,
|
||||
},
|
||||
}
|
||||
for _, rt := range tests {
|
||||
_, actual := TryLoadCertFromDisk(rt.path, rt.name)
|
||||
if (actual == nil) != rt.expected {
|
||||
t.Errorf(
|
||||
"failed TryLoadCertAndKeyFromDisk:\n\texpected: %t\n\t actual: %t",
|
||||
rt.expected,
|
||||
(actual == nil),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTryLoadKeyFromDisk(t *testing.T) {
|
||||
tmpdir, err := ioutil.TempDir("", "")
|
||||
if err != nil {
|
||||
t.Fatalf("Couldn't create tmpdir")
|
||||
}
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
_, caKey, err := NewCertificateAuthority()
|
||||
if err != nil {
|
||||
t.Errorf(
|
||||
"failed to create cert and key with an error: %v",
|
||||
err,
|
||||
)
|
||||
}
|
||||
err = WriteKey(tmpdir, "foo", caKey)
|
||||
if err != nil {
|
||||
t.Errorf(
|
||||
"failed to write cert and key with an error: %v",
|
||||
err,
|
||||
)
|
||||
}
|
||||
|
||||
var tests = []struct {
|
||||
path string
|
||||
name string
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
path: "",
|
||||
name: "",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
path: tmpdir,
|
||||
name: "foo",
|
||||
expected: true,
|
||||
},
|
||||
}
|
||||
for _, rt := range tests {
|
||||
_, actual := TryLoadKeyFromDisk(rt.path, rt.name)
|
||||
if (actual == nil) != rt.expected {
|
||||
t.Errorf(
|
||||
"failed TryLoadCertAndKeyFromDisk:\n\texpected: %t\n\t actual: %t",
|
||||
rt.expected,
|
||||
(actual == nil),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPathsForCertAndKey(t *testing.T) {
|
||||
crtPath, keyPath := pathsForCertAndKey("/foo", "bar")
|
||||
if crtPath != "/foo/bar.crt" {
|
||||
t.Errorf("unexpected certificate path: %s", crtPath)
|
||||
}
|
||||
if keyPath != "/foo/bar.key" {
|
||||
t.Errorf("unexpected key path: %s", keyPath)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPathForCert(t *testing.T) {
|
||||
crtPath := pathForCert("/foo", "bar")
|
||||
if crtPath != "/foo/bar.crt" {
|
||||
t.Errorf("unexpected certificate path: %s", crtPath)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPathForKey(t *testing.T) {
|
||||
keyPath := pathForKey("/foo", "bar")
|
||||
if keyPath != "/foo/bar.key" {
|
||||
t.Errorf("unexpected certificate path: %s", keyPath)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPathForPublicKey(t *testing.T) {
|
||||
pubPath := pathForPublicKey("/foo", "bar")
|
||||
if pubPath != "/foo/bar.pub" {
|
||||
t.Errorf("unexpected certificate path: %s", pubPath)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAPIServerAltNames(t *testing.T) {
|
||||
|
||||
var tests = []struct {
|
||||
name string
|
||||
cfg *kubeadmapi.MasterConfiguration
|
||||
expectedDNSNames []string
|
||||
expectedIPAddresses []string
|
||||
}{
|
||||
{
|
||||
name: "ControlPlaneEndpoint DNS",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadmapi.API{AdvertiseAddress: "1.2.3.4", ControlPlaneEndpoint: "api.k8s.io:6443"},
|
||||
Networking: kubeadmapi.Networking{ServiceSubnet: "10.96.0.0/12", DNSDomain: "cluster.local"},
|
||||
NodeRegistration: kubeadmapi.NodeRegistrationOptions{Name: "valid-hostname"},
|
||||
APIServerCertSANs: []string{"10.1.245.94", "10.1.245.95", "1.2.3.L", "invalid,commas,in,DNS"},
|
||||
},
|
||||
expectedDNSNames: []string{"valid-hostname", "kubernetes", "kubernetes.default", "kubernetes.default.svc", "kubernetes.default.svc.cluster.local", "api.k8s.io"},
|
||||
expectedIPAddresses: []string{"10.96.0.1", "1.2.3.4", "10.1.245.94", "10.1.245.95"},
|
||||
},
|
||||
{
|
||||
name: "ControlPlaneEndpoint IP",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadmapi.API{AdvertiseAddress: "1.2.3.4", ControlPlaneEndpoint: "4.5.6.7:6443"},
|
||||
Networking: kubeadmapi.Networking{ServiceSubnet: "10.96.0.0/12", DNSDomain: "cluster.local"},
|
||||
NodeRegistration: kubeadmapi.NodeRegistrationOptions{Name: "valid-hostname"},
|
||||
APIServerCertSANs: []string{"10.1.245.94", "10.1.245.95", "1.2.3.L", "invalid,commas,in,DNS"},
|
||||
},
|
||||
expectedDNSNames: []string{"valid-hostname", "kubernetes", "kubernetes.default", "kubernetes.default.svc", "kubernetes.default.svc.cluster.local"},
|
||||
expectedIPAddresses: []string{"10.96.0.1", "1.2.3.4", "10.1.245.94", "10.1.245.95", "4.5.6.7"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, rt := range tests {
|
||||
altNames, err := GetAPIServerAltNames(rt.cfg)
|
||||
if err != nil {
|
||||
t.Fatalf("failed calling GetAPIServerAltNames: %s: %v", rt.name, err)
|
||||
}
|
||||
|
||||
for _, DNSName := range rt.expectedDNSNames {
|
||||
found := false
|
||||
for _, val := range altNames.DNSNames {
|
||||
if val == DNSName {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
t.Errorf("%s: altNames does not contain DNSName %s but %v", rt.name, DNSName, altNames.DNSNames)
|
||||
}
|
||||
}
|
||||
|
||||
for _, IPAddress := range rt.expectedIPAddresses {
|
||||
found := false
|
||||
for _, val := range altNames.IPs {
|
||||
if val.Equal(net.ParseIP(IPAddress)) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
t.Errorf("%s: altNames does not contain IPAddress %s but %v", rt.name, IPAddress, altNames.IPs)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetEtcdAltNames(t *testing.T) {
|
||||
proxy := "user-etcd-proxy"
|
||||
proxyIP := "10.10.10.100"
|
||||
cfg := &kubeadmapi.MasterConfiguration{
|
||||
Etcd: kubeadmapi.Etcd{
|
||||
Local: &kubeadmapi.LocalEtcd{
|
||||
ServerCertSANs: []string{
|
||||
proxy,
|
||||
proxyIP,
|
||||
"1.2.3.L",
|
||||
"invalid,commas,in,DNS",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
altNames, err := GetEtcdAltNames(cfg)
|
||||
if err != nil {
|
||||
t.Fatalf("failed calling GetEtcdAltNames: %v", err)
|
||||
}
|
||||
|
||||
expectedDNSNames := []string{"localhost", proxy}
|
||||
for _, DNSName := range expectedDNSNames {
|
||||
found := false
|
||||
for _, val := range altNames.DNSNames {
|
||||
if val == DNSName {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
t.Errorf("altNames does not contain DNSName %s", DNSName)
|
||||
}
|
||||
}
|
||||
|
||||
expectedIPAddresses := []string{"127.0.0.1", net.IPv6loopback.String(), proxyIP}
|
||||
for _, IPAddress := range expectedIPAddresses {
|
||||
found := false
|
||||
for _, val := range altNames.IPs {
|
||||
if val.Equal(net.ParseIP(IPAddress)) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
t.Errorf("altNames does not contain IPAddress %s", IPAddress)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetEtcdPeerAltNames(t *testing.T) {
|
||||
hostname := "valid-hostname"
|
||||
proxy := "user-etcd-proxy"
|
||||
proxyIP := "10.10.10.100"
|
||||
advertiseIP := "1.2.3.4"
|
||||
cfg := &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadmapi.API{AdvertiseAddress: advertiseIP},
|
||||
NodeRegistration: kubeadmapi.NodeRegistrationOptions{Name: hostname},
|
||||
Etcd: kubeadmapi.Etcd{
|
||||
Local: &kubeadmapi.LocalEtcd{
|
||||
PeerCertSANs: []string{
|
||||
proxy,
|
||||
proxyIP,
|
||||
"1.2.3.L",
|
||||
"invalid,commas,in,DNS",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
altNames, err := GetEtcdPeerAltNames(cfg)
|
||||
if err != nil {
|
||||
t.Fatalf("failed calling GetEtcdPeerAltNames: %v", err)
|
||||
}
|
||||
|
||||
expectedDNSNames := []string{hostname, proxy}
|
||||
for _, DNSName := range expectedDNSNames {
|
||||
found := false
|
||||
for _, val := range altNames.DNSNames {
|
||||
if val == DNSName {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
t.Errorf("altNames does not contain DNSName %s", DNSName)
|
||||
}
|
||||
}
|
||||
|
||||
expectedIPAddresses := []string{advertiseIP, proxyIP}
|
||||
for _, IPAddress := range expectedIPAddresses {
|
||||
found := false
|
||||
for _, val := range altNames.IPs {
|
||||
if val.Equal(net.ParseIP(IPAddress)) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
t.Errorf("altNames does not contain IPAddress %s", IPAddress)
|
||||
}
|
||||
}
|
||||
}
|
59
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/renewal/BUILD
generated
vendored
Normal file
59
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/renewal/BUILD
generated
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"certsapi.go",
|
||||
"filerenewal.go",
|
||||
"interface.go",
|
||||
"renewal.go",
|
||||
],
|
||||
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/renewal",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/util/pkiutil:go_default_library",
|
||||
"//staging/src/k8s.io/api/certificates/v1beta1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/kubernetes/typed/certificates/v1beta1:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/util/cert:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/util/certificate/csr:go_default_library",
|
||||
"//vendor/github.com/pkg/errors:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"filerenewal_test.go",
|
||||
"renewal_test.go",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/phases/certs:go_default_library",
|
||||
"//cmd/kubeadm/app/util/pkiutil:go_default_library",
|
||||
"//cmd/kubeadm/test:go_default_library",
|
||||
"//cmd/kubeadm/test/certs:go_default_library",
|
||||
"//staging/src/k8s.io/api/certificates/v1beta1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/watch:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/kubernetes/typed/certificates/v1beta1/fake:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/testing:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/util/cert:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
129
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/renewal/certsapi.go
generated
vendored
Normal file
129
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/renewal/certsapi.go
generated
vendored
Normal file
@ -0,0 +1,129 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package renewal
|
||||
|
||||
import (
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
certsapi "k8s.io/api/certificates/v1beta1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
certstype "k8s.io/client-go/kubernetes/typed/certificates/v1beta1"
|
||||
certutil "k8s.io/client-go/util/cert"
|
||||
csrutil "k8s.io/client-go/util/certificate/csr"
|
||||
)
|
||||
|
||||
const certAPIPrefixName = "kubeadm-cert"
|
||||
|
||||
var watchTimeout = 5 * time.Minute
|
||||
|
||||
// CertsAPIRenewal creates new certificates using the certs API
|
||||
type CertsAPIRenewal struct {
|
||||
client certstype.CertificatesV1beta1Interface
|
||||
}
|
||||
|
||||
// NewCertsAPIRenawal takes a Kubernetes interface and returns a renewal Interface.
|
||||
func NewCertsAPIRenawal(client kubernetes.Interface) Interface {
|
||||
return &CertsAPIRenewal{
|
||||
client: client.CertificatesV1beta1(),
|
||||
}
|
||||
}
|
||||
|
||||
// Renew takes a certificate using the cert and key.
|
||||
func (r *CertsAPIRenewal) Renew(cfg *certutil.Config) (*x509.Certificate, *rsa.PrivateKey, error) {
|
||||
reqTmp := &x509.CertificateRequest{
|
||||
Subject: pkix.Name{
|
||||
CommonName: cfg.CommonName,
|
||||
Organization: cfg.Organization,
|
||||
},
|
||||
DNSNames: cfg.AltNames.DNSNames,
|
||||
IPAddresses: cfg.AltNames.IPs,
|
||||
}
|
||||
|
||||
key, err := certutil.NewPrivateKey()
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "couldn't create new private key")
|
||||
}
|
||||
|
||||
csr, err := certutil.MakeCSRFromTemplate(key, reqTmp)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "couldn't create certificate signing request")
|
||||
}
|
||||
|
||||
usages := make([]certsapi.KeyUsage, len(cfg.Usages))
|
||||
for i, usage := range cfg.Usages {
|
||||
certsAPIUsage, ok := usageMap[usage]
|
||||
if !ok {
|
||||
return nil, nil, errors.Errorf("unknown key usage: %v", usage)
|
||||
}
|
||||
usages[i] = certsAPIUsage
|
||||
}
|
||||
|
||||
k8sCSR := &certsapi.CertificateSigningRequest{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
GenerateName: fmt.Sprintf("%s-%s-", certAPIPrefixName, cfg.CommonName),
|
||||
},
|
||||
Spec: certsapi.CertificateSigningRequestSpec{
|
||||
Request: csr,
|
||||
Usages: usages,
|
||||
},
|
||||
}
|
||||
|
||||
req, err := r.client.CertificateSigningRequests().Create(k8sCSR)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "couldn't create certificate signing request")
|
||||
}
|
||||
|
||||
fmt.Printf("[certs] certificate request %q created\n", req.Name)
|
||||
|
||||
certData, err := csrutil.WaitForCertificate(r.client.CertificateSigningRequests(), req, watchTimeout)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "certificate failed to appear")
|
||||
}
|
||||
|
||||
cert, err := certutil.ParseCertsPEM(certData)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "couldn't parse issued certificate")
|
||||
}
|
||||
|
||||
if len(cert) != 1 {
|
||||
return nil, nil, errors.Errorf("certificate request %q has %d certificates, wanted exactly 1", req.Name, len(cert))
|
||||
}
|
||||
|
||||
return cert[0], key, nil
|
||||
}
|
||||
|
||||
var usageMap = map[x509.ExtKeyUsage]certsapi.KeyUsage{
|
||||
x509.ExtKeyUsageAny: certsapi.UsageAny,
|
||||
x509.ExtKeyUsageServerAuth: certsapi.UsageServerAuth,
|
||||
x509.ExtKeyUsageClientAuth: certsapi.UsageClientAuth,
|
||||
x509.ExtKeyUsageCodeSigning: certsapi.UsageCodeSigning,
|
||||
x509.ExtKeyUsageEmailProtection: certsapi.UsageEmailProtection,
|
||||
x509.ExtKeyUsageIPSECEndSystem: certsapi.UsageIPsecEndSystem,
|
||||
x509.ExtKeyUsageIPSECTunnel: certsapi.UsageIPsecTunnel,
|
||||
x509.ExtKeyUsageIPSECUser: certsapi.UsageIPsecUser,
|
||||
x509.ExtKeyUsageTimeStamping: certsapi.UsageTimestamping,
|
||||
x509.ExtKeyUsageOCSPSigning: certsapi.UsageOCSPSigning,
|
||||
x509.ExtKeyUsageMicrosoftServerGatedCrypto: certsapi.UsageMicrosoftSGC,
|
||||
x509.ExtKeyUsageNetscapeServerGatedCrypto: certsapi.UsageNetscapSGC,
|
||||
}
|
44
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/renewal/filerenewal.go
generated
vendored
Normal file
44
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/renewal/filerenewal.go
generated
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package renewal
|
||||
|
||||
import (
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
|
||||
certutil "k8s.io/client-go/util/cert"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/util/pkiutil"
|
||||
)
|
||||
|
||||
// FileRenewal renews a certificate using local certs
|
||||
type FileRenewal struct {
|
||||
caCert *x509.Certificate
|
||||
caKey *rsa.PrivateKey
|
||||
}
|
||||
|
||||
// NewFileRenewal takes a certificate pair to construct the Interface.
|
||||
func NewFileRenewal(caCert *x509.Certificate, caKey *rsa.PrivateKey) Interface {
|
||||
return &FileRenewal{
|
||||
caCert: caCert,
|
||||
caKey: caKey,
|
||||
}
|
||||
}
|
||||
|
||||
// Renew takes a certificate using the cert and key
|
||||
func (r *FileRenewal) Renew(cfg *certutil.Config) (*x509.Certificate, *rsa.PrivateKey, error) {
|
||||
return pkiutil.NewCertAndKey(r.caCert, r.caKey, cfg)
|
||||
}
|
61
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/renewal/filerenewal_test.go
generated
vendored
Normal file
61
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/renewal/filerenewal_test.go
generated
vendored
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package renewal
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"testing"
|
||||
|
||||
certutil "k8s.io/client-go/util/cert"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/phases/certs"
|
||||
)
|
||||
|
||||
func TestFileRenew(t *testing.T) {
|
||||
caCertCfg := &certutil.Config{CommonName: "kubernetes"}
|
||||
caCert, caKey, err := certs.NewCACertAndKey(caCertCfg)
|
||||
if err != nil {
|
||||
t.Fatalf("couldn't create CA: %v", err)
|
||||
}
|
||||
|
||||
fr := NewFileRenewal(caCert, caKey)
|
||||
|
||||
certCfg := &certutil.Config{
|
||||
CommonName: "test-certs",
|
||||
AltNames: certutil.AltNames{
|
||||
DNSNames: []string{"test-domain.space"},
|
||||
},
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
}
|
||||
|
||||
cert, _, err := fr.Renew(certCfg)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error renewing cert: %v", err)
|
||||
}
|
||||
|
||||
pool := x509.NewCertPool()
|
||||
pool.AddCert(caCert)
|
||||
|
||||
_, err = cert.Verify(x509.VerifyOptions{
|
||||
DNSName: "test-domain.space",
|
||||
Roots: pool,
|
||||
KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf("couldn't verify new cert: %v", err)
|
||||
}
|
||||
|
||||
}
|
29
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/renewal/interface.go
generated
vendored
Normal file
29
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/renewal/interface.go
generated
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package renewal
|
||||
|
||||
import (
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
|
||||
certutil "k8s.io/client-go/util/cert"
|
||||
)
|
||||
|
||||
// Interface represents a standard way to renew a certificate.
|
||||
type Interface interface {
|
||||
Renew(*certutil.Config) (*x509.Certificate, *rsa.PrivateKey, error)
|
||||
}
|
62
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/renewal/renewal.go
generated
vendored
Normal file
62
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/renewal/renewal.go
generated
vendored
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package renewal
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
certutil "k8s.io/client-go/util/cert"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/util/pkiutil"
|
||||
)
|
||||
|
||||
// RenewExistingCert loads a certificate file, uses the renew interface to renew it,
|
||||
// and saves the resulting certificate and key over the old one.
|
||||
func RenewExistingCert(certsDir, baseName string, impl Interface) error {
|
||||
certificatePath, _ := pkiutil.PathsForCertAndKey(certsDir, baseName)
|
||||
certs, err := certutil.CertsFromFile(certificatePath)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to load existing certificate %s", baseName)
|
||||
}
|
||||
|
||||
if len(certs) != 1 {
|
||||
return errors.Errorf("wanted exactly one certificate, got %d", len(certs))
|
||||
}
|
||||
|
||||
cfg := certToConfig(certs[0])
|
||||
newCert, newKey, err := impl.Renew(cfg)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to renew certificate %s", baseName)
|
||||
}
|
||||
|
||||
if err := pkiutil.WriteCertAndKey(certsDir, baseName, newCert, newKey); err != nil {
|
||||
return errors.Wrapf(err, "failed to write new certificate %s", baseName)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func certToConfig(cert *x509.Certificate) *certutil.Config {
|
||||
return &certutil.Config{
|
||||
CommonName: cert.Subject.CommonName,
|
||||
Organization: cert.Subject.Organization,
|
||||
AltNames: certutil.AltNames{
|
||||
IPs: cert.IPAddresses,
|
||||
DNSNames: cert.DNSNames,
|
||||
},
|
||||
Usages: cert.ExtKeyUsage,
|
||||
}
|
||||
}
|
239
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/renewal/renewal_test.go
generated
vendored
Normal file
239
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/renewal/renewal_test.go
generated
vendored
Normal file
@ -0,0 +1,239 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package renewal
|
||||
|
||||
import (
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"net"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
certsapi "k8s.io/api/certificates/v1beta1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
fakecerts "k8s.io/client-go/kubernetes/typed/certificates/v1beta1/fake"
|
||||
k8stesting "k8s.io/client-go/testing"
|
||||
certutil "k8s.io/client-go/util/cert"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/phases/certs"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/util/pkiutil"
|
||||
testutil "k8s.io/kubernetes/cmd/kubeadm/test"
|
||||
certtestutil "k8s.io/kubernetes/cmd/kubeadm/test/certs"
|
||||
)
|
||||
|
||||
func TestRenewImplementations(t *testing.T) {
|
||||
caCertCfg := &certutil.Config{CommonName: "kubernetes"}
|
||||
caCert, caKey, err := certs.NewCACertAndKey(caCertCfg)
|
||||
if err != nil {
|
||||
t.Fatalf("couldn't create CA: %v", err)
|
||||
}
|
||||
|
||||
client := &fakecerts.FakeCertificatesV1beta1{
|
||||
Fake: &k8stesting.Fake{},
|
||||
}
|
||||
certReq := getCertReq(t, caCert, caKey)
|
||||
certReqNoCert := certReq.DeepCopy()
|
||||
certReqNoCert.Status.Certificate = nil
|
||||
client.AddReactor("get", "certificatesigningrequests", defaultReactionFunc(certReq))
|
||||
watcher := watch.NewFakeWithChanSize(3, false)
|
||||
watcher.Add(certReqNoCert)
|
||||
watcher.Modify(certReqNoCert)
|
||||
watcher.Modify(certReq)
|
||||
client.AddWatchReactor("certificatesigningrequests", k8stesting.DefaultWatchReactor(watcher, nil))
|
||||
|
||||
// override the timeout so tests are faster
|
||||
watchTimeout = time.Second
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
impl Interface
|
||||
}{
|
||||
{
|
||||
name: "filerenewal",
|
||||
impl: NewFileRenewal(caCert, caKey),
|
||||
},
|
||||
{
|
||||
name: "certs api",
|
||||
impl: &CertsAPIRenewal{
|
||||
client: client,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
|
||||
certCfg := &certutil.Config{
|
||||
CommonName: "test-certs",
|
||||
AltNames: certutil.AltNames{
|
||||
DNSNames: []string{"test-domain.space"},
|
||||
},
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
}
|
||||
|
||||
cert, _, err := test.impl.Renew(certCfg)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error renewing cert: %v", err)
|
||||
}
|
||||
|
||||
pool := x509.NewCertPool()
|
||||
pool.AddCert(caCert)
|
||||
|
||||
_, err = cert.Verify(x509.VerifyOptions{
|
||||
DNSName: "test-domain.space",
|
||||
Roots: pool,
|
||||
KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf("couldn't verify new cert: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func defaultReactionFunc(obj runtime.Object) k8stesting.ReactionFunc {
|
||||
return func(act k8stesting.Action) (bool, runtime.Object, error) {
|
||||
return true, obj, nil
|
||||
}
|
||||
}
|
||||
|
||||
func getCertReq(t *testing.T, caCert *x509.Certificate, caKey *rsa.PrivateKey) *certsapi.CertificateSigningRequest {
|
||||
cert, _, err := pkiutil.NewCertAndKey(caCert, caKey, &certutil.Config{
|
||||
CommonName: "testcert",
|
||||
AltNames: certutil.AltNames{
|
||||
DNSNames: []string{"test-domain.space"},
|
||||
},
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("couldn't generate cert: %v", err)
|
||||
}
|
||||
|
||||
return &certsapi.CertificateSigningRequest{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "testcert",
|
||||
},
|
||||
Status: certsapi.CertificateSigningRequestStatus{
|
||||
Conditions: []certsapi.CertificateSigningRequestCondition{
|
||||
{
|
||||
Type: certsapi.CertificateApproved,
|
||||
},
|
||||
},
|
||||
Certificate: certutil.EncodeCertPEM(cert),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestCertToConfig(t *testing.T) {
|
||||
expectedConfig := &certutil.Config{
|
||||
CommonName: "test-common-name",
|
||||
Organization: []string{"sig-cluster-lifecycle"},
|
||||
AltNames: certutil.AltNames{
|
||||
IPs: []net.IP{net.ParseIP("10.100.0.1")},
|
||||
DNSNames: []string{"test-domain.space"},
|
||||
},
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
}
|
||||
|
||||
cert := &x509.Certificate{
|
||||
Subject: pkix.Name{
|
||||
CommonName: "test-common-name",
|
||||
Organization: []string{"sig-cluster-lifecycle"},
|
||||
},
|
||||
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
DNSNames: []string{"test-domain.space"},
|
||||
IPAddresses: []net.IP{net.ParseIP("10.100.0.1")},
|
||||
}
|
||||
|
||||
cfg := certToConfig(cert)
|
||||
|
||||
if cfg.CommonName != expectedConfig.CommonName {
|
||||
t.Errorf("expected common name %q, got %q", expectedConfig.CommonName, cfg.CommonName)
|
||||
}
|
||||
|
||||
if len(cfg.Organization) != 1 || cfg.Organization[0] != expectedConfig.Organization[0] {
|
||||
t.Errorf("expected organization %v, got %v", expectedConfig.Organization, cfg.Organization)
|
||||
|
||||
}
|
||||
|
||||
if len(cfg.Usages) != 1 || cfg.Usages[0] != expectedConfig.Usages[0] {
|
||||
t.Errorf("expected ext key usage %v, got %v", expectedConfig.Usages, cfg.Usages)
|
||||
}
|
||||
|
||||
if len(cfg.AltNames.IPs) != 1 || cfg.AltNames.IPs[0].String() != expectedConfig.AltNames.IPs[0].String() {
|
||||
t.Errorf("expected SAN IPs %v, got %v", expectedConfig.AltNames.IPs, cfg.AltNames.IPs)
|
||||
}
|
||||
|
||||
if len(cfg.AltNames.DNSNames) != 1 || cfg.AltNames.DNSNames[0] != expectedConfig.AltNames.DNSNames[0] {
|
||||
t.Errorf("expected SAN DNSNames %v, got %v", expectedConfig.AltNames.DNSNames, cfg.AltNames.DNSNames)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRenewExistingCert(t *testing.T) {
|
||||
cfg := &certutil.Config{
|
||||
CommonName: "test-common-name",
|
||||
Organization: []string{"sig-cluster-lifecycle"},
|
||||
AltNames: certutil.AltNames{
|
||||
IPs: []net.IP{net.ParseIP("10.100.0.1")},
|
||||
DNSNames: []string{"test-domain.space"},
|
||||
},
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
}
|
||||
|
||||
caCertCfg := &certutil.Config{CommonName: "kubernetes"}
|
||||
caCert, caKey, err := certs.NewCACertAndKey(caCertCfg)
|
||||
if err != nil {
|
||||
t.Fatalf("couldn't create CA: %v", err)
|
||||
}
|
||||
|
||||
cert, key, err := pkiutil.NewCertAndKey(caCert, caKey, cfg)
|
||||
if err != nil {
|
||||
t.Fatalf("couldn't generate certificate: %v", err)
|
||||
}
|
||||
|
||||
dir := testutil.SetupTempDir(t)
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
if err := pkiutil.WriteCertAndKey(dir, "server", cert, key); err != nil {
|
||||
t.Fatalf("couldn't write out certificate")
|
||||
}
|
||||
|
||||
renewer := NewFileRenewal(caCert, caKey)
|
||||
|
||||
if err := RenewExistingCert(dir, "server", renewer); err != nil {
|
||||
t.Fatalf("couldn't renew certificate: %v", err)
|
||||
}
|
||||
|
||||
newCert, err := pkiutil.TryLoadCertFromDisk(dir, "server")
|
||||
if err != nil {
|
||||
t.Fatalf("couldn't load created certificate: %v", err)
|
||||
}
|
||||
|
||||
if newCert.SerialNumber.Cmp(cert.SerialNumber) == 0 {
|
||||
t.Fatal("expected new certificate, but renewed certificate has same serial number")
|
||||
}
|
||||
|
||||
certtestutil.AssertCertificateIsSignedByCa(t, newCert, caCert)
|
||||
certtestutil.AssertCertificateHasClientAuthUsage(t, newCert)
|
||||
certtestutil.AssertCertificateHasOrganizations(t, newCert, cfg.Organization...)
|
||||
certtestutil.AssertCertificateHasCommonName(t, newCert, cfg.CommonName)
|
||||
certtestutil.AssertCertificateHasDNSNames(t, newCert, cfg.AltNames.DNSNames...)
|
||||
certtestutil.AssertCertificateHasIPAddresses(t, newCert, cfg.AltNames.IPs...)
|
||||
}
|
19
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/controlplane/BUILD
generated
vendored
19
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/controlplane/BUILD
generated
vendored
@ -16,14 +16,12 @@ go_test(
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
|
||||
"//cmd/kubeadm/app/constants:go_default_library",
|
||||
"//cmd/kubeadm/app/features:go_default_library",
|
||||
"//cmd/kubeadm/app/phases/certs:go_default_library",
|
||||
"//cmd/kubeadm/test:go_default_library",
|
||||
"//pkg/kubeapiserver/authorizer/modes:go_default_library",
|
||||
"//pkg/util/pointer:go_default_library",
|
||||
"//pkg/util/version:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//staging/src/k8s.io/api/core/v1: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",
|
||||
],
|
||||
)
|
||||
|
||||
@ -36,18 +34,17 @@ go_library(
|
||||
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/phases/controlplane",
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
|
||||
"//cmd/kubeadm/app/apis/kubeadm/v1alpha2:go_default_library",
|
||||
"//cmd/kubeadm/app/constants:go_default_library",
|
||||
"//cmd/kubeadm/app/features:go_default_library",
|
||||
"//cmd/kubeadm/app/images:go_default_library",
|
||||
"//cmd/kubeadm/app/phases/certs:go_default_library",
|
||||
"//cmd/kubeadm/app/util:go_default_library",
|
||||
"//cmd/kubeadm/app/util/staticpod:go_default_library",
|
||||
"//pkg/kubeapiserver/authorizer/modes:go_default_library",
|
||||
"//pkg/util/version:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//staging/src/k8s.io/api/core/v1: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",
|
||||
"//vendor/github.com/pkg/errors:go_default_library",
|
||||
"//vendor/k8s.io/klog:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
|
121
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/controlplane/manifests.go
generated
vendored
121
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/controlplane/manifests.go
generated
vendored
@ -24,48 +24,28 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/util/version"
|
||||
"k8s.io/klog"
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
kubeadmapiv1alpha2 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha2"
|
||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/features"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/images"
|
||||
certphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/certs"
|
||||
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
|
||||
staticpodutil "k8s.io/kubernetes/cmd/kubeadm/app/util/staticpod"
|
||||
authzmodes "k8s.io/kubernetes/pkg/kubeapiserver/authorizer/modes"
|
||||
"k8s.io/kubernetes/pkg/util/version"
|
||||
)
|
||||
|
||||
// CreateInitStaticPodManifestFiles will write all static pod manifest files needed to bring up the control plane.
|
||||
func CreateInitStaticPodManifestFiles(manifestDir string, cfg *kubeadmapi.MasterConfiguration) error {
|
||||
glog.V(1).Infoln("[controlplane] creating static pod files")
|
||||
return createStaticPodFiles(manifestDir, cfg, kubeadmconstants.KubeAPIServer, kubeadmconstants.KubeControllerManager, kubeadmconstants.KubeScheduler)
|
||||
func CreateInitStaticPodManifestFiles(manifestDir string, cfg *kubeadmapi.InitConfiguration) error {
|
||||
klog.V(1).Infoln("[control-plane] creating static Pod files")
|
||||
return CreateStaticPodFiles(manifestDir, cfg, kubeadmconstants.KubeAPIServer, kubeadmconstants.KubeControllerManager, kubeadmconstants.KubeScheduler)
|
||||
}
|
||||
|
||||
// CreateAPIServerStaticPodManifestFile will write APIserver static pod manifest file.
|
||||
func CreateAPIServerStaticPodManifestFile(manifestDir string, cfg *kubeadmapi.MasterConfiguration) error {
|
||||
glog.V(1).Infoln("creating APIserver static pod files")
|
||||
return createStaticPodFiles(manifestDir, cfg, kubeadmconstants.KubeAPIServer)
|
||||
}
|
||||
|
||||
// CreateControllerManagerStaticPodManifestFile will write controller manager static pod manifest file.
|
||||
func CreateControllerManagerStaticPodManifestFile(manifestDir string, cfg *kubeadmapi.MasterConfiguration) error {
|
||||
glog.V(1).Infoln("creating controller manager static pod files")
|
||||
return createStaticPodFiles(manifestDir, cfg, kubeadmconstants.KubeControllerManager)
|
||||
}
|
||||
|
||||
// CreateSchedulerStaticPodManifestFile will write scheduler static pod manifest file.
|
||||
func CreateSchedulerStaticPodManifestFile(manifestDir string, cfg *kubeadmapi.MasterConfiguration) error {
|
||||
glog.V(1).Infoln("creating scheduler static pod files")
|
||||
return createStaticPodFiles(manifestDir, cfg, kubeadmconstants.KubeScheduler)
|
||||
}
|
||||
|
||||
// GetStaticPodSpecs returns all staticPodSpecs actualized to the context of the current MasterConfiguration
|
||||
// GetStaticPodSpecs returns all staticPodSpecs actualized to the context of the current InitConfiguration
|
||||
// NB. this methods holds the information about how kubeadm creates static pod manifests.
|
||||
func GetStaticPodSpecs(cfg *kubeadmapi.MasterConfiguration, k8sVersion *version.Version) map[string]v1.Pod {
|
||||
func GetStaticPodSpecs(cfg *kubeadmapi.InitConfiguration, k8sVersion *version.Version) map[string]v1.Pod {
|
||||
// Get the required hostpath mounts
|
||||
mounts := getHostPathVolumesForTheControlPlane(cfg)
|
||||
|
||||
@ -73,17 +53,17 @@ func GetStaticPodSpecs(cfg *kubeadmapi.MasterConfiguration, k8sVersion *version.
|
||||
staticPodSpecs := map[string]v1.Pod{
|
||||
kubeadmconstants.KubeAPIServer: staticpodutil.ComponentPod(v1.Container{
|
||||
Name: kubeadmconstants.KubeAPIServer,
|
||||
Image: images.GetCoreImage(kubeadmconstants.KubeAPIServer, cfg.GetControlPlaneImageRepository(), cfg.KubernetesVersion, cfg.UnifiedControlPlaneImage),
|
||||
Image: images.GetKubernetesImage(kubeadmconstants.KubeAPIServer, &cfg.ClusterConfiguration),
|
||||
ImagePullPolicy: v1.PullIfNotPresent,
|
||||
Command: getAPIServerCommand(cfg),
|
||||
VolumeMounts: staticpodutil.VolumeMountMapToSlice(mounts.GetVolumeMounts(kubeadmconstants.KubeAPIServer)),
|
||||
LivenessProbe: staticpodutil.ComponentProbe(cfg, kubeadmconstants.KubeAPIServer, int(cfg.API.BindPort), "/healthz", v1.URISchemeHTTPS),
|
||||
LivenessProbe: staticpodutil.ComponentProbe(cfg, kubeadmconstants.KubeAPIServer, int(cfg.LocalAPIEndpoint.BindPort), "/healthz", v1.URISchemeHTTPS),
|
||||
Resources: staticpodutil.ComponentResources("250m"),
|
||||
Env: getProxyEnvVars(),
|
||||
}, mounts.GetVolumes(kubeadmconstants.KubeAPIServer)),
|
||||
kubeadmconstants.KubeControllerManager: staticpodutil.ComponentPod(v1.Container{
|
||||
Name: kubeadmconstants.KubeControllerManager,
|
||||
Image: images.GetCoreImage(kubeadmconstants.KubeControllerManager, cfg.GetControlPlaneImageRepository(), cfg.KubernetesVersion, cfg.UnifiedControlPlaneImage),
|
||||
Image: images.GetKubernetesImage(kubeadmconstants.KubeControllerManager, &cfg.ClusterConfiguration),
|
||||
ImagePullPolicy: v1.PullIfNotPresent,
|
||||
Command: getControllerManagerCommand(cfg, k8sVersion),
|
||||
VolumeMounts: staticpodutil.VolumeMountMapToSlice(mounts.GetVolumeMounts(kubeadmconstants.KubeControllerManager)),
|
||||
@ -93,7 +73,7 @@ func GetStaticPodSpecs(cfg *kubeadmapi.MasterConfiguration, k8sVersion *version.
|
||||
}, mounts.GetVolumes(kubeadmconstants.KubeControllerManager)),
|
||||
kubeadmconstants.KubeScheduler: staticpodutil.ComponentPod(v1.Container{
|
||||
Name: kubeadmconstants.KubeScheduler,
|
||||
Image: images.GetCoreImage(kubeadmconstants.KubeScheduler, cfg.GetControlPlaneImageRepository(), cfg.KubernetesVersion, cfg.UnifiedControlPlaneImage),
|
||||
Image: images.GetKubernetesImage(kubeadmconstants.KubeScheduler, &cfg.ClusterConfiguration),
|
||||
ImagePullPolicy: v1.PullIfNotPresent,
|
||||
Command: getSchedulerCommand(cfg),
|
||||
VolumeMounts: staticpodutil.VolumeMountMapToSlice(mounts.GetVolumeMounts(kubeadmconstants.KubeScheduler)),
|
||||
@ -105,16 +85,16 @@ func GetStaticPodSpecs(cfg *kubeadmapi.MasterConfiguration, k8sVersion *version.
|
||||
return staticPodSpecs
|
||||
}
|
||||
|
||||
// createStaticPodFiles creates all the requested static pod files.
|
||||
func createStaticPodFiles(manifestDir string, cfg *kubeadmapi.MasterConfiguration, componentNames ...string) error {
|
||||
// CreateStaticPodFiles creates all the requested static pod files.
|
||||
func CreateStaticPodFiles(manifestDir string, cfg *kubeadmapi.InitConfiguration, componentNames ...string) error {
|
||||
// TODO: Move the "pkg/util/version".Version object into the internal API instead of always parsing the string
|
||||
k8sVersion, err := version.ParseSemantic(cfg.KubernetesVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// gets the StaticPodSpecs, actualized for the current MasterConfiguration
|
||||
glog.V(1).Infoln("[controlplane] getting StaticPodSpecs")
|
||||
// gets the StaticPodSpecs, actualized for the current InitConfiguration
|
||||
klog.V(1).Infoln("[control-plane] getting StaticPodSpecs")
|
||||
specs := GetStaticPodSpecs(cfg, k8sVersion)
|
||||
|
||||
// creates required static pod specs
|
||||
@ -122,31 +102,26 @@ func createStaticPodFiles(manifestDir string, cfg *kubeadmapi.MasterConfiguratio
|
||||
// retrives the StaticPodSpec for given component
|
||||
spec, exists := specs[componentName]
|
||||
if !exists {
|
||||
return fmt.Errorf("couldn't retrive StaticPodSpec for %s", componentName)
|
||||
return errors.Errorf("couldn't retrive StaticPodSpec for %q", componentName)
|
||||
}
|
||||
|
||||
// writes the StaticPodSpec to disk
|
||||
if err := staticpodutil.WriteStaticPodToDisk(componentName, manifestDir, spec); err != nil {
|
||||
return fmt.Errorf("failed to create static pod manifest file for %q: %v", componentName, err)
|
||||
return errors.Wrapf(err, "failed to create static pod manifest file for %q", componentName)
|
||||
}
|
||||
|
||||
fmt.Printf("[controlplane] wrote Static Pod manifest for component %s to %q\n", componentName, kubeadmconstants.GetStaticPodFilepath(componentName, manifestDir))
|
||||
klog.V(1).Infof("[control-plane] wrote static Pod manifest for component %q to %q\n", componentName, kubeadmconstants.GetStaticPodFilepath(componentName, manifestDir))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// getAPIServerCommand builds the right API server command from the given config object and version
|
||||
func getAPIServerCommand(cfg *kubeadmapi.MasterConfiguration) []string {
|
||||
func getAPIServerCommand(cfg *kubeadmapi.InitConfiguration) []string {
|
||||
defaultArguments := map[string]string{
|
||||
"advertise-address": cfg.API.AdvertiseAddress,
|
||||
"insecure-port": "0",
|
||||
"enable-admission-plugins": "NodeRestriction",
|
||||
// TODO: remove `PersistentVolumeLabel` in kubeadm v1.11, as it's automatically disabled in v1.11.
|
||||
// ref: https://github.com/kubernetes/kubernetes/pull/64326
|
||||
// we can't skip it now as we support v1.10 clusters still.
|
||||
// remove it from the unit tests too.
|
||||
"disable-admission-plugins": "PersistentVolumeLabel",
|
||||
"advertise-address": cfg.LocalAPIEndpoint.AdvertiseAddress,
|
||||
"insecure-port": "0",
|
||||
"enable-admission-plugins": "NodeRestriction",
|
||||
"service-cluster-ip-range": cfg.Networking.ServiceSubnet,
|
||||
"service-account-key-file": filepath.Join(cfg.CertificatesDir, kubeadmconstants.ServiceAccountPublicKeyName),
|
||||
"client-ca-file": filepath.Join(cfg.CertificatesDir, kubeadmconstants.CACertName),
|
||||
@ -155,7 +130,7 @@ func getAPIServerCommand(cfg *kubeadmapi.MasterConfiguration) []string {
|
||||
"kubelet-client-certificate": filepath.Join(cfg.CertificatesDir, kubeadmconstants.APIServerKubeletClientCertName),
|
||||
"kubelet-client-key": filepath.Join(cfg.CertificatesDir, kubeadmconstants.APIServerKubeletClientKeyName),
|
||||
"enable-bootstrap-token-auth": "true",
|
||||
"secure-port": fmt.Sprintf("%d", cfg.API.BindPort),
|
||||
"secure-port": fmt.Sprintf("%d", cfg.LocalAPIEndpoint.BindPort),
|
||||
"allow-privileged": "true",
|
||||
"kubelet-preferred-address-types": "InternalIP,ExternalIP,Hostname",
|
||||
// add options to configure the front proxy. Without the generated client cert, this will never be useable
|
||||
@ -185,34 +160,24 @@ func getAPIServerCommand(cfg *kubeadmapi.MasterConfiguration) []string {
|
||||
}
|
||||
} else {
|
||||
// Default to etcd static pod on localhost
|
||||
defaultArguments["etcd-servers"] = "https://127.0.0.1:2379"
|
||||
defaultArguments["etcd-servers"] = fmt.Sprintf("https://127.0.0.1:%d", kubeadmconstants.EtcdListenClientPort)
|
||||
defaultArguments["etcd-cafile"] = filepath.Join(cfg.CertificatesDir, kubeadmconstants.EtcdCACertName)
|
||||
defaultArguments["etcd-certfile"] = filepath.Join(cfg.CertificatesDir, kubeadmconstants.APIServerEtcdClientCertName)
|
||||
defaultArguments["etcd-keyfile"] = filepath.Join(cfg.CertificatesDir, kubeadmconstants.APIServerEtcdClientKeyName)
|
||||
}
|
||||
|
||||
if features.Enabled(cfg.FeatureGates, features.HighAvailability) {
|
||||
defaultArguments["endpoint-reconciler-type"] = kubeadmconstants.LeaseEndpointReconcilerType
|
||||
}
|
||||
|
||||
if features.Enabled(cfg.FeatureGates, features.DynamicKubeletConfig) {
|
||||
defaultArguments["feature-gates"] = "DynamicKubeletConfig=true"
|
||||
}
|
||||
|
||||
if features.Enabled(cfg.FeatureGates, features.Auditing) {
|
||||
defaultArguments["audit-policy-file"] = kubeadmconstants.GetStaticPodAuditPolicyFile()
|
||||
defaultArguments["audit-log-path"] = filepath.Join(kubeadmconstants.StaticPodAuditPolicyLogDir, kubeadmconstants.AuditPolicyLogFile)
|
||||
if cfg.AuditPolicyConfiguration.LogMaxAge == nil {
|
||||
defaultArguments["audit-log-maxage"] = fmt.Sprintf("%d", kubeadmapiv1alpha2.DefaultAuditPolicyLogMaxAge)
|
||||
} else {
|
||||
defaultArguments["audit-log-maxage"] = fmt.Sprintf("%d", *cfg.AuditPolicyConfiguration.LogMaxAge)
|
||||
// Apply user configurations for local etcd
|
||||
if cfg.Etcd.Local != nil {
|
||||
if value, ok := cfg.Etcd.Local.ExtraArgs["advertise-client-urls"]; ok {
|
||||
defaultArguments["etcd-servers"] = value
|
||||
}
|
||||
}
|
||||
}
|
||||
if cfg.APIServerExtraArgs == nil {
|
||||
cfg.APIServerExtraArgs = map[string]string{}
|
||||
|
||||
if cfg.APIServer.ExtraArgs == nil {
|
||||
cfg.APIServer.ExtraArgs = map[string]string{}
|
||||
}
|
||||
cfg.APIServerExtraArgs["authorization-mode"] = getAuthzModes(cfg.APIServerExtraArgs["authorization-mode"])
|
||||
command = append(command, kubeadmutil.BuildArgumentListFromMap(defaultArguments, cfg.APIServerExtraArgs)...)
|
||||
cfg.APIServer.ExtraArgs["authorization-mode"] = getAuthzModes(cfg.APIServer.ExtraArgs["authorization-mode"])
|
||||
command = append(command, kubeadmutil.BuildArgumentListFromMap(defaultArguments, cfg.APIServer.ExtraArgs)...)
|
||||
|
||||
return command
|
||||
}
|
||||
@ -279,7 +244,7 @@ func calcNodeCidrSize(podSubnet string) string {
|
||||
}
|
||||
|
||||
// getControllerManagerCommand builds the right controller manager command from the given config object and version
|
||||
func getControllerManagerCommand(cfg *kubeadmapi.MasterConfiguration, k8sVersion *version.Version) []string {
|
||||
func getControllerManagerCommand(cfg *kubeadmapi.InitConfiguration, k8sVersion *version.Version) []string {
|
||||
defaultArguments := map[string]string{
|
||||
"address": "127.0.0.1",
|
||||
"leader-elect": "true",
|
||||
@ -292,6 +257,14 @@ func getControllerManagerCommand(cfg *kubeadmapi.MasterConfiguration, k8sVersion
|
||||
"controllers": "*,bootstrapsigner,tokencleaner",
|
||||
}
|
||||
|
||||
//add the extra arguments for v1.12+
|
||||
if k8sVersion.Major() >= 1 && k8sVersion.Minor() >= 12 {
|
||||
defaultArguments["authentication-kubeconfig"] = filepath.Join(kubeadmconstants.KubernetesDir, kubeadmconstants.ControllerManagerKubeConfigFileName)
|
||||
defaultArguments["authorization-kubeconfig"] = filepath.Join(kubeadmconstants.KubernetesDir, kubeadmconstants.ControllerManagerKubeConfigFileName)
|
||||
defaultArguments["client-ca-file"] = filepath.Join(cfg.CertificatesDir, kubeadmconstants.CACertName)
|
||||
defaultArguments["requestheader-client-ca-file"] = filepath.Join(cfg.CertificatesDir, kubeadmconstants.FrontProxyCACertName)
|
||||
}
|
||||
|
||||
// If using external CA, pass empty string to controller manager instead of ca.key/ca.crt path,
|
||||
// so that the csrsigning controller fails to start
|
||||
if res, _ := certphase.UsingExternalCA(cfg); res {
|
||||
@ -309,13 +282,13 @@ func getControllerManagerCommand(cfg *kubeadmapi.MasterConfiguration, k8sVersion
|
||||
}
|
||||
|
||||
command := []string{"kube-controller-manager"}
|
||||
command = append(command, kubeadmutil.BuildArgumentListFromMap(defaultArguments, cfg.ControllerManagerExtraArgs)...)
|
||||
command = append(command, kubeadmutil.BuildArgumentListFromMap(defaultArguments, cfg.ControllerManager.ExtraArgs)...)
|
||||
|
||||
return command
|
||||
}
|
||||
|
||||
// getSchedulerCommand builds the right scheduler command from the given config object and version
|
||||
func getSchedulerCommand(cfg *kubeadmapi.MasterConfiguration) []string {
|
||||
func getSchedulerCommand(cfg *kubeadmapi.InitConfiguration) []string {
|
||||
defaultArguments := map[string]string{
|
||||
"address": "127.0.0.1",
|
||||
"leader-elect": "true",
|
||||
@ -323,7 +296,7 @@ func getSchedulerCommand(cfg *kubeadmapi.MasterConfiguration) []string {
|
||||
}
|
||||
|
||||
command := []string{"kube-scheduler"}
|
||||
command = append(command, kubeadmutil.BuildArgumentListFromMap(defaultArguments, cfg.SchedulerExtraArgs)...)
|
||||
command = append(command, kubeadmutil.BuildArgumentListFromMap(defaultArguments, cfg.Scheduler.ExtraArgs)...)
|
||||
return command
|
||||
}
|
||||
|
||||
|
555
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/controlplane/manifests_test.go
generated
vendored
555
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/controlplane/manifests_test.go
generated
vendored
@ -26,15 +26,13 @@ import (
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/util/version"
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/features"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/phases/certs"
|
||||
authzmodes "k8s.io/kubernetes/pkg/kubeapiserver/authorizer/modes"
|
||||
"k8s.io/kubernetes/pkg/util/version"
|
||||
|
||||
testutil "k8s.io/kubernetes/cmd/kubeadm/test"
|
||||
utilpointer "k8s.io/kubernetes/pkg/util/pointer"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -45,8 +43,10 @@ const (
|
||||
func TestGetStaticPodSpecs(t *testing.T) {
|
||||
|
||||
// Creates a Master Configuration
|
||||
cfg := &kubeadmapi.MasterConfiguration{
|
||||
KubernetesVersion: "v1.9.0",
|
||||
cfg := &kubeadmapi.InitConfiguration{
|
||||
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
|
||||
KubernetesVersion: "v1.9.0",
|
||||
},
|
||||
}
|
||||
|
||||
// Executes GetStaticPodSpecs
|
||||
@ -89,24 +89,19 @@ func TestGetStaticPodSpecs(t *testing.T) {
|
||||
func TestCreateStaticPodFilesAndWrappers(t *testing.T) {
|
||||
|
||||
var tests = []struct {
|
||||
createStaticPodFunction func(outDir string, cfg *kubeadmapi.MasterConfiguration) error
|
||||
expectedFiles []string
|
||||
components []string
|
||||
}{
|
||||
{ // CreateInitStaticPodManifestFiles
|
||||
createStaticPodFunction: CreateInitStaticPodManifestFiles,
|
||||
expectedFiles: []string{kubeadmconstants.KubeAPIServer, kubeadmconstants.KubeControllerManager, kubeadmconstants.KubeScheduler},
|
||||
{
|
||||
components: []string{kubeadmconstants.KubeAPIServer, kubeadmconstants.KubeControllerManager, kubeadmconstants.KubeScheduler},
|
||||
},
|
||||
{ // CreateAPIServerStaticPodManifestFile
|
||||
createStaticPodFunction: CreateAPIServerStaticPodManifestFile,
|
||||
expectedFiles: []string{kubeadmconstants.KubeAPIServer},
|
||||
{
|
||||
components: []string{kubeadmconstants.KubeAPIServer},
|
||||
},
|
||||
{ // CreateControllerManagerStaticPodManifestFile
|
||||
createStaticPodFunction: CreateControllerManagerStaticPodManifestFile,
|
||||
expectedFiles: []string{kubeadmconstants.KubeControllerManager},
|
||||
{
|
||||
components: []string{kubeadmconstants.KubeControllerManager},
|
||||
},
|
||||
{ // CreateSchedulerStaticPodManifestFile
|
||||
createStaticPodFunction: CreateSchedulerStaticPodManifestFile,
|
||||
expectedFiles: []string{kubeadmconstants.KubeScheduler},
|
||||
{
|
||||
components: []string{kubeadmconstants.KubeScheduler},
|
||||
},
|
||||
}
|
||||
|
||||
@ -117,22 +112,24 @@ func TestCreateStaticPodFilesAndWrappers(t *testing.T) {
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
// Creates a Master Configuration
|
||||
cfg := &kubeadmapi.MasterConfiguration{
|
||||
KubernetesVersion: "v1.9.0",
|
||||
cfg := &kubeadmapi.InitConfiguration{
|
||||
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
|
||||
KubernetesVersion: "v1.9.0",
|
||||
},
|
||||
}
|
||||
|
||||
// Execute createStaticPodFunction
|
||||
manifestPath := filepath.Join(tmpdir, kubeadmconstants.ManifestsSubDirName)
|
||||
err := test.createStaticPodFunction(manifestPath, cfg)
|
||||
err := CreateStaticPodFiles(manifestPath, cfg, test.components...)
|
||||
if err != nil {
|
||||
t.Errorf("Error executing createStaticPodFunction: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
// Assert expected files are there
|
||||
testutil.AssertFilesCount(t, manifestPath, len(test.expectedFiles))
|
||||
testutil.AssertFilesCount(t, manifestPath, len(test.components))
|
||||
|
||||
for _, fileName := range test.expectedFiles {
|
||||
for _, fileName := range test.components {
|
||||
testutil.AssertFileExists(t, manifestPath, fileName+".yaml")
|
||||
}
|
||||
}
|
||||
@ -141,21 +138,22 @@ func TestCreateStaticPodFilesAndWrappers(t *testing.T) {
|
||||
func TestGetAPIServerCommand(t *testing.T) {
|
||||
var tests = []struct {
|
||||
name string
|
||||
cfg *kubeadmapi.MasterConfiguration
|
||||
cfg *kubeadmapi.InitConfiguration
|
||||
expected []string
|
||||
}{
|
||||
{
|
||||
name: "testing defaults",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadmapi.API{BindPort: 123, AdvertiseAddress: "1.2.3.4"},
|
||||
Networking: kubeadmapi.Networking{ServiceSubnet: "bar"},
|
||||
CertificatesDir: testCertsDir,
|
||||
cfg: &kubeadmapi.InitConfiguration{
|
||||
LocalAPIEndpoint: kubeadmapi.APIEndpoint{BindPort: 123, AdvertiseAddress: "1.2.3.4"},
|
||||
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
|
||||
Networking: kubeadmapi.Networking{ServiceSubnet: "bar"},
|
||||
CertificatesDir: testCertsDir,
|
||||
},
|
||||
},
|
||||
expected: []string{
|
||||
"kube-apiserver",
|
||||
"--insecure-port=0",
|
||||
"--enable-admission-plugins=NodeRestriction",
|
||||
"--disable-admission-plugins=PersistentVolumeLabel",
|
||||
"--service-cluster-ip-range=bar",
|
||||
"--service-account-key-file=" + testCertsDir + "/sa.pub",
|
||||
"--client-ca-file=" + testCertsDir + "/ca.crt",
|
||||
@ -176,7 +174,7 @@ func TestGetAPIServerCommand(t *testing.T) {
|
||||
"--requestheader-allowed-names=front-proxy-client",
|
||||
"--authorization-mode=Node,RBAC",
|
||||
"--advertise-address=1.2.3.4",
|
||||
"--etcd-servers=https://127.0.0.1:2379",
|
||||
fmt.Sprintf("--etcd-servers=https://127.0.0.1:%d", kubeadmconstants.EtcdListenClientPort),
|
||||
"--etcd-cafile=" + testCertsDir + "/etcd/ca.crt",
|
||||
"--etcd-certfile=" + testCertsDir + "/apiserver-etcd-client.crt",
|
||||
"--etcd-keyfile=" + testCertsDir + "/apiserver-etcd-client.key",
|
||||
@ -184,21 +182,17 @@ func TestGetAPIServerCommand(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "ignores the audit policy if the feature gate is not enabled",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadmapi.API{BindPort: 123, AdvertiseAddress: "4.3.2.1"},
|
||||
Networking: kubeadmapi.Networking{ServiceSubnet: "bar"},
|
||||
CertificatesDir: testCertsDir,
|
||||
AuditPolicyConfiguration: kubeadmapi.AuditPolicyConfiguration{
|
||||
Path: "/foo/bar",
|
||||
LogDir: "/foo/baz",
|
||||
LogMaxAge: utilpointer.Int32Ptr(10),
|
||||
cfg: &kubeadmapi.InitConfiguration{
|
||||
LocalAPIEndpoint: kubeadmapi.APIEndpoint{BindPort: 123, AdvertiseAddress: "4.3.2.1"},
|
||||
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
|
||||
Networking: kubeadmapi.Networking{ServiceSubnet: "bar"},
|
||||
CertificatesDir: testCertsDir,
|
||||
},
|
||||
},
|
||||
expected: []string{
|
||||
"kube-apiserver",
|
||||
"--insecure-port=0",
|
||||
"--enable-admission-plugins=NodeRestriction",
|
||||
"--disable-admission-plugins=PersistentVolumeLabel",
|
||||
"--service-cluster-ip-range=bar",
|
||||
"--service-account-key-file=" + testCertsDir + "/sa.pub",
|
||||
"--client-ca-file=" + testCertsDir + "/ca.crt",
|
||||
@ -219,7 +213,7 @@ func TestGetAPIServerCommand(t *testing.T) {
|
||||
"--requestheader-allowed-names=front-proxy-client",
|
||||
"--authorization-mode=Node,RBAC",
|
||||
"--advertise-address=4.3.2.1",
|
||||
"--etcd-servers=https://127.0.0.1:2379",
|
||||
fmt.Sprintf("--etcd-servers=https://127.0.0.1:%d", kubeadmconstants.EtcdListenClientPort),
|
||||
"--etcd-cafile=" + testCertsDir + "/etcd/ca.crt",
|
||||
"--etcd-certfile=" + testCertsDir + "/apiserver-etcd-client.crt",
|
||||
"--etcd-keyfile=" + testCertsDir + "/apiserver-etcd-client.key",
|
||||
@ -227,16 +221,17 @@ func TestGetAPIServerCommand(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "ipv6 advertise address",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadmapi.API{BindPort: 123, AdvertiseAddress: "2001:db8::1"},
|
||||
Networking: kubeadmapi.Networking{ServiceSubnet: "bar"},
|
||||
CertificatesDir: testCertsDir,
|
||||
cfg: &kubeadmapi.InitConfiguration{
|
||||
LocalAPIEndpoint: kubeadmapi.APIEndpoint{BindPort: 123, AdvertiseAddress: "2001:db8::1"},
|
||||
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
|
||||
Networking: kubeadmapi.Networking{ServiceSubnet: "bar"},
|
||||
CertificatesDir: testCertsDir,
|
||||
},
|
||||
},
|
||||
expected: []string{
|
||||
"kube-apiserver",
|
||||
"--insecure-port=0",
|
||||
"--enable-admission-plugins=NodeRestriction",
|
||||
"--disable-admission-plugins=PersistentVolumeLabel",
|
||||
"--service-cluster-ip-range=bar",
|
||||
"--service-account-key-file=" + testCertsDir + "/sa.pub",
|
||||
"--client-ca-file=" + testCertsDir + "/ca.crt",
|
||||
@ -257,7 +252,7 @@ func TestGetAPIServerCommand(t *testing.T) {
|
||||
"--requestheader-allowed-names=front-proxy-client",
|
||||
"--authorization-mode=Node,RBAC",
|
||||
"--advertise-address=2001:db8::1",
|
||||
"--etcd-servers=https://127.0.0.1:2379",
|
||||
fmt.Sprintf("--etcd-servers=https://127.0.0.1:%d", kubeadmconstants.EtcdListenClientPort),
|
||||
"--etcd-cafile=" + testCertsDir + "/etcd/ca.crt",
|
||||
"--etcd-certfile=" + testCertsDir + "/apiserver-etcd-client.crt",
|
||||
"--etcd-keyfile=" + testCertsDir + "/apiserver-etcd-client.key",
|
||||
@ -265,25 +260,25 @@ func TestGetAPIServerCommand(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "an external etcd with custom ca, certs and keys",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadmapi.API{BindPort: 123, AdvertiseAddress: "2001:db8::1"},
|
||||
Networking: kubeadmapi.Networking{ServiceSubnet: "bar"},
|
||||
FeatureGates: map[string]bool{features.HighAvailability: true},
|
||||
Etcd: kubeadmapi.Etcd{
|
||||
External: &kubeadmapi.ExternalEtcd{
|
||||
Endpoints: []string{"https://8.6.4.1:2379", "https://8.6.4.2:2379"},
|
||||
CAFile: "fuz",
|
||||
CertFile: "fiz",
|
||||
KeyFile: "faz",
|
||||
cfg: &kubeadmapi.InitConfiguration{
|
||||
LocalAPIEndpoint: kubeadmapi.APIEndpoint{BindPort: 123, AdvertiseAddress: "2001:db8::1"},
|
||||
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
|
||||
Networking: kubeadmapi.Networking{ServiceSubnet: "bar"},
|
||||
Etcd: kubeadmapi.Etcd{
|
||||
External: &kubeadmapi.ExternalEtcd{
|
||||
Endpoints: []string{"https://8.6.4.1:2379", "https://8.6.4.2:2379"},
|
||||
CAFile: "fuz",
|
||||
CertFile: "fiz",
|
||||
KeyFile: "faz",
|
||||
},
|
||||
},
|
||||
CertificatesDir: testCertsDir,
|
||||
},
|
||||
CertificatesDir: testCertsDir,
|
||||
},
|
||||
expected: []string{
|
||||
"kube-apiserver",
|
||||
"--insecure-port=0",
|
||||
"--enable-admission-plugins=NodeRestriction",
|
||||
"--disable-admission-plugins=PersistentVolumeLabel",
|
||||
"--service-cluster-ip-range=bar",
|
||||
"--service-account-key-file=" + testCertsDir + "/sa.pub",
|
||||
"--client-ca-file=" + testCertsDir + "/ca.crt",
|
||||
@ -308,26 +303,26 @@ func TestGetAPIServerCommand(t *testing.T) {
|
||||
"--etcd-cafile=fuz",
|
||||
"--etcd-certfile=fiz",
|
||||
"--etcd-keyfile=faz",
|
||||
fmt.Sprintf("--endpoint-reconciler-type=%s", kubeadmconstants.LeaseEndpointReconcilerType),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "an insecure etcd",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadmapi.API{BindPort: 123, AdvertiseAddress: "2001:db8::1"},
|
||||
Networking: kubeadmapi.Networking{ServiceSubnet: "bar"},
|
||||
Etcd: kubeadmapi.Etcd{
|
||||
External: &kubeadmapi.ExternalEtcd{
|
||||
Endpoints: []string{"http://127.0.0.1:2379", "http://127.0.0.1:2380"},
|
||||
cfg: &kubeadmapi.InitConfiguration{
|
||||
LocalAPIEndpoint: kubeadmapi.APIEndpoint{BindPort: 123, AdvertiseAddress: "2001:db8::1"},
|
||||
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
|
||||
Networking: kubeadmapi.Networking{ServiceSubnet: "bar"},
|
||||
Etcd: kubeadmapi.Etcd{
|
||||
External: &kubeadmapi.ExternalEtcd{
|
||||
Endpoints: []string{"http://127.0.0.1:2379", "http://127.0.0.1:2380"},
|
||||
},
|
||||
},
|
||||
CertificatesDir: testCertsDir,
|
||||
},
|
||||
CertificatesDir: testCertsDir,
|
||||
},
|
||||
expected: []string{
|
||||
"kube-apiserver",
|
||||
"--insecure-port=0",
|
||||
"--enable-admission-plugins=NodeRestriction",
|
||||
"--disable-admission-plugins=PersistentVolumeLabel",
|
||||
"--service-cluster-ip-range=bar",
|
||||
"--service-account-key-file=" + testCertsDir + "/sa.pub",
|
||||
"--client-ca-file=" + testCertsDir + "/ca.crt",
|
||||
@ -352,110 +347,28 @@ func TestGetAPIServerCommand(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "auditing and HA are enabled with a custom log max age of 0",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadmapi.API{BindPort: 123, AdvertiseAddress: "2001:db8::1"},
|
||||
Networking: kubeadmapi.Networking{ServiceSubnet: "bar"},
|
||||
FeatureGates: map[string]bool{features.HighAvailability: true, features.Auditing: true},
|
||||
CertificatesDir: testCertsDir,
|
||||
AuditPolicyConfiguration: kubeadmapi.AuditPolicyConfiguration{
|
||||
LogMaxAge: utilpointer.Int32Ptr(0),
|
||||
name: "test APIServer.ExtraArgs works as expected",
|
||||
cfg: &kubeadmapi.InitConfiguration{
|
||||
LocalAPIEndpoint: kubeadmapi.APIEndpoint{BindPort: 123, AdvertiseAddress: "1.2.3.4"},
|
||||
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
|
||||
Networking: kubeadmapi.Networking{ServiceSubnet: "bar"},
|
||||
CertificatesDir: testCertsDir,
|
||||
APIServer: kubeadmapi.APIServer{
|
||||
ControlPlaneComponent: kubeadmapi.ControlPlaneComponent{
|
||||
ExtraArgs: map[string]string{
|
||||
"service-cluster-ip-range": "baz",
|
||||
"advertise-address": "9.9.9.9",
|
||||
"audit-policy-file": "/etc/config/audit.yaml",
|
||||
"audit-log-path": "/var/log/kubernetes",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: []string{
|
||||
"kube-apiserver",
|
||||
"--insecure-port=0",
|
||||
"--enable-admission-plugins=NodeRestriction",
|
||||
"--disable-admission-plugins=PersistentVolumeLabel",
|
||||
"--service-cluster-ip-range=bar",
|
||||
"--service-account-key-file=" + testCertsDir + "/sa.pub",
|
||||
"--client-ca-file=" + testCertsDir + "/ca.crt",
|
||||
"--tls-cert-file=" + testCertsDir + "/apiserver.crt",
|
||||
"--tls-private-key-file=" + testCertsDir + "/apiserver.key",
|
||||
"--kubelet-client-certificate=" + testCertsDir + "/apiserver-kubelet-client.crt",
|
||||
"--kubelet-client-key=" + testCertsDir + "/apiserver-kubelet-client.key",
|
||||
fmt.Sprintf("--secure-port=%d", 123),
|
||||
"--allow-privileged=true",
|
||||
"--kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname",
|
||||
"--enable-bootstrap-token-auth=true",
|
||||
"--proxy-client-cert-file=/var/lib/certs/front-proxy-client.crt",
|
||||
"--proxy-client-key-file=/var/lib/certs/front-proxy-client.key",
|
||||
"--requestheader-username-headers=X-Remote-User",
|
||||
"--requestheader-group-headers=X-Remote-Group",
|
||||
"--requestheader-extra-headers-prefix=X-Remote-Extra-",
|
||||
"--requestheader-client-ca-file=" + testCertsDir + "/front-proxy-ca.crt",
|
||||
"--requestheader-allowed-names=front-proxy-client",
|
||||
"--authorization-mode=Node,RBAC",
|
||||
"--advertise-address=2001:db8::1",
|
||||
"--etcd-servers=https://127.0.0.1:2379",
|
||||
"--etcd-cafile=" + testCertsDir + "/etcd/ca.crt",
|
||||
"--etcd-certfile=" + testCertsDir + "/apiserver-etcd-client.crt",
|
||||
"--etcd-keyfile=" + testCertsDir + "/apiserver-etcd-client.key",
|
||||
fmt.Sprintf("--endpoint-reconciler-type=%s", kubeadmconstants.LeaseEndpointReconcilerType),
|
||||
"--audit-policy-file=/etc/kubernetes/audit/audit.yaml",
|
||||
"--audit-log-path=/var/log/kubernetes/audit/audit.log",
|
||||
"--audit-log-maxage=0",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ensure the DynamicKubelet flag gets passed through",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadmapi.API{BindPort: 123, AdvertiseAddress: "1.2.3.4"},
|
||||
Networking: kubeadmapi.Networking{ServiceSubnet: "bar"},
|
||||
CertificatesDir: testCertsDir,
|
||||
FeatureGates: map[string]bool{features.DynamicKubeletConfig: true},
|
||||
},
|
||||
expected: []string{
|
||||
"kube-apiserver",
|
||||
"--insecure-port=0",
|
||||
"--enable-admission-plugins=NodeRestriction",
|
||||
"--disable-admission-plugins=PersistentVolumeLabel",
|
||||
"--service-cluster-ip-range=bar",
|
||||
"--service-account-key-file=" + testCertsDir + "/sa.pub",
|
||||
"--client-ca-file=" + testCertsDir + "/ca.crt",
|
||||
"--tls-cert-file=" + testCertsDir + "/apiserver.crt",
|
||||
"--tls-private-key-file=" + testCertsDir + "/apiserver.key",
|
||||
"--kubelet-client-certificate=" + testCertsDir + "/apiserver-kubelet-client.crt",
|
||||
"--kubelet-client-key=" + testCertsDir + "/apiserver-kubelet-client.key",
|
||||
"--enable-bootstrap-token-auth=true",
|
||||
"--secure-port=123",
|
||||
"--allow-privileged=true",
|
||||
"--kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname",
|
||||
"--proxy-client-cert-file=/var/lib/certs/front-proxy-client.crt",
|
||||
"--proxy-client-key-file=/var/lib/certs/front-proxy-client.key",
|
||||
"--requestheader-username-headers=X-Remote-User",
|
||||
"--requestheader-group-headers=X-Remote-Group",
|
||||
"--requestheader-extra-headers-prefix=X-Remote-Extra-",
|
||||
"--requestheader-client-ca-file=" + testCertsDir + "/front-proxy-ca.crt",
|
||||
"--requestheader-allowed-names=front-proxy-client",
|
||||
"--authorization-mode=Node,RBAC",
|
||||
"--advertise-address=1.2.3.4",
|
||||
"--etcd-servers=https://127.0.0.1:2379",
|
||||
"--etcd-cafile=" + testCertsDir + "/etcd/ca.crt",
|
||||
"--etcd-certfile=" + testCertsDir + "/apiserver-etcd-client.crt",
|
||||
"--etcd-keyfile=" + testCertsDir + "/apiserver-etcd-client.key",
|
||||
"--feature-gates=DynamicKubeletConfig=true",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "test APIServerExtraArgs works as expected",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadmapi.API{BindPort: 123, AdvertiseAddress: "1.2.3.4"},
|
||||
Networking: kubeadmapi.Networking{ServiceSubnet: "bar"},
|
||||
CertificatesDir: testCertsDir,
|
||||
FeatureGates: map[string]bool{features.DynamicKubeletConfig: true, features.Auditing: true},
|
||||
APIServerExtraArgs: map[string]string{
|
||||
"service-cluster-ip-range": "baz",
|
||||
"advertise-address": "9.9.9.9",
|
||||
"audit-policy-file": "/etc/config/audit.yaml",
|
||||
"audit-log-path": "/var/log/kubernetes",
|
||||
},
|
||||
},
|
||||
expected: []string{
|
||||
"kube-apiserver",
|
||||
"--insecure-port=0",
|
||||
"--enable-admission-plugins=NodeRestriction",
|
||||
"--disable-admission-plugins=PersistentVolumeLabel",
|
||||
"--service-cluster-ip-range=baz",
|
||||
"--service-account-key-file=" + testCertsDir + "/sa.pub",
|
||||
"--client-ca-file=" + testCertsDir + "/ca.crt",
|
||||
@ -476,31 +389,34 @@ func TestGetAPIServerCommand(t *testing.T) {
|
||||
"--requestheader-allowed-names=front-proxy-client",
|
||||
"--authorization-mode=Node,RBAC",
|
||||
"--advertise-address=9.9.9.9",
|
||||
"--etcd-servers=https://127.0.0.1:2379",
|
||||
fmt.Sprintf("--etcd-servers=https://127.0.0.1:%d", kubeadmconstants.EtcdListenClientPort),
|
||||
"--etcd-cafile=" + testCertsDir + "/etcd/ca.crt",
|
||||
"--etcd-certfile=" + testCertsDir + "/apiserver-etcd-client.crt",
|
||||
"--etcd-keyfile=" + testCertsDir + "/apiserver-etcd-client.key",
|
||||
"--feature-gates=DynamicKubeletConfig=true",
|
||||
"--audit-policy-file=/etc/config/audit.yaml",
|
||||
"--audit-log-path=/var/log/kubernetes",
|
||||
"--audit-log-maxage=2",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "authorization-mode extra-args ABAC",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadmapi.API{BindPort: 123, AdvertiseAddress: "1.2.3.4"},
|
||||
Networking: kubeadmapi.Networking{ServiceSubnet: "bar"},
|
||||
CertificatesDir: testCertsDir,
|
||||
APIServerExtraArgs: map[string]string{
|
||||
"authorization-mode": authzmodes.ModeABAC,
|
||||
cfg: &kubeadmapi.InitConfiguration{
|
||||
LocalAPIEndpoint: kubeadmapi.APIEndpoint{BindPort: 123, AdvertiseAddress: "1.2.3.4"},
|
||||
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
|
||||
Networking: kubeadmapi.Networking{ServiceSubnet: "bar"},
|
||||
CertificatesDir: testCertsDir,
|
||||
APIServer: kubeadmapi.APIServer{
|
||||
ControlPlaneComponent: kubeadmapi.ControlPlaneComponent{
|
||||
ExtraArgs: map[string]string{
|
||||
"authorization-mode": authzmodes.ModeABAC,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: []string{
|
||||
"kube-apiserver",
|
||||
"--insecure-port=0",
|
||||
"--enable-admission-plugins=NodeRestriction",
|
||||
"--disable-admission-plugins=PersistentVolumeLabel",
|
||||
"--service-cluster-ip-range=bar",
|
||||
"--service-account-key-file=" + testCertsDir + "/sa.pub",
|
||||
"--client-ca-file=" + testCertsDir + "/ca.crt",
|
||||
@ -521,7 +437,7 @@ func TestGetAPIServerCommand(t *testing.T) {
|
||||
"--requestheader-allowed-names=front-proxy-client",
|
||||
"--authorization-mode=Node,RBAC,ABAC",
|
||||
"--advertise-address=1.2.3.4",
|
||||
"--etcd-servers=https://127.0.0.1:2379",
|
||||
fmt.Sprintf("--etcd-servers=https://127.0.0.1:%d", kubeadmconstants.EtcdListenClientPort),
|
||||
"--etcd-cafile=" + testCertsDir + "/etcd/ca.crt",
|
||||
"--etcd-certfile=" + testCertsDir + "/apiserver-etcd-client.crt",
|
||||
"--etcd-keyfile=" + testCertsDir + "/apiserver-etcd-client.key",
|
||||
@ -529,19 +445,24 @@ func TestGetAPIServerCommand(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "insecure-port extra-args",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadmapi.API{BindPort: 123, AdvertiseAddress: "1.2.3.4"},
|
||||
Networking: kubeadmapi.Networking{ServiceSubnet: "bar"},
|
||||
CertificatesDir: testCertsDir,
|
||||
APIServerExtraArgs: map[string]string{
|
||||
"insecure-port": "1234",
|
||||
cfg: &kubeadmapi.InitConfiguration{
|
||||
LocalAPIEndpoint: kubeadmapi.APIEndpoint{BindPort: 123, AdvertiseAddress: "1.2.3.4"},
|
||||
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
|
||||
Networking: kubeadmapi.Networking{ServiceSubnet: "bar"},
|
||||
CertificatesDir: testCertsDir,
|
||||
APIServer: kubeadmapi.APIServer{
|
||||
ControlPlaneComponent: kubeadmapi.ControlPlaneComponent{
|
||||
ExtraArgs: map[string]string{
|
||||
"insecure-port": "1234",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: []string{
|
||||
"kube-apiserver",
|
||||
"--insecure-port=1234",
|
||||
"--enable-admission-plugins=NodeRestriction",
|
||||
"--disable-admission-plugins=PersistentVolumeLabel",
|
||||
"--service-cluster-ip-range=bar",
|
||||
"--service-account-key-file=" + testCertsDir + "/sa.pub",
|
||||
"--client-ca-file=" + testCertsDir + "/ca.crt",
|
||||
@ -562,7 +483,7 @@ func TestGetAPIServerCommand(t *testing.T) {
|
||||
"--requestheader-allowed-names=front-proxy-client",
|
||||
"--authorization-mode=Node,RBAC",
|
||||
"--advertise-address=1.2.3.4",
|
||||
"--etcd-servers=https://127.0.0.1:2379",
|
||||
fmt.Sprintf("--etcd-servers=https://127.0.0.1:%d", kubeadmconstants.EtcdListenClientPort),
|
||||
"--etcd-cafile=" + testCertsDir + "/etcd/ca.crt",
|
||||
"--etcd-certfile=" + testCertsDir + "/apiserver-etcd-client.crt",
|
||||
"--etcd-keyfile=" + testCertsDir + "/apiserver-etcd-client.key",
|
||||
@ -570,19 +491,24 @@ func TestGetAPIServerCommand(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "authorization-mode extra-args Webhook",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadmapi.API{BindPort: 123, AdvertiseAddress: "1.2.3.4"},
|
||||
Networking: kubeadmapi.Networking{ServiceSubnet: "bar"},
|
||||
CertificatesDir: testCertsDir,
|
||||
APIServerExtraArgs: map[string]string{
|
||||
"authorization-mode": authzmodes.ModeWebhook,
|
||||
cfg: &kubeadmapi.InitConfiguration{
|
||||
LocalAPIEndpoint: kubeadmapi.APIEndpoint{BindPort: 123, AdvertiseAddress: "1.2.3.4"},
|
||||
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
|
||||
Networking: kubeadmapi.Networking{ServiceSubnet: "bar"},
|
||||
CertificatesDir: testCertsDir,
|
||||
APIServer: kubeadmapi.APIServer{
|
||||
ControlPlaneComponent: kubeadmapi.ControlPlaneComponent{
|
||||
ExtraArgs: map[string]string{
|
||||
"authorization-mode": authzmodes.ModeWebhook,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: []string{
|
||||
"kube-apiserver",
|
||||
"--insecure-port=0",
|
||||
"--enable-admission-plugins=NodeRestriction",
|
||||
"--disable-admission-plugins=PersistentVolumeLabel",
|
||||
"--service-cluster-ip-range=bar",
|
||||
"--service-account-key-file=" + testCertsDir + "/sa.pub",
|
||||
"--client-ca-file=" + testCertsDir + "/ca.crt",
|
||||
@ -603,7 +529,7 @@ func TestGetAPIServerCommand(t *testing.T) {
|
||||
"--requestheader-allowed-names=front-proxy-client",
|
||||
"--authorization-mode=Node,RBAC,Webhook",
|
||||
"--advertise-address=1.2.3.4",
|
||||
"--etcd-servers=https://127.0.0.1:2379",
|
||||
fmt.Sprintf("--etcd-servers=https://127.0.0.1:%d", kubeadmconstants.EtcdListenClientPort),
|
||||
"--etcd-cafile=" + testCertsDir + "/etcd/ca.crt",
|
||||
"--etcd-certfile=" + testCertsDir + "/apiserver-etcd-client.crt",
|
||||
"--etcd-keyfile=" + testCertsDir + "/apiserver-etcd-client.key",
|
||||
@ -644,14 +570,121 @@ func removeCommon(left, right []string) []string {
|
||||
func TestGetControllerManagerCommand(t *testing.T) {
|
||||
var tests = []struct {
|
||||
name string
|
||||
cfg *kubeadmapi.MasterConfiguration
|
||||
cfg *kubeadmapi.ClusterConfiguration
|
||||
expected []string
|
||||
}{
|
||||
{
|
||||
name: "custom certs dir",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
name: "custom certs dir for v1.12.0-beta.2",
|
||||
cfg: &kubeadmapi.ClusterConfiguration{
|
||||
CertificatesDir: testCertsDir,
|
||||
KubernetesVersion: "v1.7.0",
|
||||
KubernetesVersion: "v1.12.0-beta.2",
|
||||
},
|
||||
expected: []string{
|
||||
"kube-controller-manager",
|
||||
"--address=127.0.0.1",
|
||||
"--leader-elect=true",
|
||||
"--kubeconfig=" + kubeadmconstants.KubernetesDir + "/controller-manager.conf",
|
||||
"--root-ca-file=" + testCertsDir + "/ca.crt",
|
||||
"--service-account-private-key-file=" + testCertsDir + "/sa.key",
|
||||
"--cluster-signing-cert-file=" + testCertsDir + "/ca.crt",
|
||||
"--cluster-signing-key-file=" + testCertsDir + "/ca.key",
|
||||
"--use-service-account-credentials=true",
|
||||
"--controllers=*,bootstrapsigner,tokencleaner",
|
||||
"--authentication-kubeconfig=" + kubeadmconstants.KubernetesDir + "/controller-manager.conf",
|
||||
"--authorization-kubeconfig=" + kubeadmconstants.KubernetesDir + "/controller-manager.conf",
|
||||
"--client-ca-file=" + testCertsDir + "/ca.crt",
|
||||
"--requestheader-client-ca-file=" + testCertsDir + "/front-proxy-ca.crt",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "custom cloudprovider for v1.12.0-beta.2",
|
||||
cfg: &kubeadmapi.ClusterConfiguration{
|
||||
Networking: kubeadmapi.Networking{PodSubnet: "10.0.1.15/16"},
|
||||
CertificatesDir: testCertsDir,
|
||||
KubernetesVersion: "v1.12.0-beta.2",
|
||||
},
|
||||
expected: []string{
|
||||
"kube-controller-manager",
|
||||
"--address=127.0.0.1",
|
||||
"--leader-elect=true",
|
||||
"--kubeconfig=" + kubeadmconstants.KubernetesDir + "/controller-manager.conf",
|
||||
"--root-ca-file=" + testCertsDir + "/ca.crt",
|
||||
"--service-account-private-key-file=" + testCertsDir + "/sa.key",
|
||||
"--cluster-signing-cert-file=" + testCertsDir + "/ca.crt",
|
||||
"--cluster-signing-key-file=" + testCertsDir + "/ca.key",
|
||||
"--use-service-account-credentials=true",
|
||||
"--controllers=*,bootstrapsigner,tokencleaner",
|
||||
"--authentication-kubeconfig=" + kubeadmconstants.KubernetesDir + "/controller-manager.conf",
|
||||
"--authorization-kubeconfig=" + kubeadmconstants.KubernetesDir + "/controller-manager.conf",
|
||||
"--client-ca-file=" + testCertsDir + "/ca.crt",
|
||||
"--requestheader-client-ca-file=" + testCertsDir + "/front-proxy-ca.crt",
|
||||
"--allocate-node-cidrs=true",
|
||||
"--cluster-cidr=10.0.1.15/16",
|
||||
"--node-cidr-mask-size=24",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "custom extra-args for v1.12.0-beta.2",
|
||||
cfg: &kubeadmapi.ClusterConfiguration{
|
||||
Networking: kubeadmapi.Networking{PodSubnet: "10.0.1.15/16"},
|
||||
ControllerManager: kubeadmapi.ControlPlaneComponent{
|
||||
ExtraArgs: map[string]string{"node-cidr-mask-size": "20"},
|
||||
},
|
||||
CertificatesDir: testCertsDir,
|
||||
KubernetesVersion: "v1.12.0-beta.2",
|
||||
},
|
||||
expected: []string{
|
||||
"kube-controller-manager",
|
||||
"--address=127.0.0.1",
|
||||
"--leader-elect=true",
|
||||
"--kubeconfig=" + kubeadmconstants.KubernetesDir + "/controller-manager.conf",
|
||||
"--root-ca-file=" + testCertsDir + "/ca.crt",
|
||||
"--service-account-private-key-file=" + testCertsDir + "/sa.key",
|
||||
"--cluster-signing-cert-file=" + testCertsDir + "/ca.crt",
|
||||
"--cluster-signing-key-file=" + testCertsDir + "/ca.key",
|
||||
"--use-service-account-credentials=true",
|
||||
"--controllers=*,bootstrapsigner,tokencleaner",
|
||||
"--authentication-kubeconfig=" + kubeadmconstants.KubernetesDir + "/controller-manager.conf",
|
||||
"--authorization-kubeconfig=" + kubeadmconstants.KubernetesDir + "/controller-manager.conf",
|
||||
"--client-ca-file=" + testCertsDir + "/ca.crt",
|
||||
"--requestheader-client-ca-file=" + testCertsDir + "/front-proxy-ca.crt",
|
||||
"--allocate-node-cidrs=true",
|
||||
"--cluster-cidr=10.0.1.15/16",
|
||||
"--node-cidr-mask-size=20",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "custom IPv6 networking for v1.12.0-beta.2",
|
||||
cfg: &kubeadmapi.ClusterConfiguration{
|
||||
Networking: kubeadmapi.Networking{PodSubnet: "2001:db8::/64"},
|
||||
CertificatesDir: testCertsDir,
|
||||
KubernetesVersion: "v1.12.0-beta.2",
|
||||
},
|
||||
expected: []string{
|
||||
"kube-controller-manager",
|
||||
"--address=127.0.0.1",
|
||||
"--leader-elect=true",
|
||||
"--kubeconfig=" + kubeadmconstants.KubernetesDir + "/controller-manager.conf",
|
||||
"--root-ca-file=" + testCertsDir + "/ca.crt",
|
||||
"--service-account-private-key-file=" + testCertsDir + "/sa.key",
|
||||
"--cluster-signing-cert-file=" + testCertsDir + "/ca.crt",
|
||||
"--cluster-signing-key-file=" + testCertsDir + "/ca.key",
|
||||
"--use-service-account-credentials=true",
|
||||
"--controllers=*,bootstrapsigner,tokencleaner",
|
||||
"--authentication-kubeconfig=" + kubeadmconstants.KubernetesDir + "/controller-manager.conf",
|
||||
"--authorization-kubeconfig=" + kubeadmconstants.KubernetesDir + "/controller-manager.conf",
|
||||
"--client-ca-file=" + testCertsDir + "/ca.crt",
|
||||
"--requestheader-client-ca-file=" + testCertsDir + "/front-proxy-ca.crt",
|
||||
"--allocate-node-cidrs=true",
|
||||
"--cluster-cidr=2001:db8::/64",
|
||||
"--node-cidr-mask-size=80",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "custom certs dir for v1.11.3",
|
||||
cfg: &kubeadmapi.ClusterConfiguration{
|
||||
CertificatesDir: testCertsDir,
|
||||
KubernetesVersion: "v1.11.3",
|
||||
},
|
||||
expected: []string{
|
||||
"kube-controller-manager",
|
||||
@ -667,11 +700,11 @@ func TestGetControllerManagerCommand(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "custom cloudprovider",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
name: "custom cloudprovider for v1.11.3",
|
||||
cfg: &kubeadmapi.ClusterConfiguration{
|
||||
Networking: kubeadmapi.Networking{PodSubnet: "10.0.1.15/16"},
|
||||
CertificatesDir: testCertsDir,
|
||||
KubernetesVersion: "v1.7.0",
|
||||
KubernetesVersion: "v1.11.3",
|
||||
},
|
||||
expected: []string{
|
||||
"kube-controller-manager",
|
||||
@ -690,12 +723,14 @@ func TestGetControllerManagerCommand(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "custom extra-args",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
Networking: kubeadmapi.Networking{PodSubnet: "10.0.1.15/16"},
|
||||
ControllerManagerExtraArgs: map[string]string{"node-cidr-mask-size": "20"},
|
||||
CertificatesDir: testCertsDir,
|
||||
KubernetesVersion: "v1.7.0",
|
||||
name: "custom extra-args for v1.11.3",
|
||||
cfg: &kubeadmapi.ClusterConfiguration{
|
||||
Networking: kubeadmapi.Networking{PodSubnet: "10.0.1.15/16"},
|
||||
ControllerManager: kubeadmapi.ControlPlaneComponent{
|
||||
ExtraArgs: map[string]string{"node-cidr-mask-size": "20"},
|
||||
},
|
||||
CertificatesDir: testCertsDir,
|
||||
KubernetesVersion: "v1.11.3",
|
||||
},
|
||||
expected: []string{
|
||||
"kube-controller-manager",
|
||||
@ -714,11 +749,11 @@ func TestGetControllerManagerCommand(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "custom IPv6 networking",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
name: "custom IPv6 networking for v1.11.3",
|
||||
cfg: &kubeadmapi.ClusterConfiguration{
|
||||
Networking: kubeadmapi.Networking{PodSubnet: "2001:db8::/64"},
|
||||
CertificatesDir: testCertsDir,
|
||||
KubernetesVersion: "v1.7.0",
|
||||
KubernetesVersion: "v1.11.3",
|
||||
},
|
||||
expected: []string{
|
||||
"kube-controller-manager",
|
||||
@ -739,7 +774,11 @@ func TestGetControllerManagerCommand(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, rt := range tests {
|
||||
actual := getControllerManagerCommand(rt.cfg, version.MustParseSemantic(rt.cfg.KubernetesVersion))
|
||||
// TODO: Make getControllerManagerCommand accept a ClusterConfiguration object instead of InitConfiguration
|
||||
initcfg := &kubeadmapi.InitConfiguration{
|
||||
ClusterConfiguration: *rt.cfg,
|
||||
}
|
||||
actual := getControllerManagerCommand(initcfg, version.MustParseSemantic(rt.cfg.KubernetesVersion))
|
||||
sort.Strings(actual)
|
||||
sort.Strings(rt.expected)
|
||||
if !reflect.DeepEqual(actual, rt.expected) {
|
||||
@ -828,17 +867,76 @@ func TestGetControllerManagerCommandExternalCA(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
cfg *kubeadmapi.MasterConfiguration
|
||||
cfg *kubeadmapi.InitConfiguration
|
||||
caKeyPresent bool
|
||||
expectedArgFunc func(dir string) []string
|
||||
}{
|
||||
{
|
||||
name: "caKeyPresent-false",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
KubernetesVersion: "v1.7.0",
|
||||
API: kubeadmapi.API{AdvertiseAddress: "1.2.3.4"},
|
||||
Networking: kubeadmapi.Networking{ServiceSubnet: "10.96.0.0/12", DNSDomain: "cluster.local"},
|
||||
NodeRegistration: kubeadmapi.NodeRegistrationOptions{Name: "valid-hostname"},
|
||||
name: "caKeyPresent-false for v1.12.0-beta.2",
|
||||
cfg: &kubeadmapi.InitConfiguration{
|
||||
LocalAPIEndpoint: kubeadmapi.APIEndpoint{AdvertiseAddress: "1.2.3.4"},
|
||||
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
|
||||
KubernetesVersion: "v1.12.0-beta.2",
|
||||
Networking: kubeadmapi.Networking{ServiceSubnet: "10.96.0.0/12", DNSDomain: "cluster.local"},
|
||||
},
|
||||
},
|
||||
caKeyPresent: false,
|
||||
expectedArgFunc: func(tmpdir string) []string {
|
||||
return []string{
|
||||
"kube-controller-manager",
|
||||
"--address=127.0.0.1",
|
||||
"--leader-elect=true",
|
||||
"--kubeconfig=" + kubeadmconstants.KubernetesDir + "/controller-manager.conf",
|
||||
"--root-ca-file=" + tmpdir + "/ca.crt",
|
||||
"--service-account-private-key-file=" + tmpdir + "/sa.key",
|
||||
"--cluster-signing-cert-file=",
|
||||
"--cluster-signing-key-file=",
|
||||
"--use-service-account-credentials=true",
|
||||
"--controllers=*,bootstrapsigner,tokencleaner",
|
||||
"--authentication-kubeconfig=" + kubeadmconstants.KubernetesDir + "/controller-manager.conf",
|
||||
"--authorization-kubeconfig=" + kubeadmconstants.KubernetesDir + "/controller-manager.conf",
|
||||
"--client-ca-file=" + tmpdir + "/ca.crt",
|
||||
"--requestheader-client-ca-file=" + tmpdir + "/front-proxy-ca.crt",
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "caKeyPresent true for v1.12.0-beta.2",
|
||||
cfg: &kubeadmapi.InitConfiguration{
|
||||
LocalAPIEndpoint: kubeadmapi.APIEndpoint{AdvertiseAddress: "1.2.3.4"},
|
||||
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
|
||||
KubernetesVersion: "v1.12.0-beta.2",
|
||||
Networking: kubeadmapi.Networking{ServiceSubnet: "10.96.0.0/12", DNSDomain: "cluster.local"},
|
||||
},
|
||||
},
|
||||
caKeyPresent: true,
|
||||
expectedArgFunc: func(tmpdir string) []string {
|
||||
return []string{
|
||||
"kube-controller-manager",
|
||||
"--address=127.0.0.1",
|
||||
"--leader-elect=true",
|
||||
"--kubeconfig=" + kubeadmconstants.KubernetesDir + "/controller-manager.conf",
|
||||
"--root-ca-file=" + tmpdir + "/ca.crt",
|
||||
"--service-account-private-key-file=" + tmpdir + "/sa.key",
|
||||
"--cluster-signing-cert-file=" + tmpdir + "/ca.crt",
|
||||
"--cluster-signing-key-file=" + tmpdir + "/ca.key",
|
||||
"--use-service-account-credentials=true",
|
||||
"--controllers=*,bootstrapsigner,tokencleaner",
|
||||
"--authentication-kubeconfig=" + kubeadmconstants.KubernetesDir + "/controller-manager.conf",
|
||||
"--authorization-kubeconfig=" + kubeadmconstants.KubernetesDir + "/controller-manager.conf",
|
||||
"--client-ca-file=" + tmpdir + "/ca.crt",
|
||||
"--requestheader-client-ca-file=" + tmpdir + "/front-proxy-ca.crt",
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "caKeyPresent-false for v1.11.3",
|
||||
cfg: &kubeadmapi.InitConfiguration{
|
||||
LocalAPIEndpoint: kubeadmapi.APIEndpoint{AdvertiseAddress: "1.2.3.4"},
|
||||
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
|
||||
KubernetesVersion: "v1.11.3",
|
||||
Networking: kubeadmapi.Networking{ServiceSubnet: "10.96.0.0/12", DNSDomain: "cluster.local"},
|
||||
},
|
||||
},
|
||||
caKeyPresent: false,
|
||||
expectedArgFunc: func(tmpdir string) []string {
|
||||
@ -857,12 +955,13 @@ func TestGetControllerManagerCommandExternalCA(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "caKeyPresent true",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
KubernetesVersion: "v1.7.0",
|
||||
API: kubeadmapi.API{AdvertiseAddress: "1.2.3.4"},
|
||||
Networking: kubeadmapi.Networking{ServiceSubnet: "10.96.0.0/12", DNSDomain: "cluster.local"},
|
||||
NodeRegistration: kubeadmapi.NodeRegistrationOptions{Name: "valid-hostname"},
|
||||
name: "caKeyPresent true for v1.11.3",
|
||||
cfg: &kubeadmapi.InitConfiguration{
|
||||
LocalAPIEndpoint: kubeadmapi.APIEndpoint{AdvertiseAddress: "1.2.3.4"},
|
||||
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
|
||||
KubernetesVersion: "v1.11.3",
|
||||
Networking: kubeadmapi.Networking{ServiceSubnet: "10.96.0.0/12", DNSDomain: "cluster.local"},
|
||||
},
|
||||
},
|
||||
caKeyPresent: true,
|
||||
expectedArgFunc: func(tmpdir string) []string {
|
||||
@ -915,12 +1014,12 @@ func TestGetControllerManagerCommandExternalCA(t *testing.T) {
|
||||
func TestGetSchedulerCommand(t *testing.T) {
|
||||
var tests = []struct {
|
||||
name string
|
||||
cfg *kubeadmapi.MasterConfiguration
|
||||
cfg *kubeadmapi.ClusterConfiguration
|
||||
expected []string
|
||||
}{
|
||||
{
|
||||
name: "scheduler defaults",
|
||||
cfg: &kubeadmapi.MasterConfiguration{},
|
||||
cfg: &kubeadmapi.ClusterConfiguration{},
|
||||
expected: []string{
|
||||
"kube-scheduler",
|
||||
"--address=127.0.0.1",
|
||||
@ -931,7 +1030,11 @@ func TestGetSchedulerCommand(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, rt := range tests {
|
||||
actual := getSchedulerCommand(rt.cfg)
|
||||
// TODO: Make getSchedulerCommand accept a ClusterConfiguration object instead of InitConfiguration
|
||||
initcfg := &kubeadmapi.InitConfiguration{
|
||||
ClusterConfiguration: *rt.cfg,
|
||||
}
|
||||
actual := getSchedulerCommand(initcfg)
|
||||
sort.Strings(actual)
|
||||
sort.Strings(rt.expected)
|
||||
if !reflect.DeepEqual(actual, rt.expected) {
|
||||
|
19
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/controlplane/volumes.go
generated
vendored
19
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/controlplane/volumes.go
generated
vendored
@ -26,7 +26,6 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/features"
|
||||
staticpodutil "k8s.io/kubernetes/cmd/kubeadm/app/util/staticpod"
|
||||
)
|
||||
|
||||
@ -43,10 +42,9 @@ const (
|
||||
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
|
||||
func getHostPathVolumesForTheControlPlane(cfg *kubeadmapi.MasterConfiguration) controlPlaneHostPathMounts {
|
||||
func getHostPathVolumesForTheControlPlane(cfg *kubeadmapi.InitConfiguration) controlPlaneHostPathMounts {
|
||||
hostPathDirectoryOrCreate := v1.HostPathDirectoryOrCreate
|
||||
hostPathFileOrCreate := v1.HostPathFileOrCreate
|
||||
hostPathFile := v1.HostPathFile
|
||||
mounts := newControlPlaneHostPathMounts()
|
||||
|
||||
// HostPath volumes for the API Server
|
||||
@ -55,12 +53,7 @@ func getHostPathVolumesForTheControlPlane(cfg *kubeadmapi.MasterConfiguration) c
|
||||
mounts.NewHostPathMount(kubeadmconstants.KubeAPIServer, kubeadmconstants.KubeCertificatesVolumeName, cfg.CertificatesDir, cfg.CertificatesDir, true, &hostPathDirectoryOrCreate)
|
||||
// Read-only mount for the ca certs (/etc/ssl/certs) directory
|
||||
mounts.NewHostPathMount(kubeadmconstants.KubeAPIServer, caCertsVolumeName, caCertsVolumePath, caCertsVolumePath, true, &hostPathDirectoryOrCreate)
|
||||
if features.Enabled(cfg.FeatureGates, features.Auditing) {
|
||||
// Read-only mount for the audit policy file.
|
||||
mounts.NewHostPathMount(kubeadmconstants.KubeAPIServer, kubeadmconstants.KubeAuditPolicyVolumeName, cfg.AuditPolicyConfiguration.Path, kubeadmconstants.GetStaticPodAuditPolicyFile(), true, &hostPathFile)
|
||||
// Write mount for the audit logs.
|
||||
mounts.NewHostPathMount(kubeadmconstants.KubeAPIServer, kubeadmconstants.KubeAuditPolicyLogVolumeName, cfg.AuditPolicyConfiguration.LogDir, kubeadmconstants.StaticPodAuditPolicyLogDir, false, &hostPathDirectoryOrCreate)
|
||||
}
|
||||
|
||||
// If external etcd is specified, mount the directories needed for accessing the CA/serving certs and the private key
|
||||
if cfg.Etcd.External != nil {
|
||||
etcdVols, etcdVolMounts := getEtcdCertVolumes(cfg.Etcd.External, cfg.CertificatesDir)
|
||||
@ -99,9 +92,9 @@ func getHostPathVolumesForTheControlPlane(cfg *kubeadmapi.MasterConfiguration) c
|
||||
|
||||
// Merge user defined mounts and ensure unique volume and volume mount
|
||||
// names
|
||||
mounts.AddExtraHostPathMounts(kubeadmconstants.KubeAPIServer, cfg.APIServerExtraVolumes)
|
||||
mounts.AddExtraHostPathMounts(kubeadmconstants.KubeControllerManager, cfg.ControllerManagerExtraVolumes)
|
||||
mounts.AddExtraHostPathMounts(kubeadmconstants.KubeScheduler, cfg.SchedulerExtraVolumes)
|
||||
mounts.AddExtraHostPathMounts(kubeadmconstants.KubeAPIServer, cfg.APIServer.ExtraVolumes)
|
||||
mounts.AddExtraHostPathMounts(kubeadmconstants.KubeControllerManager, cfg.ControllerManager.ExtraVolumes)
|
||||
mounts.AddExtraHostPathMounts(kubeadmconstants.KubeScheduler, cfg.Scheduler.ExtraVolumes)
|
||||
|
||||
return mounts
|
||||
}
|
||||
@ -151,7 +144,7 @@ func (c *controlPlaneHostPathMounts) AddExtraHostPathMounts(component string, ex
|
||||
for _, extraVol := range extraVols {
|
||||
fmt.Printf("[controlplane] Adding extra host path mount %q to %q\n", extraVol.Name, component)
|
||||
hostPathType := extraVol.PathType
|
||||
c.NewHostPathMount(component, extraVol.Name, extraVol.HostPath, extraVol.MountPath, !extraVol.Writable, &hostPathType)
|
||||
c.NewHostPathMount(component, extraVol.Name, extraVol.HostPath, extraVol.MountPath, extraVol.ReadOnly, &hostPathType)
|
||||
}
|
||||
}
|
||||
|
||||
|
59
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/controlplane/volumes_test.go
generated
vendored
59
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/controlplane/volumes_test.go
generated
vendored
@ -26,7 +26,6 @@ import (
|
||||
"k8s.io/api/core/v1"
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/features"
|
||||
)
|
||||
|
||||
func TestGetEtcdCertVolumes(t *testing.T) {
|
||||
@ -259,7 +258,6 @@ func TestGetEtcdCertVolumes(t *testing.T) {
|
||||
func TestGetHostPathVolumesForTheControlPlane(t *testing.T) {
|
||||
hostPathDirectoryOrCreate := v1.HostPathDirectoryOrCreate
|
||||
hostPathFileOrCreate := v1.HostPathFileOrCreate
|
||||
hostPathFile := v1.HostPathFile
|
||||
volMap := make(map[string]map[string]v1.Volume)
|
||||
volMap[kubeadmconstants.KubeAPIServer] = map[string]v1.Volume{}
|
||||
volMap[kubeadmconstants.KubeAPIServer]["k8s-certs"] = v1.Volume{
|
||||
@ -280,24 +278,6 @@ func TestGetHostPathVolumesForTheControlPlane(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}
|
||||
volMap[kubeadmconstants.KubeAPIServer]["audit"] = v1.Volume{
|
||||
Name: "audit",
|
||||
VolumeSource: v1.VolumeSource{
|
||||
HostPath: &v1.HostPathVolumeSource{
|
||||
Path: "/foo/bar/baz.yaml",
|
||||
Type: &hostPathFile,
|
||||
},
|
||||
},
|
||||
}
|
||||
volMap[kubeadmconstants.KubeAPIServer]["audit-log"] = v1.Volume{
|
||||
Name: "audit-log",
|
||||
VolumeSource: v1.VolumeSource{
|
||||
HostPath: &v1.HostPathVolumeSource{
|
||||
Path: "/bar/foo",
|
||||
Type: &hostPathDirectoryOrCreate,
|
||||
},
|
||||
},
|
||||
}
|
||||
volMap[kubeadmconstants.KubeControllerManager] = map[string]v1.Volume{}
|
||||
volMap[kubeadmconstants.KubeControllerManager]["k8s-certs"] = v1.Volume{
|
||||
Name: "k8s-certs",
|
||||
@ -348,16 +328,6 @@ func TestGetHostPathVolumesForTheControlPlane(t *testing.T) {
|
||||
MountPath: "/etc/ssl/certs",
|
||||
ReadOnly: true,
|
||||
}
|
||||
volMountMap[kubeadmconstants.KubeAPIServer]["audit"] = v1.VolumeMount{
|
||||
Name: "audit",
|
||||
MountPath: "/etc/kubernetes/audit/audit.yaml",
|
||||
ReadOnly: true,
|
||||
}
|
||||
volMountMap[kubeadmconstants.KubeAPIServer]["audit-log"] = v1.VolumeMount{
|
||||
Name: "audit-log",
|
||||
MountPath: "/var/log/kubernetes/audit",
|
||||
ReadOnly: false,
|
||||
}
|
||||
volMountMap[kubeadmconstants.KubeControllerManager] = map[string]v1.VolumeMount{}
|
||||
volMountMap[kubeadmconstants.KubeControllerManager]["k8s-certs"] = v1.VolumeMount{
|
||||
Name: "k8s-certs",
|
||||
@ -502,27 +472,22 @@ func TestGetHostPathVolumesForTheControlPlane(t *testing.T) {
|
||||
ReadOnly: true,
|
||||
}
|
||||
var tests = []struct {
|
||||
cfg *kubeadmapi.MasterConfiguration
|
||||
cfg *kubeadmapi.ClusterConfiguration
|
||||
vol map[string]map[string]v1.Volume
|
||||
volMount map[string]map[string]v1.VolumeMount
|
||||
}{
|
||||
{
|
||||
// Should ignore files in /etc/ssl/certs
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
cfg: &kubeadmapi.ClusterConfiguration{
|
||||
CertificatesDir: testCertsDir,
|
||||
Etcd: kubeadmapi.Etcd{},
|
||||
FeatureGates: map[string]bool{features.Auditing: true},
|
||||
AuditPolicyConfiguration: kubeadmapi.AuditPolicyConfiguration{
|
||||
Path: "/foo/bar/baz.yaml",
|
||||
LogDir: "/bar/foo",
|
||||
},
|
||||
},
|
||||
vol: volMap,
|
||||
volMount: volMountMap,
|
||||
},
|
||||
{
|
||||
// Should ignore files in /etc/ssl/certs and in CertificatesDir
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
cfg: &kubeadmapi.ClusterConfiguration{
|
||||
CertificatesDir: testCertsDir,
|
||||
Etcd: kubeadmapi.Etcd{
|
||||
External: &kubeadmapi.ExternalEtcd{
|
||||
@ -549,7 +514,11 @@ func TestGetHostPathVolumesForTheControlPlane(t *testing.T) {
|
||||
defer func() { caCertsExtraVolumePaths = []string{"/etc/pki", "/usr/share/ca-certificates"} }()
|
||||
|
||||
for _, rt := range tests {
|
||||
mounts := getHostPathVolumesForTheControlPlane(rt.cfg)
|
||||
// TODO: Make getHostPathVolumesForTheControlPlane accept a ClusterConfiguration object instead of InitConfiguration
|
||||
initcfg := &kubeadmapi.InitConfiguration{
|
||||
ClusterConfiguration: *rt.cfg,
|
||||
}
|
||||
mounts := getHostPathVolumesForTheControlPlane(initcfg)
|
||||
|
||||
// Avoid unit test errors when the flexvolume is mounted
|
||||
if _, ok := mounts.volumes[kubeadmconstants.KubeControllerManager][flexvolumeDirVolumeName]; ok {
|
||||
@ -617,28 +586,28 @@ func TestAddExtraHostPathMounts(t *testing.T) {
|
||||
Name: "foo-0",
|
||||
HostPath: "/tmp/qux-0",
|
||||
MountPath: "/tmp/qux-0",
|
||||
Writable: false,
|
||||
ReadOnly: true,
|
||||
PathType: v1.HostPathFile,
|
||||
},
|
||||
{
|
||||
Name: "bar-0",
|
||||
HostPath: "/tmp/asd-0",
|
||||
MountPath: "/tmp/asd-0",
|
||||
Writable: true,
|
||||
ReadOnly: false,
|
||||
PathType: v1.HostPathDirectory,
|
||||
},
|
||||
{
|
||||
Name: "foo-1",
|
||||
HostPath: "/tmp/qux-1",
|
||||
MountPath: "/tmp/qux-1",
|
||||
Writable: false,
|
||||
ReadOnly: true,
|
||||
PathType: v1.HostPathFileOrCreate,
|
||||
},
|
||||
{
|
||||
Name: "bar-1",
|
||||
HostPath: "/tmp/asd-1",
|
||||
MountPath: "/tmp/asd-1",
|
||||
Writable: true,
|
||||
ReadOnly: false,
|
||||
PathType: v1.HostPathDirectoryOrCreate,
|
||||
},
|
||||
}
|
||||
@ -668,8 +637,8 @@ func TestAddExtraHostPathMounts(t *testing.T) {
|
||||
if volMount.MountPath != hostMount.MountPath {
|
||||
t.Errorf("Expected container path %q", hostMount.MountPath)
|
||||
}
|
||||
if volMount.ReadOnly != !hostMount.Writable {
|
||||
t.Errorf("Expected volume writable setting %t", hostMount.Writable)
|
||||
if volMount.ReadOnly != hostMount.ReadOnly {
|
||||
t.Errorf("Expected volume readOnly setting %t", hostMount.ReadOnly)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
8
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/etcd/BUILD
generated
vendored
8
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/etcd/BUILD
generated
vendored
@ -13,6 +13,7 @@ go_test(
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
|
||||
"//cmd/kubeadm/app/constants:go_default_library",
|
||||
"//cmd/kubeadm/app/util/etcd:go_default_library",
|
||||
"//cmd/kubeadm/test:go_default_library",
|
||||
],
|
||||
)
|
||||
@ -26,9 +27,12 @@ go_library(
|
||||
"//cmd/kubeadm/app/constants:go_default_library",
|
||||
"//cmd/kubeadm/app/images:go_default_library",
|
||||
"//cmd/kubeadm/app/util:go_default_library",
|
||||
"//cmd/kubeadm/app/util/etcd:go_default_library",
|
||||
"//cmd/kubeadm/app/util/staticpod:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//vendor/github.com/pkg/errors:go_default_library",
|
||||
"//vendor/k8s.io/klog:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
|
107
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/etcd/local.go
generated
vendored
107
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/etcd/local.go
generated
vendored
@ -19,14 +19,18 @@ package etcd
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/pkg/errors"
|
||||
"k8s.io/klog"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/images"
|
||||
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
|
||||
etcdutil "k8s.io/kubernetes/cmd/kubeadm/app/util/etcd"
|
||||
staticpodutil "k8s.io/kubernetes/cmd/kubeadm/app/util/staticpod"
|
||||
)
|
||||
|
||||
@ -36,10 +40,69 @@ const (
|
||||
)
|
||||
|
||||
// CreateLocalEtcdStaticPodManifestFile will write local etcd static pod manifest file.
|
||||
func CreateLocalEtcdStaticPodManifestFile(manifestDir string, cfg *kubeadmapi.MasterConfiguration) error {
|
||||
glog.V(1).Infoln("creating local etcd static pod manifest file")
|
||||
// gets etcd StaticPodSpec, actualized for the current MasterConfiguration
|
||||
spec := GetEtcdPodSpec(cfg)
|
||||
// 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)
|
||||
func CreateLocalEtcdStaticPodManifestFile(manifestDir string, cfg *kubeadmapi.InitConfiguration) error {
|
||||
if cfg.ClusterConfiguration.Etcd.External != nil {
|
||||
return errors.New("etcd static pod manifest cannot be generated for cluster using external etcd")
|
||||
}
|
||||
// gets etcd StaticPodSpec
|
||||
emptyInitialCluster := []etcdutil.Member{}
|
||||
spec := GetEtcdPodSpec(cfg, emptyInitialCluster)
|
||||
// writes etcd StaticPod to disk
|
||||
if err := staticpodutil.WriteStaticPodToDisk(kubeadmconstants.Etcd, manifestDir, spec); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
klog.V(1).Infof("[etcd] wrote Static Pod manifest for a local etcd instance to %q\n", kubeadmconstants.GetStaticPodFilepath(kubeadmconstants.Etcd, manifestDir))
|
||||
return nil
|
||||
}
|
||||
|
||||
// CheckLocalEtcdClusterStatus verifies health state of local/stacked etcd cluster before installing a new etcd member
|
||||
func CheckLocalEtcdClusterStatus(client clientset.Interface, cfg *kubeadmapi.InitConfiguration) error {
|
||||
fmt.Println("[etcd] Checking Etcd cluster health")
|
||||
|
||||
// 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")
|
||||
etcdClient, err := etcdutil.NewFromCluster(client, cfg.CertificatesDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Checking health state
|
||||
_, err = etcdClient.GetClusterStatus()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "etcd cluster is not healthy")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateStackedEtcdStaticPodManifestFile will write local etcd static pod manifest file
|
||||
// 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.
|
||||
func CreateStackedEtcdStaticPodManifestFile(client clientset.Interface, manifestDir string, cfg *kubeadmapi.InitConfiguration) error {
|
||||
// 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")
|
||||
etcdClient, err := etcdutil.NewFromCluster(client, cfg.CertificatesDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// notifies the other members of the etcd cluster about the joining member
|
||||
etcdPeerAddress := etcdutil.GetPeerURL(cfg)
|
||||
|
||||
klog.V(1).Infof("Adding etcd member: %s", etcdPeerAddress)
|
||||
initialCluster, err := etcdClient.AddMember(cfg.NodeRegistration.Name, etcdPeerAddress)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println("[etcd] Announced new etcd member joining to the existing etcd cluster")
|
||||
klog.V(1).Infof("Updated etcd member list: %v", initialCluster)
|
||||
|
||||
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
|
||||
spec := GetEtcdPodSpec(cfg, initialCluster)
|
||||
// writes etcd StaticPod to disk
|
||||
if err := staticpodutil.WriteStaticPodToDisk(kubeadmconstants.Etcd, manifestDir, spec); err != nil {
|
||||
return err
|
||||
@ -49,9 +112,9 @@ func CreateLocalEtcdStaticPodManifestFile(manifestDir string, cfg *kubeadmapi.Ma
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetEtcdPodSpec returns the etcd static Pod actualized to the context of the current MasterConfiguration
|
||||
// GetEtcdPodSpec returns the etcd static Pod actualized to the context of the current InitConfiguration
|
||||
// NB. GetEtcdPodSpec methods holds the information about how kubeadm creates etcd static pod manifests.
|
||||
func GetEtcdPodSpec(cfg *kubeadmapi.MasterConfiguration) v1.Pod {
|
||||
func GetEtcdPodSpec(cfg *kubeadmapi.InitConfiguration, initialCluster []etcdutil.Member) v1.Pod {
|
||||
pathType := v1.HostPathDirectoryOrCreate
|
||||
etcdMounts := map[string]v1.Volume{
|
||||
etcdVolumeName: staticpodutil.NewVolume(etcdVolumeName, cfg.Etcd.Local.DataDir, &pathType),
|
||||
@ -59,8 +122,8 @@ func GetEtcdPodSpec(cfg *kubeadmapi.MasterConfiguration) v1.Pod {
|
||||
}
|
||||
return staticpodutil.ComponentPod(v1.Container{
|
||||
Name: kubeadmconstants.Etcd,
|
||||
Command: getEtcdCommand(cfg),
|
||||
Image: images.GetCoreImage(kubeadmconstants.Etcd, cfg.ImageRepository, cfg.KubernetesVersion, cfg.Etcd.Local.Image),
|
||||
Command: getEtcdCommand(cfg, initialCluster),
|
||||
Image: images.GetEtcdImage(&cfg.ClusterConfiguration),
|
||||
ImagePullPolicy: v1.PullIfNotPresent,
|
||||
// Mount the etcd datadir path read-write so etcd can store data in a more persistent manner
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
@ -68,20 +131,20 @@ func GetEtcdPodSpec(cfg *kubeadmapi.MasterConfiguration) v1.Pod {
|
||||
staticpodutil.NewVolumeMount(certsVolumeName, cfg.CertificatesDir+"/etcd", false),
|
||||
},
|
||||
LivenessProbe: staticpodutil.EtcdProbe(
|
||||
cfg, kubeadmconstants.Etcd, 2379, cfg.CertificatesDir,
|
||||
cfg, kubeadmconstants.Etcd, kubeadmconstants.EtcdListenClientPort, cfg.CertificatesDir,
|
||||
kubeadmconstants.EtcdCACertName, kubeadmconstants.EtcdHealthcheckClientCertName, kubeadmconstants.EtcdHealthcheckClientKeyName,
|
||||
),
|
||||
}, etcdMounts)
|
||||
}
|
||||
|
||||
// getEtcdCommand builds the right etcd command from the given config object
|
||||
func getEtcdCommand(cfg *kubeadmapi.MasterConfiguration) []string {
|
||||
func getEtcdCommand(cfg *kubeadmapi.InitConfiguration, initialCluster []etcdutil.Member) []string {
|
||||
defaultArguments := map[string]string{
|
||||
"name": cfg.GetNodeName(),
|
||||
"listen-client-urls": "https://127.0.0.1:2379",
|
||||
"advertise-client-urls": "https://127.0.0.1:2379",
|
||||
"listen-peer-urls": "https://127.0.0.1:2380",
|
||||
"initial-advertise-peer-urls": "https://127.0.0.1:2380",
|
||||
"listen-client-urls": fmt.Sprintf("%s,%s", etcdutil.GetClientURLByIP("127.0.0.1"), etcdutil.GetClientURL(cfg)),
|
||||
"advertise-client-urls": etcdutil.GetClientURL(cfg),
|
||||
"listen-peer-urls": etcdutil.GetPeerURL(cfg),
|
||||
"initial-advertise-peer-urls": etcdutil.GetPeerURL(cfg),
|
||||
"data-dir": cfg.Etcd.Local.DataDir,
|
||||
"cert-file": filepath.Join(cfg.CertificatesDir, kubeadmconstants.EtcdServerCertName),
|
||||
"key-file": filepath.Join(cfg.CertificatesDir, kubeadmconstants.EtcdServerKeyName),
|
||||
@ -92,7 +155,19 @@ func getEtcdCommand(cfg *kubeadmapi.MasterConfiguration) []string {
|
||||
"peer-trusted-ca-file": filepath.Join(cfg.CertificatesDir, kubeadmconstants.EtcdCACertName),
|
||||
"peer-client-cert-auth": "true",
|
||||
"snapshot-count": "10000",
|
||||
"initial-cluster": fmt.Sprintf("%s=https://127.0.0.1:2380", cfg.GetNodeName()),
|
||||
}
|
||||
|
||||
if len(initialCluster) == 0 {
|
||||
defaultArguments["initial-cluster"] = fmt.Sprintf("%s=%s", cfg.GetNodeName(), etcdutil.GetPeerURL(cfg))
|
||||
} else {
|
||||
// NB. the joining etcd instance should be part of the initialCluster list
|
||||
endpoints := []string{}
|
||||
for _, member := range initialCluster {
|
||||
endpoints = append(endpoints, fmt.Sprintf("%s=%s", member.Name, member.PeerURL))
|
||||
}
|
||||
|
||||
defaultArguments["initial-cluster"] = strings.Join(endpoints, ",")
|
||||
defaultArguments["initial-cluster-state"] = "existing"
|
||||
}
|
||||
|
||||
command := []string{"etcd"}
|
||||
|
226
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/etcd/local_test.go
generated
vendored
226
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/etcd/local_test.go
generated
vendored
@ -17,6 +17,7 @@ limitations under the License.
|
||||
package etcd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
@ -25,25 +26,25 @@ import (
|
||||
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
|
||||
etcdutil "k8s.io/kubernetes/cmd/kubeadm/app/util/etcd"
|
||||
testutil "k8s.io/kubernetes/cmd/kubeadm/test"
|
||||
)
|
||||
|
||||
func TestGetEtcdPodSpec(t *testing.T) {
|
||||
|
||||
// Creates a Master Configuration
|
||||
cfg := &kubeadmapi.MasterConfiguration{
|
||||
KubernetesVersion: "v1.7.0",
|
||||
Etcd: kubeadmapi.Etcd{
|
||||
Local: &kubeadmapi.LocalEtcd{
|
||||
DataDir: "/var/lib/etcd",
|
||||
Image: "",
|
||||
cfg := &kubeadmapi.InitConfiguration{
|
||||
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
|
||||
KubernetesVersion: "v1.7.0",
|
||||
Etcd: kubeadmapi.Etcd{
|
||||
Local: &kubeadmapi.LocalEtcd{
|
||||
DataDir: "/var/lib/etcd",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Executes GetEtcdPodSpec
|
||||
spec := GetEtcdPodSpec(cfg)
|
||||
spec := GetEtcdPodSpec(cfg, []etcdutil.Member{})
|
||||
|
||||
// Assert each specs refers to the right pod
|
||||
if spec.Spec.Containers[0].Name != kubeadmconstants.Etcd {
|
||||
@ -52,57 +53,85 @@ func TestGetEtcdPodSpec(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCreateLocalEtcdStaticPodManifestFile(t *testing.T) {
|
||||
|
||||
// Create temp folder for the test case
|
||||
tmpdir := testutil.SetupTempDir(t)
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
// Creates a Master Configuration
|
||||
cfg := &kubeadmapi.MasterConfiguration{
|
||||
KubernetesVersion: "v1.7.0",
|
||||
Etcd: kubeadmapi.Etcd{
|
||||
Local: &kubeadmapi.LocalEtcd{
|
||||
DataDir: "/var/lib/etcd",
|
||||
Image: "k8s.gcr.io/etcd",
|
||||
var tests = []struct {
|
||||
cfg *kubeadmapi.InitConfiguration
|
||||
expectedError bool
|
||||
}{
|
||||
{
|
||||
cfg: &kubeadmapi.InitConfiguration{
|
||||
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
|
||||
KubernetesVersion: "v1.7.0",
|
||||
Etcd: kubeadmapi.Etcd{
|
||||
Local: &kubeadmapi.LocalEtcd{
|
||||
DataDir: "/var/lib/etcd",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedError: false,
|
||||
},
|
||||
{
|
||||
cfg: &kubeadmapi.InitConfiguration{
|
||||
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
|
||||
KubernetesVersion: "v1.7.0",
|
||||
Etcd: kubeadmapi.Etcd{
|
||||
External: &kubeadmapi.ExternalEtcd{
|
||||
Endpoints: []string{
|
||||
"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",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedError: true,
|
||||
},
|
||||
}
|
||||
|
||||
// Execute createStaticPodFunction
|
||||
manifestPath := filepath.Join(tmpdir, kubeadmconstants.ManifestsSubDirName)
|
||||
err := CreateLocalEtcdStaticPodManifestFile(manifestPath, cfg)
|
||||
if err != nil {
|
||||
t.Errorf("Error executing CreateEtcdStaticPodManifestFile: %v", err)
|
||||
}
|
||||
for _, test := range tests {
|
||||
// Execute createStaticPodFunction
|
||||
manifestPath := filepath.Join(tmpdir, kubeadmconstants.ManifestsSubDirName)
|
||||
err := CreateLocalEtcdStaticPodManifestFile(manifestPath, test.cfg)
|
||||
|
||||
// Assert expected files are there
|
||||
testutil.AssertFilesCount(t, manifestPath, 1)
|
||||
testutil.AssertFileExists(t, manifestPath, kubeadmconstants.Etcd+".yaml")
|
||||
if !test.expectedError {
|
||||
if err != nil {
|
||||
t.Errorf("CreateLocalEtcdStaticPodManifestFile failed when not expected: %v", err)
|
||||
}
|
||||
// Assert expected files are there
|
||||
testutil.AssertFilesCount(t, manifestPath, 1)
|
||||
testutil.AssertFileExists(t, manifestPath, kubeadmconstants.Etcd+".yaml")
|
||||
} else {
|
||||
testutil.AssertError(t, err, "etcd static pod manifest cannot be generated for cluster using external etcd")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetEtcdCommand(t *testing.T) {
|
||||
var tests = []struct {
|
||||
cfg *kubeadmapi.MasterConfiguration
|
||||
expected []string
|
||||
name string
|
||||
advertiseAddress string
|
||||
nodeName string
|
||||
extraArgs map[string]string
|
||||
initialCluster []etcdutil.Member
|
||||
expected []string
|
||||
}{
|
||||
{
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
NodeRegistration: kubeadmapi.NodeRegistrationOptions{
|
||||
Name: "foo",
|
||||
},
|
||||
Etcd: kubeadmapi.Etcd{
|
||||
Local: &kubeadmapi.LocalEtcd{
|
||||
DataDir: "/var/lib/etcd",
|
||||
},
|
||||
},
|
||||
},
|
||||
name: "Default args - with empty etcd initial cluster",
|
||||
advertiseAddress: "1.2.3.4",
|
||||
nodeName: "foo",
|
||||
expected: []string{
|
||||
"etcd",
|
||||
"--name=foo",
|
||||
"--listen-client-urls=https://127.0.0.1:2379",
|
||||
"--advertise-client-urls=https://127.0.0.1:2379",
|
||||
"--listen-peer-urls=https://127.0.0.1:2380",
|
||||
"--initial-advertise-peer-urls=https://127.0.0.1:2380",
|
||||
fmt.Sprintf("--listen-client-urls=https://127.0.0.1:%d,https://1.2.3.4:%d", kubeadmconstants.EtcdListenClientPort, kubeadmconstants.EtcdListenClientPort),
|
||||
fmt.Sprintf("--advertise-client-urls=https://1.2.3.4:%d", kubeadmconstants.EtcdListenClientPort),
|
||||
fmt.Sprintf("--listen-peer-urls=https://1.2.3.4:%d", kubeadmconstants.EtcdListenPeerPort),
|
||||
fmt.Sprintf("--initial-advertise-peer-urls=https://1.2.3.4:%d", kubeadmconstants.EtcdListenPeerPort),
|
||||
"--data-dir=/var/lib/etcd",
|
||||
"--cert-file=" + kubeadmconstants.EtcdServerCertName,
|
||||
"--key-file=" + kubeadmconstants.EtcdServerKeyName,
|
||||
@ -113,31 +142,53 @@ func TestGetEtcdCommand(t *testing.T) {
|
||||
"--peer-trusted-ca-file=" + kubeadmconstants.EtcdCACertName,
|
||||
"--snapshot-count=10000",
|
||||
"--peer-client-cert-auth=true",
|
||||
"--initial-cluster=foo=https://127.0.0.1:2380",
|
||||
fmt.Sprintf("--initial-cluster=foo=https://1.2.3.4:%d", kubeadmconstants.EtcdListenPeerPort),
|
||||
},
|
||||
},
|
||||
{
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
NodeRegistration: kubeadmapi.NodeRegistrationOptions{
|
||||
Name: "bar",
|
||||
},
|
||||
Etcd: kubeadmapi.Etcd{
|
||||
Local: &kubeadmapi.LocalEtcd{
|
||||
DataDir: "/var/lib/etcd",
|
||||
ExtraArgs: map[string]string{
|
||||
"listen-client-urls": "https://10.0.1.10:2379",
|
||||
"advertise-client-urls": "https://10.0.1.10:2379",
|
||||
},
|
||||
},
|
||||
},
|
||||
name: "Default args - With an existing etcd cluster",
|
||||
advertiseAddress: "1.2.3.4",
|
||||
nodeName: "foo",
|
||||
initialCluster: []etcdutil.Member{
|
||||
{Name: "foo", PeerURL: fmt.Sprintf("https://1.2.3.4:%d", kubeadmconstants.EtcdListenPeerPort)}, // NB. the joining etcd instance should be part of the initialCluster list
|
||||
{Name: "bar", PeerURL: fmt.Sprintf("https://5.6.7.8:%d", kubeadmconstants.EtcdListenPeerPort)},
|
||||
},
|
||||
expected: []string{
|
||||
"etcd",
|
||||
"--name=foo",
|
||||
fmt.Sprintf("--listen-client-urls=https://127.0.0.1:%d,https://1.2.3.4:%d", kubeadmconstants.EtcdListenClientPort, kubeadmconstants.EtcdListenClientPort),
|
||||
fmt.Sprintf("--advertise-client-urls=https://1.2.3.4:%d", kubeadmconstants.EtcdListenClientPort),
|
||||
fmt.Sprintf("--listen-peer-urls=https://1.2.3.4:%d", kubeadmconstants.EtcdListenPeerPort),
|
||||
fmt.Sprintf("--initial-advertise-peer-urls=https://1.2.3.4:%d", kubeadmconstants.EtcdListenPeerPort),
|
||||
"--data-dir=/var/lib/etcd",
|
||||
"--cert-file=" + kubeadmconstants.EtcdServerCertName,
|
||||
"--key-file=" + kubeadmconstants.EtcdServerKeyName,
|
||||
"--trusted-ca-file=" + kubeadmconstants.EtcdCACertName,
|
||||
"--client-cert-auth=true",
|
||||
"--peer-cert-file=" + kubeadmconstants.EtcdPeerCertName,
|
||||
"--peer-key-file=" + kubeadmconstants.EtcdPeerKeyName,
|
||||
"--peer-trusted-ca-file=" + kubeadmconstants.EtcdCACertName,
|
||||
"--snapshot-count=10000",
|
||||
"--peer-client-cert-auth=true",
|
||||
"--initial-cluster-state=existing",
|
||||
fmt.Sprintf("--initial-cluster=foo=https://1.2.3.4:%d,bar=https://5.6.7.8:%d", kubeadmconstants.EtcdListenPeerPort, kubeadmconstants.EtcdListenPeerPort),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Extra args",
|
||||
advertiseAddress: "1.2.3.4",
|
||||
nodeName: "bar",
|
||||
extraArgs: map[string]string{
|
||||
"listen-client-urls": "https://10.0.1.10:2379",
|
||||
"advertise-client-urls": "https://10.0.1.10:2379",
|
||||
},
|
||||
expected: []string{
|
||||
"etcd",
|
||||
"--name=bar",
|
||||
"--listen-client-urls=https://10.0.1.10:2379",
|
||||
"--advertise-client-urls=https://10.0.1.10:2379",
|
||||
"--listen-peer-urls=https://127.0.0.1:2380",
|
||||
"--initial-advertise-peer-urls=https://127.0.0.1:2380",
|
||||
fmt.Sprintf("--listen-peer-urls=https://1.2.3.4:%d", kubeadmconstants.EtcdListenPeerPort),
|
||||
fmt.Sprintf("--initial-advertise-peer-urls=https://1.2.3.4:%d", kubeadmconstants.EtcdListenPeerPort),
|
||||
"--data-dir=/var/lib/etcd",
|
||||
"--cert-file=" + kubeadmconstants.EtcdServerCertName,
|
||||
"--key-file=" + kubeadmconstants.EtcdServerKeyName,
|
||||
@ -148,28 +199,21 @@ func TestGetEtcdCommand(t *testing.T) {
|
||||
"--peer-trusted-ca-file=" + kubeadmconstants.EtcdCACertName,
|
||||
"--snapshot-count=10000",
|
||||
"--peer-client-cert-auth=true",
|
||||
"--initial-cluster=bar=https://127.0.0.1:2380",
|
||||
fmt.Sprintf("--initial-cluster=bar=https://1.2.3.4:%d", kubeadmconstants.EtcdListenPeerPort),
|
||||
},
|
||||
},
|
||||
{
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
NodeRegistration: kubeadmapi.NodeRegistrationOptions{
|
||||
Name: "wombat",
|
||||
},
|
||||
Etcd: kubeadmapi.Etcd{
|
||||
Local: &kubeadmapi.LocalEtcd{
|
||||
DataDir: "/etc/foo",
|
||||
},
|
||||
},
|
||||
},
|
||||
name: "IPv6 advertise address",
|
||||
advertiseAddress: "2001:db8::3",
|
||||
nodeName: "foo",
|
||||
expected: []string{
|
||||
"etcd",
|
||||
"--name=wombat",
|
||||
"--listen-client-urls=https://127.0.0.1:2379",
|
||||
"--advertise-client-urls=https://127.0.0.1:2379",
|
||||
"--listen-peer-urls=https://127.0.0.1:2380",
|
||||
"--initial-advertise-peer-urls=https://127.0.0.1:2380",
|
||||
"--data-dir=/etc/foo",
|
||||
"--name=foo",
|
||||
fmt.Sprintf("--listen-client-urls=https://127.0.0.1:%d,https://[2001:db8::3]:%d", kubeadmconstants.EtcdListenClientPort, kubeadmconstants.EtcdListenClientPort),
|
||||
fmt.Sprintf("--advertise-client-urls=https://[2001:db8::3]:%d", kubeadmconstants.EtcdListenClientPort),
|
||||
fmt.Sprintf("--listen-peer-urls=https://[2001:db8::3]:%d", kubeadmconstants.EtcdListenPeerPort),
|
||||
fmt.Sprintf("--initial-advertise-peer-urls=https://[2001:db8::3]:%d", kubeadmconstants.EtcdListenPeerPort),
|
||||
"--data-dir=/var/lib/etcd",
|
||||
"--cert-file=" + kubeadmconstants.EtcdServerCertName,
|
||||
"--key-file=" + kubeadmconstants.EtcdServerKeyName,
|
||||
"--trusted-ca-file=" + kubeadmconstants.EtcdCACertName,
|
||||
@ -179,17 +223,35 @@ func TestGetEtcdCommand(t *testing.T) {
|
||||
"--peer-trusted-ca-file=" + kubeadmconstants.EtcdCACertName,
|
||||
"--snapshot-count=10000",
|
||||
"--peer-client-cert-auth=true",
|
||||
"--initial-cluster=wombat=https://127.0.0.1:2380",
|
||||
fmt.Sprintf("--initial-cluster=foo=https://[2001:db8::3]:%d", kubeadmconstants.EtcdListenPeerPort),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, rt := range tests {
|
||||
actual := getEtcdCommand(rt.cfg)
|
||||
sort.Strings(actual)
|
||||
sort.Strings(rt.expected)
|
||||
if !reflect.DeepEqual(actual, rt.expected) {
|
||||
t.Errorf("failed getEtcdCommand:\nexpected:\n%v\nsaw:\n%v", rt.expected, actual)
|
||||
}
|
||||
t.Run(rt.name, func(t *testing.T) {
|
||||
cfg := &kubeadmapi.InitConfiguration{
|
||||
LocalAPIEndpoint: kubeadmapi.APIEndpoint{
|
||||
AdvertiseAddress: rt.advertiseAddress,
|
||||
},
|
||||
NodeRegistration: kubeadmapi.NodeRegistrationOptions{
|
||||
Name: rt.nodeName,
|
||||
},
|
||||
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
|
||||
Etcd: kubeadmapi.Etcd{
|
||||
Local: &kubeadmapi.LocalEtcd{
|
||||
DataDir: "/var/lib/etcd",
|
||||
ExtraArgs: rt.extraArgs,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
actual := getEtcdCommand(cfg, rt.initialCluster)
|
||||
sort.Strings(actual)
|
||||
sort.Strings(rt.expected)
|
||||
if !reflect.DeepEqual(actual, rt.expected) {
|
||||
t.Errorf("failed getEtcdCommand:\nexpected:\n%v\nsaw:\n%v", rt.expected, actual)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
18
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig/BUILD
generated
vendored
18
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig/BUILD
generated
vendored
@ -16,13 +16,14 @@ go_library(
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
|
||||
"//cmd/kubeadm/app/constants:go_default_library",
|
||||
"//cmd/kubeadm/app/phases/certs/pkiutil:go_default_library",
|
||||
"//cmd/kubeadm/app/util:go_default_library",
|
||||
"//cmd/kubeadm/app/util/kubeconfig:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/clientcmd:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/clientcmd/api:go_default_library",
|
||||
"//vendor/k8s.io/client-go/util/cert:go_default_library",
|
||||
"//cmd/kubeadm/app/util/pkiutil:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/tools/clientcmd:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/tools/clientcmd/api:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/util/cert:go_default_library",
|
||||
"//vendor/github.com/pkg/errors:go_default_library",
|
||||
"//vendor/k8s.io/klog:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@ -46,12 +47,13 @@ go_test(
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
|
||||
"//cmd/kubeadm/app/constants:go_default_library",
|
||||
"//cmd/kubeadm/app/phases/certs/pkiutil:go_default_library",
|
||||
"//cmd/kubeadm/app/util:go_default_library",
|
||||
"//cmd/kubeadm/app/util/pkiutil:go_default_library",
|
||||
"//cmd/kubeadm/test:go_default_library",
|
||||
"//cmd/kubeadm/test/certs:go_default_library",
|
||||
"//cmd/kubeadm/test/kubeconfig:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/clientcmd:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/clientcmd/api:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/tools/clientcmd:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/tools/clientcmd/api:go_default_library",
|
||||
"//vendor/github.com/renstrom/dedent:go_default_library",
|
||||
],
|
||||
)
|
||||
|
6
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig/doc.go
generated
vendored
6
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig/doc.go
generated
vendored
@ -21,9 +21,9 @@ package kubeconfig
|
||||
PHASE: KUBECONFIG
|
||||
|
||||
INPUTS:
|
||||
From MasterConfiguration
|
||||
The Master API Server endpoint (AdvertiseAddress + BindPort) is required so the KubeConfig file knows where to find the master
|
||||
The KubernetesDir path is required for knowing where to put the KubeConfig files
|
||||
From InitConfiguration
|
||||
The Master API Server endpoint (AdvertiseAddress + BindPort) is required so the kubeconfig file knows where to find the master
|
||||
The KubernetesDir path is required for knowing where to put the kubeconfig files
|
||||
The PKIPath is required for knowing where all certificates should be stored
|
||||
|
||||
OUTPUTS:
|
||||
|
177
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig/kubeconfig.go
generated
vendored
177
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig/kubeconfig.go
generated
vendored
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@ -18,24 +18,23 @@ package kubeconfig
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"crypto/rsa"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||
certutil "k8s.io/client-go/util/cert"
|
||||
"k8s.io/klog"
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/pkiutil"
|
||||
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
|
||||
kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/util/pkiutil"
|
||||
)
|
||||
|
||||
// clientCertAuth struct holds info required to build a client certificate to provide authentication info in a kubeconfig object
|
||||
@ -61,8 +60,8 @@ type kubeConfigSpec struct {
|
||||
// CreateInitKubeConfigFiles will create and write to disk all kubeconfig files necessary in the kubeadm init phase
|
||||
// to establish the control plane, including also the admin kubeconfig file.
|
||||
// If kubeconfig files already exists, they are used only if evaluated equal; otherwise an error is returned.
|
||||
func CreateInitKubeConfigFiles(outDir string, cfg *kubeadmapi.MasterConfiguration) error {
|
||||
glog.V(1).Infoln("creating all kubeconfig files")
|
||||
func CreateInitKubeConfigFiles(outDir string, cfg *kubeadmapi.InitConfiguration) error {
|
||||
klog.V(1).Infoln("creating all kubeconfig files")
|
||||
return createKubeConfigFiles(
|
||||
outDir,
|
||||
cfg,
|
||||
@ -73,39 +72,32 @@ func CreateInitKubeConfigFiles(outDir string, cfg *kubeadmapi.MasterConfiguratio
|
||||
)
|
||||
}
|
||||
|
||||
// CreateAdminKubeConfigFile create a kubeconfig file for the admin to use and for kubeadm itself.
|
||||
// If the kubeconfig file already exists, it is used only if evaluated equal; otherwise an error is returned.
|
||||
func CreateAdminKubeConfigFile(outDir string, cfg *kubeadmapi.MasterConfiguration) error {
|
||||
glog.V(1).Infoln("create a kubeconfig file for the admin and for kubeadm itself")
|
||||
return createKubeConfigFiles(outDir, cfg, kubeadmconstants.AdminKubeConfigFileName)
|
||||
// CreateJoinControlPlaneKubeConfigFiles will create and write to disk the kubeconfig files required by kubeadm
|
||||
// join --control-plane workflow, plus the admin kubeconfig file used by the administrator and kubeadm itself; the
|
||||
// kubelet.conf file must not be created because it will be created and signed by the kubelet TLS bootstrap process.
|
||||
// If any kubeconfig files already exists, it used only if evaluated equal; otherwise an error is returned.
|
||||
func CreateJoinControlPlaneKubeConfigFiles(outDir string, cfg *kubeadmapi.InitConfiguration) error {
|
||||
return createKubeConfigFiles(
|
||||
outDir,
|
||||
cfg,
|
||||
kubeadmconstants.AdminKubeConfigFileName,
|
||||
kubeadmconstants.ControllerManagerKubeConfigFileName,
|
||||
kubeadmconstants.SchedulerKubeConfigFileName,
|
||||
)
|
||||
}
|
||||
|
||||
// CreateKubeletKubeConfigFile create a kubeconfig file for the Kubelet to use.
|
||||
// CreateKubeConfigFile creates a kubeconfig file.
|
||||
// If the kubeconfig file already exists, it is used only if evaluated equal; otherwise an error is returned.
|
||||
func CreateKubeletKubeConfigFile(outDir string, cfg *kubeadmapi.MasterConfiguration) error {
|
||||
glog.V(1).Infoln("creating a kubeconfig file for the Kubelet")
|
||||
return createKubeConfigFiles(outDir, cfg, kubeadmconstants.KubeletKubeConfigFileName)
|
||||
}
|
||||
|
||||
// CreateControllerManagerKubeConfigFile create a kubeconfig file for the ControllerManager to use.
|
||||
// If the kubeconfig file already exists, it is used only if evaluated equal; otherwise an error is returned.
|
||||
func CreateControllerManagerKubeConfigFile(outDir string, cfg *kubeadmapi.MasterConfiguration) error {
|
||||
glog.V(1).Infoln("creating kubeconfig file for the ControllerManager")
|
||||
return createKubeConfigFiles(outDir, cfg, kubeadmconstants.ControllerManagerKubeConfigFileName)
|
||||
}
|
||||
|
||||
// CreateSchedulerKubeConfigFile create a create a kubeconfig file for the Scheduler to use.
|
||||
// If the kubeconfig file already exists, it is used only if evaluated equal; otherwise an error is returned.
|
||||
func CreateSchedulerKubeConfigFile(outDir string, cfg *kubeadmapi.MasterConfiguration) error {
|
||||
glog.V(1).Infoln("creating kubeconfig file for Scheduler")
|
||||
return createKubeConfigFiles(outDir, cfg, kubeadmconstants.SchedulerKubeConfigFileName)
|
||||
func CreateKubeConfigFile(kubeConfigFileName string, outDir string, cfg *kubeadmapi.InitConfiguration) error {
|
||||
klog.V(1).Infof("creating kubeconfig file for %s", kubeConfigFileName)
|
||||
return createKubeConfigFiles(outDir, cfg, kubeConfigFileName)
|
||||
}
|
||||
|
||||
// createKubeConfigFiles creates all the requested kubeconfig files.
|
||||
// If kubeconfig files already exists, they are used only if evaluated equal; otherwise an error is returned.
|
||||
func createKubeConfigFiles(outDir string, cfg *kubeadmapi.MasterConfiguration, kubeConfigFileNames ...string) error {
|
||||
func createKubeConfigFiles(outDir string, cfg *kubeadmapi.InitConfiguration, kubeConfigFileNames ...string) error {
|
||||
|
||||
// gets the KubeConfigSpecs, actualized for the current MasterConfiguration
|
||||
// gets the KubeConfigSpecs, actualized for the current InitConfiguration
|
||||
specs, err := getKubeConfigSpecs(cfg)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -115,7 +107,7 @@ func createKubeConfigFiles(outDir string, cfg *kubeadmapi.MasterConfiguration, k
|
||||
// retrives the KubeConfigSpec for given kubeConfigFileName
|
||||
spec, exists := specs[kubeConfigFileName]
|
||||
if !exists {
|
||||
return fmt.Errorf("couldn't retrive KubeConfigSpec for %s", kubeConfigFileName)
|
||||
return errors.Errorf("couldn't retrive KubeConfigSpec for %s", kubeConfigFileName)
|
||||
}
|
||||
|
||||
// builds the KubeConfig object
|
||||
@ -124,7 +116,7 @@ func createKubeConfigFiles(outDir string, cfg *kubeadmapi.MasterConfiguration, k
|
||||
return err
|
||||
}
|
||||
|
||||
// writes the KubeConfig to disk if it not exists
|
||||
// writes the kubeconfig to disk if it not exists
|
||||
if err = createKubeConfigFileIfNotExists(outDir, kubeConfigFileName, config); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -133,16 +125,16 @@ func createKubeConfigFiles(outDir string, cfg *kubeadmapi.MasterConfiguration, k
|
||||
return nil
|
||||
}
|
||||
|
||||
// getKubeConfigSpecs returns all KubeConfigSpecs actualized to the context of the current MasterConfiguration
|
||||
// getKubeConfigSpecs returns all KubeConfigSpecs actualized to the context of the current InitConfiguration
|
||||
// NB. this methods holds the information about how kubeadm creates kubeconfig files.
|
||||
func getKubeConfigSpecs(cfg *kubeadmapi.MasterConfiguration) (map[string]*kubeConfigSpec, error) {
|
||||
func getKubeConfigSpecs(cfg *kubeadmapi.InitConfiguration) (map[string]*kubeConfigSpec, error) {
|
||||
|
||||
caCert, caKey, err := pkiutil.TryLoadCertAndKeyFromDisk(cfg.CertificatesDir, kubeadmconstants.CACertAndKeyBaseName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't create a kubeconfig; the CA files couldn't be loaded: %v", err)
|
||||
return nil, errors.Wrap(err, "couldn't create a kubeconfig; the CA files couldn't be loaded")
|
||||
}
|
||||
|
||||
masterEndpoint, err := kubeadmutil.GetMasterEndpoint(&cfg.API)
|
||||
masterEndpoint, err := kubeadmutil.GetMasterEndpoint(cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -160,7 +152,7 @@ func getKubeConfigSpecs(cfg *kubeadmapi.MasterConfiguration) (map[string]*kubeCo
|
||||
kubeadmconstants.KubeletKubeConfigFileName: {
|
||||
CACert: caCert,
|
||||
APIServer: masterEndpoint,
|
||||
ClientName: fmt.Sprintf("system:node:%s", cfg.NodeRegistration.Name),
|
||||
ClientName: fmt.Sprintf("%s%s", kubeadmconstants.NodesUserPrefix, cfg.NodeRegistration.Name),
|
||||
ClientCertAuth: &clientCertAuth{
|
||||
CAKey: caKey,
|
||||
Organizations: []string{kubeadmconstants.NodesGroup},
|
||||
@ -208,9 +200,9 @@ func buildKubeConfigFromSpec(spec *kubeConfigSpec, clustername string) (*clientc
|
||||
Organization: spec.ClientCertAuth.Organizations,
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
}
|
||||
clientCert, clientKey, err := pkiutil.NewCertAndKey(spec.CACert, spec.ClientCertAuth.CAKey, clientCertConfig)
|
||||
clientCert, clientKey, err := pkiutil.NewCertAndKey(spec.CACert, spec.ClientCertAuth.CAKey, &clientCertConfig)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failure while creating %s client certificate: %v", spec.ClientName, err)
|
||||
return nil, errors.Wrapf(err, "failure while creating %s client certificate", spec.ClientName)
|
||||
}
|
||||
|
||||
// create a kubeconfig with the client certs
|
||||
@ -224,28 +216,18 @@ func buildKubeConfigFromSpec(spec *kubeConfigSpec, clustername string) (*clientc
|
||||
), nil
|
||||
}
|
||||
|
||||
// createKubeConfigFileIfNotExists saves the KubeConfig object into a file if there isn't any file at the given path.
|
||||
// If there already is a KubeConfig file at the given path; kubeadm tries to load it and check if the values in the
|
||||
// existing and the expected config equals. If they do; kubeadm will just skip writing the file as it's up-to-date,
|
||||
// but if a file exists but has old content or isn't a kubeconfig file, this function returns an error.
|
||||
func createKubeConfigFileIfNotExists(outDir, filename string, config *clientcmdapi.Config) error {
|
||||
// validateKubeConfig check if the kubeconfig file exist and has the expected CA and server URL
|
||||
func validateKubeConfig(outDir, filename string, config *clientcmdapi.Config) error {
|
||||
kubeConfigFilePath := filepath.Join(outDir, filename)
|
||||
|
||||
// Check if the file exist, and if it doesn't, just write it to disk
|
||||
if _, err := os.Stat(kubeConfigFilePath); os.IsNotExist(err) {
|
||||
err = kubeconfigutil.WriteToDisk(kubeConfigFilePath, config)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to save kubeconfig file %s on disk: %v", kubeConfigFilePath, err)
|
||||
}
|
||||
|
||||
fmt.Printf("[kubeconfig] Wrote KubeConfig file to disk: %q\n", kubeConfigFilePath)
|
||||
return nil
|
||||
if _, err := os.Stat(kubeConfigFilePath); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// The kubeconfig already exists, let's check if it has got the same CA and server URL
|
||||
currentConfig, err := clientcmd.LoadFromFile(kubeConfigFilePath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load kubeconfig file %s that already exists on disk: %v", kubeConfigFilePath, err)
|
||||
return errors.Wrapf(err, "failed to load kubeconfig file %s that already exists on disk", kubeConfigFilePath)
|
||||
}
|
||||
|
||||
expectedCtx := config.CurrentContext
|
||||
@ -255,31 +237,54 @@ func createKubeConfigFileIfNotExists(outDir, filename string, config *clientcmda
|
||||
|
||||
// If the current CA cert on disk doesn't match the expected CA cert, error out because we have a file, but it's stale
|
||||
if !bytes.Equal(currentConfig.Clusters[currentCluster].CertificateAuthorityData, config.Clusters[expectedCluster].CertificateAuthorityData) {
|
||||
return fmt.Errorf("a kubeconfig file %q exists already but has got the wrong CA cert", kubeConfigFilePath)
|
||||
return errors.Errorf("a kubeconfig file %q exists already but has got the wrong CA cert", kubeConfigFilePath)
|
||||
}
|
||||
// If the current API Server location on disk doesn't match the expected API server, error out because we have a file, but it's stale
|
||||
if currentConfig.Clusters[currentCluster].Server != config.Clusters[expectedCluster].Server {
|
||||
return fmt.Errorf("a kubeconfig file %q exists already but has got the wrong API Server URL", kubeConfigFilePath)
|
||||
return errors.Errorf("a kubeconfig file %q exists already but has got the wrong API Server URL", kubeConfigFilePath)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// createKubeConfigFileIfNotExists saves the KubeConfig object into a file if there isn't any file at the given path.
|
||||
// If there already is a kubeconfig file at the given path; kubeadm tries to load it and check if the values in the
|
||||
// existing and the expected config equals. If they do; kubeadm will just skip writing the file as it's up-to-date,
|
||||
// but if a file exists but has old content or isn't a kubeconfig file, this function returns an error.
|
||||
func createKubeConfigFileIfNotExists(outDir, filename string, config *clientcmdapi.Config) error {
|
||||
kubeConfigFilePath := filepath.Join(outDir, filename)
|
||||
|
||||
err := validateKubeConfig(outDir, filename, config)
|
||||
if err != nil {
|
||||
// Check if the file exist, and if it doesn't, just write it to disk
|
||||
if !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("[kubeconfig] Writing %q kubeconfig file\n", filename)
|
||||
err = kubeconfigutil.WriteToDisk(kubeConfigFilePath, config)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to save kubeconfig file %q on disk", kubeConfigFilePath)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
// kubeadm doesn't validate the existing kubeconfig file more than this (kubeadm trusts the client certs to be valid)
|
||||
// Basically, if we find a kubeconfig file with the same path; the same CA cert and the same server URL;
|
||||
// kubeadm thinks those files are equal and doesn't bother writing a new file
|
||||
fmt.Printf("[kubeconfig] Using existing up-to-date KubeConfig file: %q\n", kubeConfigFilePath)
|
||||
fmt.Printf("[kubeconfig] Using existing up-to-date kubeconfig file: %q\n", kubeConfigFilePath)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// WriteKubeConfigWithClientCert writes a kubeconfig file - with a client certificate as authentication info - to the given writer.
|
||||
func WriteKubeConfigWithClientCert(out io.Writer, cfg *kubeadmapi.MasterConfiguration, clientName string, organizations []string) error {
|
||||
func WriteKubeConfigWithClientCert(out io.Writer, cfg *kubeadmapi.InitConfiguration, clientName string, organizations []string) error {
|
||||
|
||||
// creates the KubeConfigSpecs, actualized for the current MasterConfiguration
|
||||
// creates the KubeConfigSpecs, actualized for the current InitConfiguration
|
||||
caCert, caKey, err := pkiutil.TryLoadCertAndKeyFromDisk(cfg.CertificatesDir, kubeadmconstants.CACertAndKeyBaseName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("couldn't create a kubeconfig; the CA files couldn't be loaded: %v", err)
|
||||
return errors.Wrap(err, "couldn't create a kubeconfig; the CA files couldn't be loaded")
|
||||
}
|
||||
|
||||
masterEndpoint, err := kubeadmutil.GetMasterEndpoint(&cfg.API)
|
||||
masterEndpoint, err := kubeadmutil.GetMasterEndpoint(cfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -298,15 +303,15 @@ func WriteKubeConfigWithClientCert(out io.Writer, cfg *kubeadmapi.MasterConfigur
|
||||
}
|
||||
|
||||
// WriteKubeConfigWithToken writes a kubeconfig file - with a token as client authentication info - to the given writer.
|
||||
func WriteKubeConfigWithToken(out io.Writer, cfg *kubeadmapi.MasterConfiguration, clientName, token string) error {
|
||||
func WriteKubeConfigWithToken(out io.Writer, cfg *kubeadmapi.InitConfiguration, clientName, token string) error {
|
||||
|
||||
// creates the KubeConfigSpecs, actualized for the current MasterConfiguration
|
||||
// creates the KubeConfigSpecs, actualized for the current InitConfiguration
|
||||
caCert, _, err := pkiutil.TryLoadCertAndKeyFromDisk(cfg.CertificatesDir, kubeadmconstants.CACertAndKeyBaseName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("couldn't create a kubeconfig; the CA files couldn't be loaded: %v", err)
|
||||
return errors.Wrap(err, "couldn't create a kubeconfig; the CA files couldn't be loaded")
|
||||
}
|
||||
|
||||
masterEndpoint, err := kubeadmutil.GetMasterEndpoint(&cfg.API)
|
||||
masterEndpoint, err := kubeadmutil.GetMasterEndpoint(cfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -332,12 +337,44 @@ func writeKubeConfigFromSpec(out io.Writer, spec *kubeConfigSpec, clustername st
|
||||
return err
|
||||
}
|
||||
|
||||
// writes the KubeConfig to disk if it not exists
|
||||
// writes the kubeconfig to disk if it not exists
|
||||
configBytes, err := clientcmd.Write(*config)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failure while serializing admin kubeconfig: %v", err)
|
||||
return errors.Wrap(err, "failure while serializing admin kubeconfig")
|
||||
}
|
||||
|
||||
fmt.Fprintln(out, string(configBytes))
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateKubeconfigsForExternalCA check if the kubeconfig file exist and has the expected CA and server URL using kubeadmapi.InitConfiguration.
|
||||
func ValidateKubeconfigsForExternalCA(outDir string, cfg *kubeadmapi.InitConfiguration) error {
|
||||
kubeConfigFileNames := []string{
|
||||
kubeadmconstants.AdminKubeConfigFileName,
|
||||
kubeadmconstants.KubeletKubeConfigFileName,
|
||||
kubeadmconstants.ControllerManagerKubeConfigFileName,
|
||||
kubeadmconstants.SchedulerKubeConfigFileName,
|
||||
}
|
||||
|
||||
specs, err := getKubeConfigSpecs(cfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, kubeConfigFileName := range kubeConfigFileNames {
|
||||
spec, exists := specs[kubeConfigFileName]
|
||||
if !exists {
|
||||
return errors.Errorf("couldn't retrive KubeConfigSpec for %s", kubeConfigFileName)
|
||||
}
|
||||
|
||||
kubeconfig, err := buildKubeConfigFromSpec(spec, cfg.ClusterName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = validateKubeConfig(outDir, kubeConfigFileName, kubeconfig); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
254
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig/kubeconfig_test.go
generated
vendored
254
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig/kubeconfig_test.go
generated
vendored
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@ -23,18 +23,18 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
"github.com/renstrom/dedent"
|
||||
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||
|
||||
pkiutil "k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/pkiutil"
|
||||
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
|
||||
pkiutil "k8s.io/kubernetes/cmd/kubeadm/app/util/pkiutil"
|
||||
testutil "k8s.io/kubernetes/cmd/kubeadm/test"
|
||||
certstestutil "k8s.io/kubernetes/cmd/kubeadm/test/certs"
|
||||
kubeconfigtestutil "k8s.io/kubernetes/cmd/kubeadm/test/kubeconfig"
|
||||
@ -46,8 +46,10 @@ func TestGetKubeConfigSpecsFailsIfCADoesntExists(t *testing.T) {
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
// Creates a Master Configuration pointing to the pkidir folder
|
||||
cfg := &kubeadmapi.MasterConfiguration{
|
||||
CertificatesDir: tmpdir,
|
||||
cfg := &kubeadmapi.InitConfiguration{
|
||||
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
|
||||
CertificatesDir: tmpdir,
|
||||
},
|
||||
}
|
||||
|
||||
// Executes getKubeConfigSpecs
|
||||
@ -65,30 +67,44 @@ func TestGetKubeConfigSpecs(t *testing.T) {
|
||||
pkidir := testutil.SetupPkiDirWithCertificateAuthorithy(t, tmpdir)
|
||||
|
||||
// Creates Master Configurations pointing to the pkidir folder
|
||||
cfgs := []*kubeadmapi.MasterConfiguration{
|
||||
cfgs := []*kubeadmapi.InitConfiguration{
|
||||
{
|
||||
API: kubeadmapi.API{AdvertiseAddress: "1.2.3.4", BindPort: 1234},
|
||||
CertificatesDir: pkidir,
|
||||
LocalAPIEndpoint: kubeadmapi.APIEndpoint{AdvertiseAddress: "1.2.3.4", BindPort: 1234},
|
||||
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
|
||||
CertificatesDir: pkidir,
|
||||
},
|
||||
NodeRegistration: kubeadmapi.NodeRegistrationOptions{Name: "valid-node-name"},
|
||||
},
|
||||
{
|
||||
API: kubeadmapi.API{AdvertiseAddress: "1.2.3.4", ControlPlaneEndpoint: "api.k8s.io", BindPort: 1234},
|
||||
CertificatesDir: pkidir,
|
||||
LocalAPIEndpoint: kubeadmapi.APIEndpoint{AdvertiseAddress: "1.2.3.4", BindPort: 1234},
|
||||
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
|
||||
ControlPlaneEndpoint: "api.k8s.io",
|
||||
CertificatesDir: pkidir,
|
||||
},
|
||||
NodeRegistration: kubeadmapi.NodeRegistrationOptions{Name: "valid-node-name"},
|
||||
},
|
||||
{
|
||||
API: kubeadmapi.API{AdvertiseAddress: "1.2.3.4", ControlPlaneEndpoint: "api.k8s.io:4321", BindPort: 1234},
|
||||
CertificatesDir: pkidir,
|
||||
LocalAPIEndpoint: kubeadmapi.APIEndpoint{AdvertiseAddress: "1.2.3.4", BindPort: 1234},
|
||||
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
|
||||
ControlPlaneEndpoint: "api.k8s.io:4321",
|
||||
CertificatesDir: pkidir,
|
||||
},
|
||||
NodeRegistration: kubeadmapi.NodeRegistrationOptions{Name: "valid-node-name"},
|
||||
},
|
||||
{
|
||||
API: kubeadmapi.API{AdvertiseAddress: "1.2.3.4", ControlPlaneEndpoint: "api.k8s.io", BindPort: 1234},
|
||||
CertificatesDir: pkidir,
|
||||
LocalAPIEndpoint: kubeadmapi.APIEndpoint{AdvertiseAddress: "1.2.3.4", BindPort: 1234},
|
||||
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
|
||||
ControlPlaneEndpoint: "api.k8s.io",
|
||||
CertificatesDir: pkidir,
|
||||
},
|
||||
NodeRegistration: kubeadmapi.NodeRegistrationOptions{Name: "valid-node-name"},
|
||||
},
|
||||
{
|
||||
API: kubeadmapi.API{AdvertiseAddress: "1.2.3.4", ControlPlaneEndpoint: "api.k8s.io:4321", BindPort: 1234},
|
||||
CertificatesDir: pkidir,
|
||||
LocalAPIEndpoint: kubeadmapi.APIEndpoint{AdvertiseAddress: "1.2.3.4", BindPort: 1234},
|
||||
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
|
||||
ControlPlaneEndpoint: "api.k8s.io:4321",
|
||||
CertificatesDir: pkidir,
|
||||
},
|
||||
NodeRegistration: kubeadmapi.NodeRegistrationOptions{Name: "valid-node-name"},
|
||||
},
|
||||
}
|
||||
@ -106,7 +122,7 @@ func TestGetKubeConfigSpecs(t *testing.T) {
|
||||
},
|
||||
{
|
||||
kubeConfigFile: kubeadmconstants.KubeletKubeConfigFileName,
|
||||
clientName: fmt.Sprintf("system:node:%s", cfg.NodeRegistration.Name),
|
||||
clientName: fmt.Sprintf("%s%s", kubeadmconstants.NodesUserPrefix, cfg.NodeRegistration.Name),
|
||||
organizations: []string{kubeadmconstants.NodesGroup},
|
||||
},
|
||||
{
|
||||
@ -145,8 +161,8 @@ func TestGetKubeConfigSpecs(t *testing.T) {
|
||||
t.Errorf("getKubeConfigSpecs for %s Organizations is %v, expected %v", assertion.kubeConfigFile, spec.ClientCertAuth.Organizations, assertion.organizations)
|
||||
}
|
||||
|
||||
// Asserts MasterConfiguration values injected into spec
|
||||
masterEndpoint, err := kubeadmutil.GetMasterEndpoint(&cfg.API)
|
||||
// Asserts InitConfiguration values injected into spec
|
||||
masterEndpoint, err := kubeadmutil.GetMasterEndpoint(cfg)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@ -236,7 +252,7 @@ func TestCreateKubeConfigFileIfNotExists(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// Writes the KubeConfig file to disk
|
||||
// Writes the kubeconfig file to disk
|
||||
err := createKubeConfigFileIfNotExists(tmpdir, "test.conf", test.kubeConfig)
|
||||
if test.expectedError && err == nil {
|
||||
t.Errorf("createKubeConfigFileIfNotExists didn't failed when expected to fail")
|
||||
@ -252,12 +268,12 @@ func TestCreateKubeConfigFileIfNotExists(t *testing.T) {
|
||||
|
||||
func TestCreateKubeconfigFilesAndWrappers(t *testing.T) {
|
||||
var tests = []struct {
|
||||
createKubeConfigFunction func(outDir string, cfg *kubeadmapi.MasterConfiguration) error
|
||||
createKubeConfigFunction func(outDir string, cfg *kubeadmapi.InitConfiguration) error
|
||||
expectedFiles []string
|
||||
expectedError bool
|
||||
}{
|
||||
{ // Test createKubeConfigFiles fails for unknown kubeconfig is requested
|
||||
createKubeConfigFunction: func(outDir string, cfg *kubeadmapi.MasterConfiguration) error {
|
||||
createKubeConfigFunction: func(outDir string, cfg *kubeadmapi.InitConfiguration) error {
|
||||
return createKubeConfigFiles(outDir, cfg, "unknown.conf")
|
||||
},
|
||||
expectedError: true,
|
||||
@ -271,21 +287,13 @@ func TestCreateKubeconfigFilesAndWrappers(t *testing.T) {
|
||||
kubeadmconstants.SchedulerKubeConfigFileName,
|
||||
},
|
||||
},
|
||||
{ // Test CreateAdminKubeConfigFile (wrapper to createKubeConfigFile)
|
||||
createKubeConfigFunction: CreateAdminKubeConfigFile,
|
||||
expectedFiles: []string{kubeadmconstants.AdminKubeConfigFileName},
|
||||
},
|
||||
{ // Test CreateKubeletKubeConfigFile (wrapper to createKubeConfigFile)
|
||||
createKubeConfigFunction: CreateKubeletKubeConfigFile,
|
||||
expectedFiles: []string{kubeadmconstants.KubeletKubeConfigFileName},
|
||||
},
|
||||
{ // Test CreateControllerManagerKubeConfigFile (wrapper to createKubeConfigFile)
|
||||
createKubeConfigFunction: CreateControllerManagerKubeConfigFile,
|
||||
expectedFiles: []string{kubeadmconstants.ControllerManagerKubeConfigFileName},
|
||||
},
|
||||
{ // Test createKubeConfigFile (wrapper to createKubeConfigFile)
|
||||
createKubeConfigFunction: CreateSchedulerKubeConfigFile,
|
||||
expectedFiles: []string{kubeadmconstants.SchedulerKubeConfigFileName},
|
||||
{ // Test CreateJoinControlPlaneKubeConfigFiles (wrapper to createKubeConfigFile)
|
||||
createKubeConfigFunction: CreateJoinControlPlaneKubeConfigFiles,
|
||||
expectedFiles: []string{
|
||||
kubeadmconstants.AdminKubeConfigFileName,
|
||||
kubeadmconstants.ControllerManagerKubeConfigFileName,
|
||||
kubeadmconstants.SchedulerKubeConfigFileName,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@ -298,9 +306,11 @@ func TestCreateKubeconfigFilesAndWrappers(t *testing.T) {
|
||||
pkidir := testutil.SetupPkiDirWithCertificateAuthorithy(t, tmpdir)
|
||||
|
||||
// Creates a Master Configuration pointing to the pkidir folder
|
||||
cfg := &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadmapi.API{AdvertiseAddress: "1.2.3.4", BindPort: 1234},
|
||||
CertificatesDir: pkidir,
|
||||
cfg := &kubeadmapi.InitConfiguration{
|
||||
LocalAPIEndpoint: kubeadmapi.APIEndpoint{AdvertiseAddress: "1.2.3.4", BindPort: 1234},
|
||||
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
|
||||
CertificatesDir: pkidir,
|
||||
},
|
||||
}
|
||||
|
||||
// Execs the createKubeConfigFunction
|
||||
@ -326,8 +336,10 @@ func TestWriteKubeConfigFailsIfCADoesntExists(t *testing.T) {
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
// Creates a Master Configuration pointing to the tmpdir folder
|
||||
cfg := &kubeadmapi.MasterConfiguration{
|
||||
CertificatesDir: tmpdir,
|
||||
cfg := &kubeadmapi.InitConfiguration{
|
||||
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
|
||||
CertificatesDir: tmpdir,
|
||||
},
|
||||
}
|
||||
|
||||
var tests = []struct {
|
||||
@ -371,9 +383,11 @@ func TestWriteKubeConfig(t *testing.T) {
|
||||
}
|
||||
|
||||
// Creates a Master Configuration pointing to the pkidir folder
|
||||
cfg := &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadmapi.API{AdvertiseAddress: "1.2.3.4", BindPort: 1234},
|
||||
CertificatesDir: pkidir,
|
||||
cfg := &kubeadmapi.InitConfiguration{
|
||||
LocalAPIEndpoint: kubeadmapi.APIEndpoint{AdvertiseAddress: "1.2.3.4", BindPort: 1234},
|
||||
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
|
||||
CertificatesDir: pkidir,
|
||||
},
|
||||
}
|
||||
|
||||
var tests = []struct {
|
||||
@ -426,6 +440,150 @@ func TestWriteKubeConfig(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateKubeConfig(t *testing.T) {
|
||||
caCert, caKey := certstestutil.SetupCertificateAuthorithy(t)
|
||||
anotherCaCert, anotherCaKey := certstestutil.SetupCertificateAuthorithy(t)
|
||||
|
||||
config := setupdKubeConfigWithClientAuth(t, caCert, caKey, "https://1.2.3.4:1234", "test-cluster", "myOrg1")
|
||||
configWithAnotherClusterCa := setupdKubeConfigWithClientAuth(t, anotherCaCert, anotherCaKey, "https://1.2.3.4:1234", "test-cluster", "myOrg1")
|
||||
configWithAnotherServerURL := setupdKubeConfigWithClientAuth(t, caCert, caKey, "https://4.3.2.1:4321", "test-cluster", "myOrg1")
|
||||
|
||||
tests := map[string]struct {
|
||||
existingKubeConfig *clientcmdapi.Config
|
||||
kubeConfig *clientcmdapi.Config
|
||||
expectedError bool
|
||||
}{
|
||||
"kubeconfig don't exist": {
|
||||
kubeConfig: config,
|
||||
expectedError: true,
|
||||
},
|
||||
"kubeconfig exist and has invalid ca": {
|
||||
existingKubeConfig: configWithAnotherClusterCa,
|
||||
kubeConfig: config,
|
||||
expectedError: true,
|
||||
},
|
||||
"kubeconfig exist and has invalid server url": {
|
||||
existingKubeConfig: configWithAnotherServerURL,
|
||||
kubeConfig: config,
|
||||
expectedError: true,
|
||||
},
|
||||
"kubeconfig exist and is valid": {
|
||||
existingKubeConfig: config,
|
||||
kubeConfig: config,
|
||||
expectedError: false,
|
||||
},
|
||||
}
|
||||
|
||||
for name, test := range tests {
|
||||
tmpdir := testutil.SetupTempDir(t)
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
if test.existingKubeConfig != nil {
|
||||
if err := createKubeConfigFileIfNotExists(tmpdir, "test.conf", test.existingKubeConfig); err != nil {
|
||||
t.Errorf("createKubeConfigFileIfNotExists failed")
|
||||
}
|
||||
}
|
||||
|
||||
err := validateKubeConfig(tmpdir, "test.conf", test.kubeConfig)
|
||||
if (err != nil) != test.expectedError {
|
||||
t.Fatalf(dedent.Dedent(
|
||||
"validateKubeConfig failed\n%s\nexpected error: %t\n\tgot: %t\nerror: %v"),
|
||||
name,
|
||||
test.expectedError,
|
||||
(err != nil),
|
||||
err,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateKubeconfigsForExternalCA(t *testing.T) {
|
||||
tmpDir := testutil.SetupTempDir(t)
|
||||
defer os.RemoveAll(tmpDir)
|
||||
pkiDir := filepath.Join(tmpDir, "pki")
|
||||
|
||||
initConfig := &kubeadmapi.InitConfiguration{
|
||||
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
|
||||
CertificatesDir: pkiDir,
|
||||
},
|
||||
LocalAPIEndpoint: kubeadmapi.APIEndpoint{
|
||||
BindPort: 1234,
|
||||
AdvertiseAddress: "1.2.3.4",
|
||||
},
|
||||
}
|
||||
|
||||
caCert, caKey := certstestutil.SetupCertificateAuthorithy(t)
|
||||
anotherCaCert, anotherCaKey := certstestutil.SetupCertificateAuthorithy(t)
|
||||
if err := pkiutil.WriteCertAndKey(pkiDir, kubeadmconstants.CACertAndKeyBaseName, caCert, caKey); err != nil {
|
||||
t.Fatalf("failure while saving CA certificate and key: %v", err)
|
||||
}
|
||||
|
||||
config := setupdKubeConfigWithClientAuth(t, caCert, caKey, "https://1.2.3.4:1234", "test-cluster", "myOrg1")
|
||||
configWithAnotherClusterCa := setupdKubeConfigWithClientAuth(t, anotherCaCert, anotherCaKey, "https://1.2.3.4:1234", "test-cluster", "myOrg1")
|
||||
configWithAnotherServerURL := setupdKubeConfigWithClientAuth(t, caCert, caKey, "https://4.3.2.1:4321", "test-cluster", "myOrg1")
|
||||
|
||||
tests := map[string]struct {
|
||||
filesToWrite map[string]*clientcmdapi.Config
|
||||
initConfig *kubeadmapi.InitConfiguration
|
||||
expectedError bool
|
||||
}{
|
||||
"files don't exist": {
|
||||
initConfig: initConfig,
|
||||
expectedError: true,
|
||||
},
|
||||
"some files don't exist": {
|
||||
filesToWrite: map[string]*clientcmdapi.Config{
|
||||
kubeadmconstants.AdminKubeConfigFileName: config,
|
||||
kubeadmconstants.KubeletKubeConfigFileName: config,
|
||||
},
|
||||
initConfig: initConfig,
|
||||
expectedError: true,
|
||||
},
|
||||
"some files are invalid": {
|
||||
filesToWrite: map[string]*clientcmdapi.Config{
|
||||
kubeadmconstants.AdminKubeConfigFileName: config,
|
||||
kubeadmconstants.KubeletKubeConfigFileName: config,
|
||||
kubeadmconstants.ControllerManagerKubeConfigFileName: configWithAnotherClusterCa,
|
||||
kubeadmconstants.SchedulerKubeConfigFileName: configWithAnotherServerURL,
|
||||
},
|
||||
initConfig: initConfig,
|
||||
expectedError: true,
|
||||
},
|
||||
"all files are valid": {
|
||||
filesToWrite: map[string]*clientcmdapi.Config{
|
||||
kubeadmconstants.AdminKubeConfigFileName: config,
|
||||
kubeadmconstants.KubeletKubeConfigFileName: config,
|
||||
kubeadmconstants.ControllerManagerKubeConfigFileName: config,
|
||||
kubeadmconstants.SchedulerKubeConfigFileName: config,
|
||||
},
|
||||
initConfig: initConfig,
|
||||
expectedError: false,
|
||||
},
|
||||
}
|
||||
|
||||
for name, test := range tests {
|
||||
tmpdir := testutil.SetupTempDir(t)
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
for name, config := range test.filesToWrite {
|
||||
if err := createKubeConfigFileIfNotExists(tmpdir, name, config); err != nil {
|
||||
t.Errorf("createKubeConfigFileIfNotExists failed")
|
||||
}
|
||||
}
|
||||
|
||||
err := ValidateKubeconfigsForExternalCA(tmpdir, test.initConfig)
|
||||
if (err != nil) != test.expectedError {
|
||||
t.Fatalf(dedent.Dedent(
|
||||
"ValidateKubeconfigsForExternalCA failed\n%s\nexpected error: %t\n\tgot: %t\nerror: %v"),
|
||||
name,
|
||||
test.expectedError,
|
||||
(err != nil),
|
||||
err,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// setupdKubeConfigWithClientAuth is a test utility function that wraps buildKubeConfigFromSpec for building a KubeConfig object With ClientAuth
|
||||
func setupdKubeConfigWithClientAuth(t *testing.T, caCert *x509.Certificate, caKey *rsa.PrivateKey, APIServer, clientName, clustername string, organizations ...string) *clientcmdapi.Config {
|
||||
spec := &kubeConfigSpec{
|
||||
|
40
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/kubelet/BUILD
generated
vendored
40
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/kubelet/BUILD
generated
vendored
@ -6,29 +6,31 @@ go_library(
|
||||
"config.go",
|
||||
"dynamic.go",
|
||||
"flags.go",
|
||||
"kubelet.go",
|
||||
],
|
||||
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/phases/kubelet",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
|
||||
"//cmd/kubeadm/app/apis/kubeadm/v1alpha2:go_default_library",
|
||||
"//cmd/kubeadm/app/apis/kubeadm/v1beta1:go_default_library",
|
||||
"//cmd/kubeadm/app/componentconfigs:go_default_library",
|
||||
"//cmd/kubeadm/app/constants:go_default_library",
|
||||
"//cmd/kubeadm/app/features:go_default_library",
|
||||
"//cmd/kubeadm/app/images:go_default_library",
|
||||
"//cmd/kubeadm/app/util:go_default_library",
|
||||
"//cmd/kubeadm/app/util/apiclient:go_default_library",
|
||||
"//pkg/apis/rbac/v1:go_default_library",
|
||||
"//pkg/kubelet/apis/kubeletconfig/scheme:go_default_library",
|
||||
"//pkg/kubelet/apis/kubeletconfig/v1beta1:go_default_library",
|
||||
"//pkg/kubelet/apis/config:go_default_library",
|
||||
"//pkg/util/initsystem:go_default_library",
|
||||
"//pkg/util/node:go_default_library",
|
||||
"//pkg/util/procfs:go_default_library",
|
||||
"//pkg/util/version:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/api/rbac/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||
"//staging/src/k8s.io/api/rbac/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/version:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//vendor/github.com/pkg/errors:go_default_library",
|
||||
"//vendor/k8s.io/klog:go_default_library",
|
||||
"//vendor/k8s.io/utils/exec:go_default_library",
|
||||
],
|
||||
)
|
||||
@ -44,13 +46,13 @@ go_test(
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
|
||||
"//pkg/kubelet/apis:go_default_library",
|
||||
"//pkg/kubelet/apis/kubeletconfig/v1beta1:go_default_library",
|
||||
"//pkg/util/version:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes/fake:go_default_library",
|
||||
"//vendor/k8s.io/client-go/testing:go_default_library",
|
||||
"//pkg/kubelet/apis/config: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/runtime:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/version:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/testing:go_default_library",
|
||||
"//vendor/k8s.io/utils/exec:go_default_library",
|
||||
],
|
||||
)
|
||||
|
44
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/kubelet/config.go
generated
vendored
44
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/kubelet/config.go
generated
vendored
@ -22,24 +22,24 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"k8s.io/api/core/v1"
|
||||
rbac "k8s.io/api/rbac/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/version"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/componentconfigs"
|
||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
|
||||
rbachelper "k8s.io/kubernetes/pkg/apis/rbac/v1"
|
||||
kubeletconfigscheme "k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/scheme"
|
||||
kubeletconfigv1beta1 "k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/v1beta1"
|
||||
"k8s.io/kubernetes/pkg/util/version"
|
||||
kubeletconfig "k8s.io/kubernetes/pkg/kubelet/apis/config"
|
||||
)
|
||||
|
||||
// WriteConfigToDisk writes the kubelet config object down to a file
|
||||
// Used at "kubeadm init" and "kubeadm upgrade" time
|
||||
func WriteConfigToDisk(kubeletConfig *kubeletconfigv1beta1.KubeletConfiguration, kubeletDir string) error {
|
||||
func WriteConfigToDisk(kubeletConfig *kubeletconfig.KubeletConfiguration, kubeletDir string) error {
|
||||
|
||||
kubeletBytes, err := getConfigBytes(kubeletConfig)
|
||||
if err != nil {
|
||||
@ -50,17 +50,17 @@ func WriteConfigToDisk(kubeletConfig *kubeletconfigv1beta1.KubeletConfiguration,
|
||||
|
||||
// CreateConfigMap creates a ConfigMap with the generic kubelet configuration.
|
||||
// Used at "kubeadm init" and "kubeadm upgrade" time
|
||||
func CreateConfigMap(cfg *kubeadmapi.MasterConfiguration, client clientset.Interface) error {
|
||||
func CreateConfigMap(cfg *kubeadmapi.InitConfiguration, client clientset.Interface) error {
|
||||
|
||||
k8sVersion, err := version.ParseSemantic(cfg.KubernetesVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
configMapName := configMapName(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)
|
||||
|
||||
kubeletBytes, err := getConfigBytes(cfg.KubeletConfiguration.BaseConfig)
|
||||
kubeletBytes, err := getConfigBytes(cfg.ComponentConfigs.Kubelet)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -78,7 +78,7 @@ func CreateConfigMap(cfg *kubeadmapi.MasterConfiguration, client clientset.Inter
|
||||
}
|
||||
|
||||
if err := createConfigMapRBACRules(client, k8sVersion); err != nil {
|
||||
return fmt.Errorf("error creating kubelet configuration configmap RBAC rules: %v", err)
|
||||
return errors.Wrap(err, "error creating kubelet configuration configmap RBAC rules")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -91,7 +91,7 @@ func createConfigMapRBACRules(client clientset.Interface, k8sVersion *version.Ve
|
||||
Namespace: metav1.NamespaceSystem,
|
||||
},
|
||||
Rules: []rbac.PolicyRule{
|
||||
rbachelper.NewRule("get").Groups("").Resources("configmaps").Names(configMapName(k8sVersion)).RuleOrDie(),
|
||||
rbachelper.NewRule("get").Groups("").Resources("configmaps").Names(kubeadmconstants.GetKubeletConfigMapName(k8sVersion)).RuleOrDie(),
|
||||
},
|
||||
}); err != nil {
|
||||
return err
|
||||
@ -125,7 +125,7 @@ func createConfigMapRBACRules(client clientset.Interface, k8sVersion *version.Ve
|
||||
func DownloadConfig(client clientset.Interface, kubeletVersion *version.Version, kubeletDir string) error {
|
||||
|
||||
// Download the ConfigMap from the cluster based on what version the kubelet is
|
||||
configMapName := configMapName(kubeletVersion)
|
||||
configMapName := kubeadmconstants.GetKubeletConfigMapName(kubeletVersion)
|
||||
|
||||
fmt.Printf("[kubelet] Downloading configuration for the kubelet from the %q ConfigMap in the %s namespace\n",
|
||||
configMapName, metav1.NamespaceSystem)
|
||||
@ -143,38 +143,28 @@ func DownloadConfig(client clientset.Interface, kubeletVersion *version.Version,
|
||||
return writeConfigBytesToDisk([]byte(kubeletCfg.Data[kubeadmconstants.KubeletBaseConfigurationConfigMapKey]), kubeletDir)
|
||||
}
|
||||
|
||||
// configMapName returns the right ConfigMap name for the right branch of k8s
|
||||
func configMapName(k8sVersion *version.Version) string {
|
||||
return fmt.Sprintf("%s%d.%d", kubeadmconstants.KubeletBaseConfigurationConfigMapPrefix, k8sVersion.Major(), k8sVersion.Minor())
|
||||
}
|
||||
|
||||
// configMapRBACName returns the name for the Role/RoleBinding for the kubelet config configmap for the right branch of k8s
|
||||
func configMapRBACName(k8sVersion *version.Version) string {
|
||||
return fmt.Sprintf("%s%d.%d", kubeadmconstants.KubeletBaseConfigMapRolePrefix, k8sVersion.Major(), k8sVersion.Minor())
|
||||
}
|
||||
|
||||
// getConfigBytes marshals a kubeletconfiguration object to bytes
|
||||
func getConfigBytes(kubeletConfig *kubeletconfigv1beta1.KubeletConfiguration) ([]byte, error) {
|
||||
_, kubeletCodecs, err := kubeletconfigscheme.NewSchemeAndCodecs()
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
|
||||
return kubeadmutil.MarshalToYamlForCodecs(kubeletConfig, kubeletconfigv1beta1.SchemeGroupVersion, *kubeletCodecs)
|
||||
// getConfigBytes marshals a KubeletConfiguration object to bytes
|
||||
func getConfigBytes(kubeletConfig *kubeletconfig.KubeletConfiguration) ([]byte, error) {
|
||||
return componentconfigs.Known[componentconfigs.KubeletConfigurationKind].Marshal(kubeletConfig)
|
||||
}
|
||||
|
||||
// writeConfigBytesToDisk writes a byte slice down to disk at the specific location of the kubelet config file
|
||||
func writeConfigBytesToDisk(b []byte, kubeletDir string) error {
|
||||
configFile := filepath.Join(kubeletDir, kubeadmconstants.KubeletConfigurationFileName)
|
||||
fmt.Printf("[kubelet] Writing kubelet configuration to file %q\n", configFile)
|
||||
fmt.Printf("[kubelet-start] Writing kubelet configuration to file %q\n", configFile)
|
||||
|
||||
// creates target folder if not already exists
|
||||
if err := os.MkdirAll(kubeletDir, 0700); err != nil {
|
||||
return fmt.Errorf("failed to create directory %q: %v", kubeletDir, err)
|
||||
return errors.Wrapf(err, "failed to create directory %q", kubeletDir)
|
||||
}
|
||||
|
||||
if err := ioutil.WriteFile(configFile, b, 0644); err != nil {
|
||||
return fmt.Errorf("failed to write kubelet configuration to the file %q: %v", configFile, err)
|
||||
return errors.Wrapf(err, "failed to write kubelet configuration to the file %q", configFile)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
16
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/kubelet/config_test.go
generated
vendored
16
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/kubelet/config_test.go
generated
vendored
@ -22,21 +22,23 @@ import (
|
||||
"k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/version"
|
||||
"k8s.io/client-go/kubernetes/fake"
|
||||
core "k8s.io/client-go/testing"
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
kubeletconfigv1beta1 "k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/v1beta1"
|
||||
"k8s.io/kubernetes/pkg/util/version"
|
||||
kubeletconfig "k8s.io/kubernetes/pkg/kubelet/apis/config"
|
||||
)
|
||||
|
||||
func TestCreateConfigMap(t *testing.T) {
|
||||
nodeName := "fake-node"
|
||||
client := fake.NewSimpleClientset()
|
||||
cfg := &kubeadmapi.MasterConfiguration{
|
||||
NodeRegistration: kubeadmapi.NodeRegistrationOptions{Name: nodeName},
|
||||
KubernetesVersion: "v1.11.0",
|
||||
KubeletConfiguration: kubeadmapi.KubeletConfiguration{
|
||||
BaseConfig: &kubeletconfigv1beta1.KubeletConfiguration{},
|
||||
cfg := &kubeadmapi.InitConfiguration{
|
||||
NodeRegistration: kubeadmapi.NodeRegistrationOptions{Name: nodeName},
|
||||
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
|
||||
KubernetesVersion: "v1.13.0",
|
||||
ComponentConfigs: kubeadmapi.ComponentConfigs{
|
||||
Kubelet: &kubeletconfig.KubeletConfiguration{},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
19
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/kubelet/dynamic.go
generated
vendored
19
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/kubelet/dynamic.go
generated
vendored
@ -19,42 +19,41 @@ package kubelet
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/version"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
|
||||
"k8s.io/kubernetes/pkg/util/version"
|
||||
)
|
||||
|
||||
// EnableDynamicConfigForNode updates the Node's ConfigSource to enable Dynamic Kubelet Configuration, depending on what version the kubelet is
|
||||
// Used at "kubeadm init", "kubeadm join" and "kubeadm upgrade" time
|
||||
// This func is ONLY run if the user enables the `DynamicKubeletConfig` feature gate, which is by default off
|
||||
func EnableDynamicConfigForNode(client clientset.Interface, nodeName string, kubeletVersion *version.Version) error {
|
||||
|
||||
configMapName := configMapName(kubeletVersion)
|
||||
configMapName := kubeadmconstants.GetKubeletConfigMapName(kubeletVersion)
|
||||
fmt.Printf("[kubelet] Enabling Dynamic Kubelet Config for Node %q; config sourced from ConfigMap %q in namespace %s\n",
|
||||
nodeName, configMapName, metav1.NamespaceSystem)
|
||||
fmt.Println("[kubelet] WARNING: The Dynamic Kubelet Config feature is alpha and off by default. It hasn't been well-tested yet at this stage, use with caution.")
|
||||
fmt.Println("[kubelet] WARNING: The Dynamic Kubelet Config feature is beta, but off by default. It hasn't been well-tested yet at this stage, use with caution.")
|
||||
|
||||
kubeletConfigMap, err := client.CoreV1().ConfigMaps(metav1.NamespaceSystem).Get(configMapName, metav1.GetOptions{})
|
||||
_, err := client.CoreV1().ConfigMaps(metav1.NamespaceSystem).Get(configMapName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("couldn't get the kubelet configuration ConfigMap: %v", err)
|
||||
return errors.Wrap(err, "couldn't get the kubelet configuration ConfigMap")
|
||||
}
|
||||
|
||||
// Loop on every falsy return. Return with an error if raised. Exit successfully if true is returned.
|
||||
return apiclient.PatchNode(client, nodeName, func(n *v1.Node) {
|
||||
patchNodeForDynamicConfig(n, configMapName, kubeletConfigMap.UID)
|
||||
patchNodeForDynamicConfig(n, configMapName)
|
||||
})
|
||||
}
|
||||
|
||||
func patchNodeForDynamicConfig(n *v1.Node, configMapName string, configMapUID types.UID) {
|
||||
func patchNodeForDynamicConfig(n *v1.Node, configMapName string) {
|
||||
n.Spec.ConfigSource = &v1.NodeConfigSource{
|
||||
ConfigMap: &v1.ConfigMapNodeConfigSource{
|
||||
Name: configMapName,
|
||||
Namespace: metav1.NamespaceSystem,
|
||||
UID: configMapUID,
|
||||
KubeletConfigKey: kubeadmconstants.KubeletBaseConfigurationConfigMapKey,
|
||||
},
|
||||
}
|
||||
|
2
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/kubelet/dynamic_test.go
generated
vendored
2
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/kubelet/dynamic_test.go
generated
vendored
@ -22,10 +22,10 @@ import (
|
||||
"k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/version"
|
||||
"k8s.io/client-go/kubernetes/fake"
|
||||
core "k8s.io/client-go/testing"
|
||||
kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis"
|
||||
"k8s.io/kubernetes/pkg/util/version"
|
||||
)
|
||||
|
||||
func TestEnableDynamicConfigForNode(t *testing.T) {
|
||||
|
54
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/kubelet/flags.go
generated
vendored
54
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/kubelet/flags.go
generated
vendored
@ -23,11 +23,12 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/pkg/errors"
|
||||
"k8s.io/klog"
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
kubeadmapiv1alpha2 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha2"
|
||||
kubeadmapiv1beta1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta1"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/features"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/images"
|
||||
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
|
||||
nodeutil "k8s.io/kubernetes/pkg/util/node"
|
||||
"k8s.io/kubernetes/pkg/util/procfs"
|
||||
@ -37,47 +38,54 @@ import (
|
||||
type kubeletFlagsOpts struct {
|
||||
nodeRegOpts *kubeadmapi.NodeRegistrationOptions
|
||||
featureGates map[string]bool
|
||||
pauseImage string
|
||||
registerTaintsUsingFlags bool
|
||||
execer utilsexec.Interface
|
||||
pidOfFunc func(string) ([]int, error)
|
||||
defaultHostname string
|
||||
}
|
||||
|
||||
// WriteKubeletDynamicEnvFile writes a 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.
|
||||
func WriteKubeletDynamicEnvFile(nodeRegOpts *kubeadmapi.NodeRegistrationOptions, featureGates map[string]bool, registerTaintsUsingFlags bool, kubeletDir string) error {
|
||||
func WriteKubeletDynamicEnvFile(cfg *kubeadmapi.InitConfiguration, registerTaintsUsingFlags bool, kubeletDir string) error {
|
||||
hostName, err := nodeutil.GetHostname("")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
flagOpts := kubeletFlagsOpts{
|
||||
nodeRegOpts: nodeRegOpts,
|
||||
featureGates: featureGates,
|
||||
nodeRegOpts: &cfg.NodeRegistration,
|
||||
featureGates: cfg.FeatureGates,
|
||||
pauseImage: images.GetPauseImage(&cfg.ClusterConfiguration),
|
||||
registerTaintsUsingFlags: registerTaintsUsingFlags,
|
||||
execer: utilsexec.New(),
|
||||
pidOfFunc: procfs.PidOf,
|
||||
defaultHostname: nodeutil.GetHostname(""),
|
||||
execer: utilsexec.New(),
|
||||
pidOfFunc: procfs.PidOf,
|
||||
defaultHostname: hostName,
|
||||
}
|
||||
stringMap := buildKubeletArgMap(flagOpts)
|
||||
argList := kubeadmutil.BuildArgumentListFromMap(stringMap, nodeRegOpts.KubeletExtraArgs)
|
||||
argList := kubeadmutil.BuildArgumentListFromMap(stringMap, cfg.NodeRegistration.KubeletExtraArgs)
|
||||
envFileContent := fmt.Sprintf("%s=%s\n", constants.KubeletEnvFileVariableName, strings.Join(argList, " "))
|
||||
|
||||
return writeKubeletFlagBytesToDisk([]byte(envFileContent), kubeletDir)
|
||||
}
|
||||
|
||||
// buildKubeletArgMap takes a MasterConfiguration object and builds based on that a string-string map with flags
|
||||
// buildKubeletArgMap takes a InitConfiguration object and builds based on that a string-string map with flags
|
||||
// that should be given to the local kubelet daemon.
|
||||
func buildKubeletArgMap(opts kubeletFlagsOpts) map[string]string {
|
||||
kubeletFlags := map[string]string{}
|
||||
|
||||
if opts.nodeRegOpts.CRISocket == kubeadmapiv1alpha2.DefaultCRISocket {
|
||||
if opts.nodeRegOpts.CRISocket == kubeadmapiv1beta1.DefaultCRISocket {
|
||||
// These flags should only be set when running docker
|
||||
kubeletFlags["network-plugin"] = "cni"
|
||||
kubeletFlags["cni-conf-dir"] = "/etc/cni/net.d"
|
||||
kubeletFlags["cni-bin-dir"] = "/opt/cni/bin"
|
||||
driver, err := kubeadmutil.GetCgroupDriverDocker(opts.execer)
|
||||
if err != nil {
|
||||
glog.Warningf("cannot automatically assign a '--cgroup-driver' value when starting the Kubelet: %v\n", err)
|
||||
klog.Warningf("cannot automatically assign a '--cgroup-driver' value when starting the Kubelet: %v\n", err)
|
||||
} else {
|
||||
kubeletFlags["cgroup-driver"] = driver
|
||||
}
|
||||
if opts.pauseImage != "" {
|
||||
kubeletFlags["pod-infra-container-image"] = opts.pauseImage
|
||||
}
|
||||
} else {
|
||||
kubeletFlags["container-runtime"] = "remote"
|
||||
kubeletFlags["container-runtime-endpoint"] = opts.nodeRegOpts.CRISocket
|
||||
@ -99,16 +107,10 @@ func buildKubeletArgMap(opts kubeletFlagsOpts) map[string]string {
|
||||
|
||||
// Make sure the node name we're passed will work with Kubelet
|
||||
if opts.nodeRegOpts.Name != "" && opts.nodeRegOpts.Name != opts.defaultHostname {
|
||||
glog.V(1).Info("setting kubelet hostname-override to %q", opts.nodeRegOpts.Name)
|
||||
klog.V(1).Infof("setting kubelet hostname-override to %q", opts.nodeRegOpts.Name)
|
||||
kubeletFlags["hostname-override"] = opts.nodeRegOpts.Name
|
||||
}
|
||||
|
||||
// If the user enabled Dynamic Kubelet Configuration (which is disabled by default), set the directory
|
||||
// in the CLI flags so that the feature actually gets enabled
|
||||
if features.Enabled(opts.featureGates, features.DynamicKubeletConfig) {
|
||||
kubeletFlags["dynamic-config-dir"] = filepath.Join(constants.KubeletRunDirectory, constants.DynamicKubeletConfigurationDirectoryName)
|
||||
}
|
||||
|
||||
// TODO: Conditionally set `--cgroup-driver` to either `systemd` or `cgroupfs` for CRI other than Docker
|
||||
|
||||
return kubeletFlags
|
||||
@ -117,14 +119,14 @@ func buildKubeletArgMap(opts kubeletFlagsOpts) map[string]string {
|
||||
// writeKubeletFlagBytesToDisk writes a byte slice down to disk at the specific location of the kubelet flag overrides file
|
||||
func writeKubeletFlagBytesToDisk(b []byte, kubeletDir string) error {
|
||||
kubeletEnvFilePath := filepath.Join(kubeletDir, constants.KubeletEnvFileName)
|
||||
fmt.Printf("[kubelet] Writing kubelet environment file with flags to file %q\n", kubeletEnvFilePath)
|
||||
fmt.Printf("[kubelet-start] Writing kubelet environment file with flags to file %q\n", kubeletEnvFilePath)
|
||||
|
||||
// creates target folder if not already exists
|
||||
if err := os.MkdirAll(kubeletDir, 0700); err != nil {
|
||||
return fmt.Errorf("failed to create directory %q: %v", kubeletDir, err)
|
||||
return errors.Wrapf(err, "failed to create directory %q", kubeletDir)
|
||||
}
|
||||
if err := ioutil.WriteFile(kubeletEnvFilePath, b, 0644); err != nil {
|
||||
return fmt.Errorf("failed to write kubelet configuration to the file %q: %v", kubeletEnvFilePath, err)
|
||||
return errors.Wrapf(err, "failed to write kubelet configuration to the file %q", kubeletEnvFilePath)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
31
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/kubelet/flags_test.go
generated
vendored
31
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/kubelet/flags_test.go
generated
vendored
@ -19,7 +19,6 @@ package kubelet
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"strings"
|
||||
@ -78,7 +77,7 @@ var (
|
||||
errCgroupExecer = fakeExecer{
|
||||
ioMap: map[string]fakeCmd{
|
||||
"docker info": {
|
||||
err: fmt.Errorf("no such binary: docker"),
|
||||
err: errors.New("no such binary: docker"),
|
||||
},
|
||||
},
|
||||
}
|
||||
@ -119,8 +118,6 @@ func TestBuildKubeletArgMap(t *testing.T) {
|
||||
},
|
||||
expected: map[string]string{
|
||||
"network-plugin": "cni",
|
||||
"cni-conf-dir": "/etc/cni/net.d",
|
||||
"cni-bin-dir": "/opt/cni/bin",
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -136,8 +133,6 @@ func TestBuildKubeletArgMap(t *testing.T) {
|
||||
},
|
||||
expected: map[string]string{
|
||||
"network-plugin": "cni",
|
||||
"cni-conf-dir": "/etc/cni/net.d",
|
||||
"cni-bin-dir": "/opt/cni/bin",
|
||||
"hostname-override": "override-name",
|
||||
},
|
||||
},
|
||||
@ -154,8 +149,6 @@ func TestBuildKubeletArgMap(t *testing.T) {
|
||||
},
|
||||
expected: map[string]string{
|
||||
"network-plugin": "cni",
|
||||
"cni-conf-dir": "/etc/cni/net.d",
|
||||
"cni-bin-dir": "/opt/cni/bin",
|
||||
"cgroup-driver": "systemd",
|
||||
},
|
||||
},
|
||||
@ -172,8 +165,6 @@ func TestBuildKubeletArgMap(t *testing.T) {
|
||||
},
|
||||
expected: map[string]string{
|
||||
"network-plugin": "cni",
|
||||
"cni-conf-dir": "/etc/cni/net.d",
|
||||
"cni-bin-dir": "/opt/cni/bin",
|
||||
"cgroup-driver": "cgroupfs",
|
||||
},
|
||||
},
|
||||
@ -213,9 +204,9 @@ func TestBuildKubeletArgMap(t *testing.T) {
|
||||
},
|
||||
},
|
||||
registerTaintsUsingFlags: true,
|
||||
execer: cgroupfsCgroupExecer,
|
||||
pidOfFunc: binaryNotRunningPidOfFunc,
|
||||
defaultHostname: "foo",
|
||||
execer: cgroupfsCgroupExecer,
|
||||
pidOfFunc: binaryNotRunningPidOfFunc,
|
||||
defaultHostname: "foo",
|
||||
},
|
||||
expected: map[string]string{
|
||||
"container-runtime": "remote",
|
||||
@ -241,23 +232,21 @@ func TestBuildKubeletArgMap(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "dynamic kubelet config enabled",
|
||||
name: "pause image is set",
|
||||
opts: kubeletFlagsOpts{
|
||||
nodeRegOpts: &kubeadmapi.NodeRegistrationOptions{
|
||||
CRISocket: "/var/run/containerd.sock",
|
||||
CRISocket: "/var/run/dockershim.sock",
|
||||
Name: "foo",
|
||||
},
|
||||
featureGates: map[string]bool{
|
||||
"DynamicKubeletConfig": true,
|
||||
},
|
||||
pauseImage: "gcr.io/pause:3.1",
|
||||
execer: cgroupfsCgroupExecer,
|
||||
pidOfFunc: binaryNotRunningPidOfFunc,
|
||||
defaultHostname: "foo",
|
||||
},
|
||||
expected: map[string]string{
|
||||
"container-runtime": "remote",
|
||||
"container-runtime-endpoint": "/var/run/containerd.sock",
|
||||
"dynamic-config-dir": "/var/lib/kubelet/dynamic-config",
|
||||
"network-plugin": "cni",
|
||||
"cgroup-driver": "cgroupfs",
|
||||
"pod-infra-container-image": "gcr.io/pause:3.1",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
63
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/kubelet/kubelet.go
generated
vendored
Normal file
63
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/kubelet/kubelet.go
generated
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package kubelet
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/kubernetes/pkg/util/initsystem"
|
||||
)
|
||||
|
||||
// TryStartKubelet attempts to bring up kubelet service
|
||||
func TryStartKubelet() {
|
||||
// If we notice that the kubelet service is inactive, try to start it
|
||||
initSystem, err := initsystem.GetInitSystem()
|
||||
if err != nil {
|
||||
fmt.Println("[kubelet-start] no supported init system detected, won't make sure the kubelet is running properly.")
|
||||
return
|
||||
}
|
||||
|
||||
if !initSystem.ServiceExists("kubelet") {
|
||||
fmt.Println("[kubelet-start] couldn't detect a kubelet service, can't make sure the kubelet is running properly.")
|
||||
}
|
||||
|
||||
fmt.Println("[kubelet-start] Activating the kubelet service")
|
||||
// This runs "systemctl daemon-reload && systemctl restart kubelet"
|
||||
if err := initSystem.ServiceRestart("kubelet"); err != nil {
|
||||
fmt.Printf("[kubelet-start] WARNING: unable to start the kubelet service: [%v]\n", err)
|
||||
fmt.Printf("[kubelet-start] please ensure kubelet is reloaded and running manually.\n")
|
||||
}
|
||||
}
|
||||
|
||||
// TryStopKubelet attempts to bring down the kubelet service momentarily
|
||||
func TryStopKubelet() {
|
||||
// If we notice that the kubelet service is inactive, try to start it
|
||||
initSystem, err := initsystem.GetInitSystem()
|
||||
if err != nil {
|
||||
fmt.Println("[kubelet-start] no supported init system detected, won't make sure the kubelet not running for a short period of time while setting up configuration for it.")
|
||||
return
|
||||
}
|
||||
|
||||
if !initSystem.ServiceExists("kubelet") {
|
||||
fmt.Println("[kubelet-start] couldn't detect a kubelet service, can't make sure the kubelet not running for a short period of time while setting up configuration for it.")
|
||||
}
|
||||
|
||||
// This runs "systemctl daemon-reload && systemctl stop kubelet"
|
||||
if err := initSystem.ServiceStop("kubelet"); err != nil {
|
||||
fmt.Printf("[kubelet-start] WARNING: unable to stop the kubelet service momentarily: [%v]\n", err)
|
||||
}
|
||||
}
|
@ -8,28 +8,28 @@ load(
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["markmaster_test.go"],
|
||||
srcs = ["markcontrolplane_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/constants:go_default_library",
|
||||
"//pkg/kubelet/apis:go_default_library",
|
||||
"//pkg/util/node:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//vendor/k8s.io/client-go/rest: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/client-go/kubernetes:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/rest:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["markmaster.go"],
|
||||
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/phases/markmaster",
|
||||
srcs = ["markcontrolplane.go"],
|
||||
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/phases/markcontrolplane",
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/constants:go_default_library",
|
||||
"//cmd/kubeadm/app/util/apiclient:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
|
||||
],
|
||||
)
|
||||
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package markmaster
|
||||
package markcontrolplane
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@ -25,20 +25,20 @@ import (
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
|
||||
)
|
||||
|
||||
// MarkMaster taints the master and sets the master label
|
||||
func MarkMaster(client clientset.Interface, masterName string, taints []v1.Taint) error {
|
||||
// MarkControlPlane taints the control-plane and sets the control-plane label
|
||||
func MarkControlPlane(client clientset.Interface, controlPlaneName string, taints []v1.Taint) error {
|
||||
|
||||
fmt.Printf("[markmaster] Marking the node %s as master by adding the label \"%s=''\"\n", masterName, constants.LabelNodeRoleMaster)
|
||||
fmt.Printf("[mark-control-plane] Marking the node %s as control-plane by adding the label \"%s=''\"\n", controlPlaneName, constants.LabelNodeRoleMaster)
|
||||
|
||||
if taints != nil && len(taints) > 0 {
|
||||
taintStrs := []string{}
|
||||
for _, taint := range taints {
|
||||
taintStrs = append(taintStrs, taint.ToString())
|
||||
}
|
||||
fmt.Printf("[markmaster] Marking the node %s as master by adding the taints %v\n", masterName, taintStrs)
|
||||
fmt.Printf("[mark-control-plane] Marking the node %s as control-plane by adding the taints %v\n", controlPlaneName, taintStrs)
|
||||
}
|
||||
|
||||
return apiclient.PatchNode(client, masterName, func(n *v1.Node) {
|
||||
return apiclient.PatchNode(client, controlPlaneName, func(n *v1.Node) {
|
||||
markMasterNode(n, taints)
|
||||
})
|
||||
}
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package markmaster
|
||||
package markcontrolplane
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@ -33,7 +33,7 @@ import (
|
||||
"k8s.io/kubernetes/pkg/util/node"
|
||||
)
|
||||
|
||||
func TestMarkMaster(t *testing.T) {
|
||||
func TestMarkControlPlane(t *testing.T) {
|
||||
// Note: this test takes advantage of the deterministic marshalling of
|
||||
// JSON provided by strategicpatch so that "expectedPatch" can use a
|
||||
// string equality test instead of a logical JSON equality test. That
|
||||
@ -47,28 +47,28 @@ func TestMarkMaster(t *testing.T) {
|
||||
expectedPatch string
|
||||
}{
|
||||
{
|
||||
"master label and taint missing",
|
||||
"control-plane label and taint missing",
|
||||
"",
|
||||
nil,
|
||||
[]v1.Taint{kubeadmconstants.MasterTaint},
|
||||
"{\"metadata\":{\"labels\":{\"node-role.kubernetes.io/master\":\"\"}},\"spec\":{\"taints\":[{\"effect\":\"NoSchedule\",\"key\":\"node-role.kubernetes.io/master\"}]}}",
|
||||
},
|
||||
{
|
||||
"master label and taint missing but taint not wanted",
|
||||
"control-plane label and taint missing but taint not wanted",
|
||||
"",
|
||||
nil,
|
||||
nil,
|
||||
"{\"metadata\":{\"labels\":{\"node-role.kubernetes.io/master\":\"\"}}}",
|
||||
},
|
||||
{
|
||||
"master label missing",
|
||||
"control-plane label missing",
|
||||
"",
|
||||
[]v1.Taint{kubeadmconstants.MasterTaint},
|
||||
[]v1.Taint{kubeadmconstants.MasterTaint},
|
||||
"{\"metadata\":{\"labels\":{\"node-role.kubernetes.io/master\":\"\"}}}",
|
||||
},
|
||||
{
|
||||
"master taint missing",
|
||||
"control-plane taint missing",
|
||||
kubeadmconstants.LabelNodeRoleMaster,
|
||||
nil,
|
||||
[]v1.Taint{kubeadmconstants.MasterTaint},
|
||||
@ -108,8 +108,11 @@ func TestMarkMaster(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
hostname := node.GetHostname("")
|
||||
masterNode := &v1.Node{
|
||||
hostname, err := node.GetHostname("")
|
||||
if err != nil {
|
||||
t.Fatalf("MarkControlPlane(%s): unexpected error: %v", tc.name, err)
|
||||
}
|
||||
controlPlaneNode := &v1.Node{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: hostname,
|
||||
Labels: map[string]string{
|
||||
@ -119,16 +122,16 @@ func TestMarkMaster(t *testing.T) {
|
||||
}
|
||||
|
||||
if tc.existingLabel != "" {
|
||||
masterNode.ObjectMeta.Labels[tc.existingLabel] = ""
|
||||
controlPlaneNode.ObjectMeta.Labels[tc.existingLabel] = ""
|
||||
}
|
||||
|
||||
if tc.existingTaints != nil {
|
||||
masterNode.Spec.Taints = tc.existingTaints
|
||||
controlPlaneNode.Spec.Taints = tc.existingTaints
|
||||
}
|
||||
|
||||
jsonNode, err := json.Marshal(masterNode)
|
||||
jsonNode, err := json.Marshal(controlPlaneNode)
|
||||
if err != nil {
|
||||
t.Fatalf("MarkMaster(%s): unexpected encoding error: %v", tc.name, err)
|
||||
t.Fatalf("MarkControlPlane(%s): unexpected encoding error: %v", tc.name, err)
|
||||
}
|
||||
|
||||
var patchRequest string
|
||||
@ -136,8 +139,8 @@ func TestMarkMaster(t *testing.T) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
if req.URL.Path != "/api/v1/nodes/"+hostname {
|
||||
t.Errorf("MarkMaster(%s): request for unexpected HTTP resource: %v", tc.name, req.URL.Path)
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
t.Errorf("MarkControlPlane(%s): request for unexpected HTTP resource: %v", tc.name, req.URL.Path)
|
||||
http.Error(w, "", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
@ -146,8 +149,8 @@ func TestMarkMaster(t *testing.T) {
|
||||
case "PATCH":
|
||||
patchRequest = toString(req.Body)
|
||||
default:
|
||||
t.Errorf("MarkMaster(%s): request for unexpected HTTP verb: %v", tc.name, req.Method)
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
t.Errorf("MarkControlPlane(%s): request for unexpected HTTP verb: %v", tc.name, req.Method)
|
||||
http.Error(w, "", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
@ -158,15 +161,15 @@ func TestMarkMaster(t *testing.T) {
|
||||
|
||||
cs, err := clientset.NewForConfig(&restclient.Config{Host: s.URL})
|
||||
if err != nil {
|
||||
t.Fatalf("MarkMaster(%s): unexpected error building clientset: %v", tc.name, err)
|
||||
t.Fatalf("MarkControlPlane(%s): unexpected error building clientset: %v", tc.name, err)
|
||||
}
|
||||
|
||||
if err := MarkMaster(cs, hostname, tc.newTaints); err != nil {
|
||||
t.Errorf("MarkMaster(%s) returned unexpected error: %v", tc.name, err)
|
||||
if err := MarkControlPlane(cs, hostname, tc.newTaints); err != nil {
|
||||
t.Errorf("MarkControlPlane(%s) returned unexpected error: %v", tc.name, err)
|
||||
}
|
||||
|
||||
if tc.expectedPatch != patchRequest {
|
||||
t.Errorf("MarkMaster(%s) wanted patch %v, got %v", tc.name, tc.expectedPatch, patchRequest)
|
||||
t.Errorf("MarkControlPlane(%s) wanted patch %v, got %v", tc.name, tc.expectedPatch, patchRequest)
|
||||
}
|
||||
}
|
||||
}
|
4
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/patchnode/BUILD
generated
vendored
4
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/patchnode/BUILD
generated
vendored
@ -8,8 +8,8 @@ go_library(
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/constants:go_default_library",
|
||||
"//cmd/kubeadm/app/util/apiclient:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
|
3
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/patchnode/patchnode.go
generated
vendored
3
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/patchnode/patchnode.go
generated
vendored
@ -36,5 +36,8 @@ func AnnotateCRISocket(client clientset.Interface, nodeName string, criSocket st
|
||||
}
|
||||
|
||||
func annotateNodeWithCRISocket(n *v1.Node, criSocket string) {
|
||||
if n.ObjectMeta.Annotations == nil {
|
||||
n.ObjectMeta.Annotations = make(map[string]string)
|
||||
}
|
||||
n.ObjectMeta.Annotations[constants.AnnotationKubeadmCRISocket] = criSocket
|
||||
}
|
||||
|
21
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/selfhosting/BUILD
generated
vendored
21
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/selfhosting/BUILD
generated
vendored
@ -17,8 +17,9 @@ go_test(
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/constants:go_default_library",
|
||||
"//cmd/kubeadm/app/util:go_default_library",
|
||||
"//vendor/k8s.io/api/apps/v1:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//staging/src/k8s.io/api/apps/v1:go_default_library",
|
||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/github.com/pkg/errors:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@ -33,16 +34,16 @@ go_library(
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
|
||||
"//cmd/kubeadm/app/constants:go_default_library",
|
||||
"//cmd/kubeadm/app/features:go_default_library",
|
||||
"//cmd/kubeadm/app/util:go_default_library",
|
||||
"//cmd/kubeadm/app/util/apiclient:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/k8s.io/api/apps/v1:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes/scheme:go_default_library",
|
||||
"//staging/src/k8s.io/api/apps/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/runtime:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/kubernetes/scheme:go_default_library",
|
||||
"//vendor/github.com/pkg/errors:go_default_library",
|
||||
"//vendor/k8s.io/klog:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
|
9
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/selfhosting/podspec_mutation.go
generated
vendored
9
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/selfhosting/podspec_mutation.go
generated
vendored
@ -22,7 +22,6 @@ import (
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/features"
|
||||
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
|
||||
)
|
||||
|
||||
@ -59,18 +58,18 @@ func GetDefaultMutators() map[string][]PodSpecMutatorFunc {
|
||||
}
|
||||
|
||||
// GetMutatorsFromFeatureGates returns all mutators needed based on the feature gates passed
|
||||
func GetMutatorsFromFeatureGates(featureGates map[string]bool) map[string][]PodSpecMutatorFunc {
|
||||
func GetMutatorsFromFeatureGates(certsInSecrets bool) map[string][]PodSpecMutatorFunc {
|
||||
// Here the map of different mutators to use for the control plane's podspec is stored
|
||||
mutators := GetDefaultMutators()
|
||||
|
||||
// Some extra work to be done if we should store the control plane certificates in Secrets
|
||||
if features.Enabled(featureGates, features.StoreCertsInSecrets) {
|
||||
|
||||
if certsInSecrets {
|
||||
// Some extra work to be done if we should store the control plane certificates in Secrets
|
||||
// Add the store-certs-in-secrets-specific mutators here so that the self-hosted component starts using them
|
||||
mutators[kubeadmconstants.KubeAPIServer] = append(mutators[kubeadmconstants.KubeAPIServer], setSelfHostedVolumesForAPIServer)
|
||||
mutators[kubeadmconstants.KubeControllerManager] = append(mutators[kubeadmconstants.KubeControllerManager], setSelfHostedVolumesForControllerManager)
|
||||
mutators[kubeadmconstants.KubeScheduler] = append(mutators[kubeadmconstants.KubeScheduler], setSelfHostedVolumesForScheduler)
|
||||
}
|
||||
|
||||
return mutators
|
||||
}
|
||||
|
||||
|
2
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/selfhosting/podspec_mutation_test.go
generated
vendored
2
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/selfhosting/podspec_mutation_test.go
generated
vendored
@ -130,7 +130,7 @@ func TestAddNodeSelectorToPodSpec(t *testing.T) {
|
||||
},
|
||||
expected: v1.PodSpec{
|
||||
NodeSelector: map[string]string{
|
||||
"foo": "bar",
|
||||
"foo": "bar",
|
||||
kubeadmconstants.LabelNodeRoleMaster: "",
|
||||
},
|
||||
},
|
||||
|
24
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/selfhosting/selfhosting.go
generated
vendored
24
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/selfhosting/selfhosting.go
generated
vendored
@ -22,8 +22,9 @@ import (
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/klog"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
apps "k8s.io/api/apps/v1"
|
||||
"k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@ -32,7 +33,6 @@ import (
|
||||
clientscheme "k8s.io/client-go/kubernetes/scheme"
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/features"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
|
||||
)
|
||||
|
||||
@ -56,18 +56,16 @@ const (
|
||||
// 8. In order to avoid race conditions, we have to make sure that static pod is deleted correctly before we continue
|
||||
// Otherwise, there is a race condition when we proceed without kubelet having restarted the API server correctly and the next .Create call flakes
|
||||
// 9. Do that for the kube-apiserver, kube-controller-manager and kube-scheduler in a loop
|
||||
func CreateSelfHostedControlPlane(manifestsDir, kubeConfigDir string, cfg *kubeadmapi.MasterConfiguration, client clientset.Interface, waiter apiclient.Waiter, dryRun bool) error {
|
||||
glog.V(1).Infoln("creating self hosted control plane")
|
||||
func CreateSelfHostedControlPlane(manifestsDir, kubeConfigDir string, cfg *kubeadmapi.InitConfiguration, client clientset.Interface, waiter apiclient.Waiter, dryRun bool, certsInSecrets bool) error {
|
||||
klog.V(1).Infoln("creating self hosted control plane")
|
||||
// Adjust the timeout slightly to something self-hosting specific
|
||||
waiter.SetTimeout(selfHostingWaitTimeout)
|
||||
|
||||
// Here the map of different mutators to use for the control plane's PodSpec is stored
|
||||
glog.V(1).Infoln("getting mutators")
|
||||
mutators := GetMutatorsFromFeatureGates(cfg.FeatureGates)
|
||||
|
||||
// Some extra work to be done if we should store the control plane certificates in Secrets
|
||||
if features.Enabled(cfg.FeatureGates, features.StoreCertsInSecrets) {
|
||||
klog.V(1).Infoln("getting mutators")
|
||||
mutators := GetMutatorsFromFeatureGates(certsInSecrets)
|
||||
|
||||
if certsInSecrets {
|
||||
// Upload the certificates and kubeconfig files from disk to the cluster as Secrets
|
||||
if err := uploadTLSSecrets(client, cfg.CertificatesDir); err != nil {
|
||||
return err
|
||||
@ -111,7 +109,7 @@ func CreateSelfHostedControlPlane(manifestsDir, kubeConfigDir string, cfg *kubea
|
||||
// Remove the old Static Pod manifest if not dryrunning
|
||||
if !dryRun {
|
||||
if err := os.RemoveAll(manifestPath); err != nil {
|
||||
return fmt.Errorf("unable to delete static pod manifest for %s [%v]", componentName, err)
|
||||
return errors.Wrapf(err, "unable to delete static pod manifest for %s ", componentName)
|
||||
}
|
||||
}
|
||||
|
||||
@ -179,18 +177,18 @@ func BuildSelfHostedComponentLabelQuery(componentName string) string {
|
||||
func loadPodSpecFromFile(filePath string) (*v1.PodSpec, error) {
|
||||
podDef, err := ioutil.ReadFile(filePath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read file path %s: %+v", filePath, err)
|
||||
return nil, errors.Wrapf(err, "failed to read file path %s", filePath)
|
||||
}
|
||||
|
||||
if len(podDef) == 0 {
|
||||
return nil, fmt.Errorf("file was empty: %s", filePath)
|
||||
return nil, errors.Errorf("file was empty: %s", filePath)
|
||||
}
|
||||
|
||||
codec := clientscheme.Codecs.UniversalDecoder()
|
||||
pod := &v1.Pod{}
|
||||
|
||||
if err = runtime.DecodeInto(codec, podDef, pod); err != nil {
|
||||
return nil, fmt.Errorf("failed decoding pod: %v", err)
|
||||
return nil, errors.Wrap(err, "failed decoding pod")
|
||||
}
|
||||
|
||||
return &pod.Spec, nil
|
||||
|
9
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/selfhosting/selfhosting_test.go
generated
vendored
9
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/selfhosting/selfhosting_test.go
generated
vendored
@ -18,11 +18,12 @@ package selfhosting
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
apps "k8s.io/api/apps/v1"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/util"
|
||||
@ -588,13 +589,13 @@ spec:
|
||||
func createTempFileWithContent(content []byte) (string, error) {
|
||||
tempFile, err := ioutil.TempFile("", "")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("cannot create temporary file: %v", err)
|
||||
return "", errors.Wrap(err, "cannot create temporary file")
|
||||
}
|
||||
if _, err = tempFile.Write([]byte(content)); err != nil {
|
||||
return "", fmt.Errorf("cannot save temporary file: %v", err)
|
||||
return "", errors.Wrap(err, "cannot save temporary file")
|
||||
}
|
||||
if err = tempFile.Close(); err != nil {
|
||||
return "", fmt.Errorf("cannot close temporary file: %v", err)
|
||||
return "", errors.Wrap(err, "cannot close temporary file")
|
||||
}
|
||||
return tempFile.Name(), nil
|
||||
}
|
||||
|
47
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/upgrade/BUILD
generated
vendored
47
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/upgrade/BUILD
generated
vendored
@ -8,7 +8,6 @@ go_library(
|
||||
"policy.go",
|
||||
"postupgrade.go",
|
||||
"prepull.go",
|
||||
"selfhosted.go",
|
||||
"staticpods.go",
|
||||
"versiongetter.go",
|
||||
],
|
||||
@ -16,37 +15,38 @@ go_library(
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
|
||||
"//cmd/kubeadm/app/apis/kubeadm/v1alpha2:go_default_library",
|
||||
"//cmd/kubeadm/app/apis/kubeadm/v1beta1:go_default_library",
|
||||
"//cmd/kubeadm/app/constants:go_default_library",
|
||||
"//cmd/kubeadm/app/features:go_default_library",
|
||||
"//cmd/kubeadm/app/images:go_default_library",
|
||||
"//cmd/kubeadm/app/phases/addons/dns:go_default_library",
|
||||
"//cmd/kubeadm/app/phases/addons/proxy:go_default_library",
|
||||
"//cmd/kubeadm/app/phases/bootstraptoken/clusterinfo:go_default_library",
|
||||
"//cmd/kubeadm/app/phases/bootstraptoken/node:go_default_library",
|
||||
"//cmd/kubeadm/app/phases/certs:go_default_library",
|
||||
"//cmd/kubeadm/app/phases/certs/renewal:go_default_library",
|
||||
"//cmd/kubeadm/app/phases/controlplane:go_default_library",
|
||||
"//cmd/kubeadm/app/phases/etcd:go_default_library",
|
||||
"//cmd/kubeadm/app/phases/kubelet:go_default_library",
|
||||
"//cmd/kubeadm/app/phases/patchnode:go_default_library",
|
||||
"//cmd/kubeadm/app/phases/selfhosting:go_default_library",
|
||||
"//cmd/kubeadm/app/phases/uploadconfig:go_default_library",
|
||||
"//cmd/kubeadm/app/preflight:go_default_library",
|
||||
"//cmd/kubeadm/app/util:go_default_library",
|
||||
"//cmd/kubeadm/app/util/apiclient:go_default_library",
|
||||
"//cmd/kubeadm/app/util/dryrun:go_default_library",
|
||||
"//cmd/kubeadm/app/util/etcd:go_default_library",
|
||||
"//pkg/util/version:go_default_library",
|
||||
"//cmd/kubeadm/app/util/staticpod:go_default_library",
|
||||
"//pkg/version:go_default_library",
|
||||
"//vendor/k8s.io/api/apps/v1:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/errors:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//vendor/k8s.io/client-go/util/cert:go_default_library",
|
||||
"//staging/src/k8s.io/api/apps/v1:go_default_library",
|
||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/errors: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/client-go/kubernetes:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/util/cert:go_default_library",
|
||||
"//vendor/github.com/pkg/errors:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@ -76,23 +76,24 @@ go_test(
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
|
||||
"//cmd/kubeadm/app/apis/kubeadm/scheme:go_default_library",
|
||||
"//cmd/kubeadm/app/apis/kubeadm/v1alpha2:go_default_library",
|
||||
"//cmd/kubeadm/app/apis/kubeadm/validation:go_default_library",
|
||||
"//cmd/kubeadm/app/constants:go_default_library",
|
||||
"//cmd/kubeadm/app/phases/certs:go_default_library",
|
||||
"//cmd/kubeadm/app/phases/certs/pkiutil:go_default_library",
|
||||
"//cmd/kubeadm/app/phases/controlplane:go_default_library",
|
||||
"//cmd/kubeadm/app/phases/etcd:go_default_library",
|
||||
"//cmd/kubeadm/app/util/apiclient:go_default_library",
|
||||
"//cmd/kubeadm/app/util/config:go_default_library",
|
||||
"//cmd/kubeadm/app/util/etcd:go_default_library",
|
||||
"//cmd/kubeadm/app/util/pkiutil:go_default_library",
|
||||
"//cmd/kubeadm/test:go_default_library",
|
||||
"//pkg/util/version:go_default_library",
|
||||
"//cmd/kubeadm/test/certs:go_default_library",
|
||||
"//staging/src/k8s.io/api/apps/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/util/version:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library",
|
||||
"//vendor/github.com/coreos/etcd/clientv3:go_default_library",
|
||||
"//vendor/github.com/coreos/etcd/pkg/transport:go_default_library",
|
||||
"//vendor/k8s.io/api/apps/v1:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes/fake:go_default_library",
|
||||
"//vendor/github.com/pkg/errors:go_default_library",
|
||||
],
|
||||
)
|
||||
|
40
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/upgrade/compute.go
generated
vendored
40
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/upgrade/compute.go
generated
vendored
@ -20,12 +20,12 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
versionutil "k8s.io/apimachinery/pkg/util/version"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/features"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/dns"
|
||||
etcdutil "k8s.io/kubernetes/cmd/kubeadm/app/util/etcd"
|
||||
versionutil "k8s.io/kubernetes/pkg/util/version"
|
||||
)
|
||||
|
||||
// Upgrade defines an upgrade possibility to upgrade from a current version to a new one
|
||||
@ -56,20 +56,12 @@ func (u *Upgrade) CanUpgradeEtcd() bool {
|
||||
return u.Before.EtcdVersion != u.After.EtcdVersion
|
||||
}
|
||||
|
||||
// ActiveDNSAddon returns the version of CoreDNS or kube-dns
|
||||
func ActiveDNSAddon(featureGates map[string]bool) string {
|
||||
if features.Enabled(featureGates, features.CoreDNS) {
|
||||
return kubeadmconstants.CoreDNS
|
||||
}
|
||||
return kubeadmconstants.KubeDNS
|
||||
}
|
||||
|
||||
// ClusterState describes the state of certain versions for a cluster
|
||||
type ClusterState struct {
|
||||
// KubeVersion describes the version of the Kubernetes API Server, Controller Manager, Scheduler and Proxy.
|
||||
KubeVersion string
|
||||
// DNSType
|
||||
DNSType string
|
||||
DNSType kubeadmapi.DNSAddOnType
|
||||
// DNSVersion describes the version of the kube-dns images used and manifest version
|
||||
DNSVersion string
|
||||
// KubeadmVersion describes the version of the kubeadm CLI
|
||||
@ -82,7 +74,7 @@ type ClusterState struct {
|
||||
|
||||
// GetAvailableUpgrades fetches all versions from the specified VersionGetter and computes which
|
||||
// kinds of upgrades can be performed
|
||||
func GetAvailableUpgrades(versionGetterImpl VersionGetter, experimentalUpgradesAllowed, rcUpgradesAllowed bool, etcdClient etcdutil.ClusterInterrogator, featureGates map[string]bool, client clientset.Interface) ([]Upgrade, error) {
|
||||
func GetAvailableUpgrades(versionGetterImpl VersionGetter, experimentalUpgradesAllowed, rcUpgradesAllowed bool, etcdClient etcdutil.ClusterInterrogator, dnsType kubeadmapi.DNSAddOnType, client clientset.Interface) ([]Upgrade, error) {
|
||||
fmt.Println("[upgrade] Fetching available versions to upgrade to")
|
||||
|
||||
// Collect the upgrades kubeadm can do in this list
|
||||
@ -120,7 +112,7 @@ func GetAvailableUpgrades(versionGetterImpl VersionGetter, experimentalUpgradesA
|
||||
return upgrades, err
|
||||
}
|
||||
|
||||
dnsType, dnsVersion, err := dns.DeployedDNSAddon(client)
|
||||
currentDNSType, dnsVersion, err := dns.DeployedDNSAddon(client)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -128,7 +120,7 @@ func GetAvailableUpgrades(versionGetterImpl VersionGetter, experimentalUpgradesA
|
||||
// Construct a descriptor for the current state of the world
|
||||
beforeState := ClusterState{
|
||||
KubeVersion: clusterVersionStr,
|
||||
DNSType: dnsType,
|
||||
DNSType: currentDNSType,
|
||||
DNSVersion: dnsVersion,
|
||||
KubeadmVersion: kubeadmVersionStr,
|
||||
KubeletVersions: kubeletVersions,
|
||||
@ -172,8 +164,8 @@ func GetAvailableUpgrades(versionGetterImpl VersionGetter, experimentalUpgradesA
|
||||
Before: beforeState,
|
||||
After: ClusterState{
|
||||
KubeVersion: patchVersionStr,
|
||||
DNSType: ActiveDNSAddon(featureGates),
|
||||
DNSVersion: kubeadmconstants.GetDNSVersion(ActiveDNSAddon(featureGates)),
|
||||
DNSType: dnsType,
|
||||
DNSVersion: kubeadmconstants.GetDNSVersion(dnsType),
|
||||
KubeadmVersion: newKubeadmVer,
|
||||
EtcdVersion: getSuggestedEtcdVersion(patchVersionStr),
|
||||
// KubeletVersions is unset here as it is not used anywhere in .After
|
||||
@ -189,8 +181,8 @@ func GetAvailableUpgrades(versionGetterImpl VersionGetter, experimentalUpgradesA
|
||||
Before: beforeState,
|
||||
After: ClusterState{
|
||||
KubeVersion: stableVersionStr,
|
||||
DNSType: ActiveDNSAddon(featureGates),
|
||||
DNSVersion: kubeadmconstants.GetDNSVersion(ActiveDNSAddon(featureGates)),
|
||||
DNSType: dnsType,
|
||||
DNSVersion: kubeadmconstants.GetDNSVersion(dnsType),
|
||||
KubeadmVersion: stableVersionStr,
|
||||
EtcdVersion: getSuggestedEtcdVersion(stableVersionStr),
|
||||
// KubeletVersions is unset here as it is not used anywhere in .After
|
||||
@ -235,8 +227,8 @@ func GetAvailableUpgrades(versionGetterImpl VersionGetter, experimentalUpgradesA
|
||||
Before: beforeState,
|
||||
After: ClusterState{
|
||||
KubeVersion: previousBranchLatestVersionStr,
|
||||
DNSType: ActiveDNSAddon(featureGates),
|
||||
DNSVersion: kubeadmconstants.GetDNSVersion(ActiveDNSAddon(featureGates)),
|
||||
DNSType: dnsType,
|
||||
DNSVersion: kubeadmconstants.GetDNSVersion(dnsType),
|
||||
KubeadmVersion: previousBranchLatestVersionStr,
|
||||
EtcdVersion: getSuggestedEtcdVersion(previousBranchLatestVersionStr),
|
||||
// KubeletVersions is unset here as it is not used anywhere in .After
|
||||
@ -249,12 +241,12 @@ func GetAvailableUpgrades(versionGetterImpl VersionGetter, experimentalUpgradesA
|
||||
|
||||
// Default to assume that the experimental version to show is the unstable one
|
||||
unstableKubeVersion := latestVersionStr
|
||||
unstableKubeDNSVersion := kubeadmconstants.GetDNSVersion(ActiveDNSAddon(featureGates))
|
||||
unstableKubeDNSVersion := kubeadmconstants.GetDNSVersion(dnsType)
|
||||
|
||||
// Ẃe should not display alpha.0. The previous branch's beta/rc versions are more relevant due how the kube branching process works.
|
||||
if latestVersion.PreRelease() == "alpha.0" {
|
||||
unstableKubeVersion = previousBranchLatestVersionStr
|
||||
unstableKubeDNSVersion = kubeadmconstants.GetDNSVersion(ActiveDNSAddon(featureGates))
|
||||
unstableKubeDNSVersion = kubeadmconstants.GetDNSVersion(dnsType)
|
||||
}
|
||||
|
||||
upgrades = append(upgrades, Upgrade{
|
||||
@ -262,7 +254,7 @@ func GetAvailableUpgrades(versionGetterImpl VersionGetter, experimentalUpgradesA
|
||||
Before: beforeState,
|
||||
After: ClusterState{
|
||||
KubeVersion: unstableKubeVersion,
|
||||
DNSType: ActiveDNSAddon(featureGates),
|
||||
DNSType: dnsType,
|
||||
DNSVersion: unstableKubeDNSVersion,
|
||||
KubeadmVersion: unstableKubeVersion,
|
||||
EtcdVersion: getSuggestedEtcdVersion(unstableKubeVersion),
|
||||
@ -302,7 +294,7 @@ func minorUpgradePossibleWithPatchRelease(stableVersion, patchVersion *versionut
|
||||
func getSuggestedEtcdVersion(kubernetesVersion string) string {
|
||||
etcdVersion, err := kubeadmconstants.EtcdSupportedVersion(kubernetesVersion)
|
||||
if err != nil {
|
||||
fmt.Printf("[upgrade/versions] WARNING: No recommended etcd for requested kubernetes version (%s)\n", kubernetesVersion)
|
||||
fmt.Printf("[upgrade/versions] WARNING: No recommended etcd for requested Kubernetes version (%s)\n", kubernetesVersion)
|
||||
return "N/A"
|
||||
}
|
||||
return etcdVersion.String()
|
||||
|
185
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/upgrade/compute_test.go
generated
vendored
185
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/upgrade/compute_test.go
generated
vendored
@ -23,13 +23,15 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/coreos/etcd/clientv3"
|
||||
"github.com/pkg/errors"
|
||||
apps "k8s.io/api/apps/v1"
|
||||
"k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
versionutil "k8s.io/apimachinery/pkg/util/version"
|
||||
clientsetfake "k8s.io/client-go/kubernetes/fake"
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
etcdutil "k8s.io/kubernetes/cmd/kubeadm/app/util/etcd"
|
||||
versionutil "k8s.io/kubernetes/pkg/util/version"
|
||||
)
|
||||
|
||||
type fakeVersionGetter struct {
|
||||
@ -89,7 +91,7 @@ func (f fakeEtcdClient) GetClusterStatus() (map[string]*clientv3.StatusResponse,
|
||||
func (f fakeEtcdClient) GetVersion() (string, error) {
|
||||
versions, _ := f.GetClusterVersions()
|
||||
if f.mismatchedVersions {
|
||||
return "", fmt.Errorf("etcd cluster contains endpoints with mismatched versions: %v", versions)
|
||||
return "", errors.Errorf("etcd cluster contains endpoints with mismatched versions: %v", versions)
|
||||
}
|
||||
return "3.1.12", nil
|
||||
}
|
||||
@ -107,6 +109,12 @@ func (f fakeEtcdClient) GetClusterVersions() (map[string]string, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (f fakeEtcdClient) Sync() error { return nil }
|
||||
|
||||
func (f fakeEtcdClient) AddMember(name string, peerAddrs string) ([]etcdutil.Member, error) {
|
||||
return []etcdutil.Member{}, nil
|
||||
}
|
||||
|
||||
func TestGetAvailableUpgrades(t *testing.T) {
|
||||
etcdClient := fakeEtcdClient{}
|
||||
tests := []struct {
|
||||
@ -116,9 +124,9 @@ func TestGetAvailableUpgrades(t *testing.T) {
|
||||
allowExperimental, allowRCs bool
|
||||
errExpected bool
|
||||
etcdClient etcdutil.ClusterInterrogator
|
||||
beforeDNSType string
|
||||
beforeDNSType kubeadmapi.DNSAddOnType
|
||||
beforeDNSVersion string
|
||||
featureGates map[string]bool
|
||||
dnsType kubeadmapi.DNSAddOnType
|
||||
}{
|
||||
{
|
||||
name: "no action needed, already up-to-date",
|
||||
@ -130,9 +138,9 @@ func TestGetAvailableUpgrades(t *testing.T) {
|
||||
stablePatchVersion: "v1.10.3",
|
||||
stableVersion: "v1.10.3",
|
||||
},
|
||||
beforeDNSType: constants.CoreDNS,
|
||||
beforeDNSType: kubeadmapi.CoreDNS,
|
||||
beforeDNSVersion: "v1.0.6",
|
||||
featureGates: make(map[string]bool),
|
||||
dnsType: kubeadmapi.CoreDNS,
|
||||
expectedUpgrades: []Upgrade{},
|
||||
allowExperimental: false,
|
||||
errExpected: false,
|
||||
@ -148,9 +156,9 @@ func TestGetAvailableUpgrades(t *testing.T) {
|
||||
stablePatchVersion: "v1.10.3",
|
||||
stableVersion: "v1.10.3",
|
||||
},
|
||||
beforeDNSType: constants.CoreDNS,
|
||||
beforeDNSType: kubeadmapi.CoreDNS,
|
||||
beforeDNSVersion: "1.0.6",
|
||||
featureGates: make(map[string]bool),
|
||||
dnsType: kubeadmapi.CoreDNS,
|
||||
expectedUpgrades: []Upgrade{
|
||||
{
|
||||
Description: "version in the v1.10 series",
|
||||
@ -160,15 +168,15 @@ func TestGetAvailableUpgrades(t *testing.T) {
|
||||
"v1.10.1": 1,
|
||||
},
|
||||
KubeadmVersion: "v1.10.2",
|
||||
DNSType: "coredns",
|
||||
DNSType: kubeadmapi.CoreDNS,
|
||||
DNSVersion: "1.0.6",
|
||||
EtcdVersion: "3.1.12",
|
||||
},
|
||||
After: ClusterState{
|
||||
KubeVersion: "v1.10.3",
|
||||
KubeadmVersion: "v1.10.3",
|
||||
DNSType: "coredns",
|
||||
DNSVersion: "1.1.3",
|
||||
DNSType: kubeadmapi.CoreDNS,
|
||||
DNSVersion: "1.2.6",
|
||||
EtcdVersion: "3.1.12",
|
||||
},
|
||||
},
|
||||
@ -187,9 +195,9 @@ func TestGetAvailableUpgrades(t *testing.T) {
|
||||
stablePatchVersion: "v1.10.3",
|
||||
stableVersion: "v1.10.3",
|
||||
}, ""),
|
||||
beforeDNSType: constants.CoreDNS,
|
||||
beforeDNSType: kubeadmapi.CoreDNS,
|
||||
beforeDNSVersion: "1.0.6",
|
||||
featureGates: make(map[string]bool),
|
||||
dnsType: kubeadmapi.CoreDNS,
|
||||
expectedUpgrades: []Upgrade{
|
||||
{
|
||||
Description: "version in the v1.10 series",
|
||||
@ -199,15 +207,15 @@ func TestGetAvailableUpgrades(t *testing.T) {
|
||||
"v1.10.1": 1,
|
||||
},
|
||||
KubeadmVersion: "v1.10.2",
|
||||
DNSType: "coredns",
|
||||
DNSType: kubeadmapi.CoreDNS,
|
||||
DNSVersion: "1.0.6",
|
||||
EtcdVersion: "3.1.12",
|
||||
},
|
||||
After: ClusterState{
|
||||
KubeVersion: "v1.10.3",
|
||||
KubeadmVersion: "v1.10.3",
|
||||
DNSType: "coredns",
|
||||
DNSVersion: "1.1.3",
|
||||
DNSType: kubeadmapi.CoreDNS,
|
||||
DNSVersion: "1.2.6",
|
||||
EtcdVersion: "3.1.12",
|
||||
},
|
||||
},
|
||||
@ -226,9 +234,9 @@ func TestGetAvailableUpgrades(t *testing.T) {
|
||||
stablePatchVersion: "v1.10.1",
|
||||
stableVersion: "v1.11.0",
|
||||
},
|
||||
beforeDNSType: constants.CoreDNS,
|
||||
beforeDNSType: kubeadmapi.CoreDNS,
|
||||
beforeDNSVersion: "1.0.6",
|
||||
featureGates: make(map[string]bool),
|
||||
dnsType: kubeadmapi.CoreDNS,
|
||||
expectedUpgrades: []Upgrade{
|
||||
{
|
||||
Description: "stable version",
|
||||
@ -238,15 +246,15 @@ func TestGetAvailableUpgrades(t *testing.T) {
|
||||
"v1.10.1": 1,
|
||||
},
|
||||
KubeadmVersion: "v1.11.0",
|
||||
DNSType: "coredns",
|
||||
DNSType: kubeadmapi.CoreDNS,
|
||||
DNSVersion: "1.0.6",
|
||||
EtcdVersion: "3.1.12",
|
||||
},
|
||||
After: ClusterState{
|
||||
KubeVersion: "v1.11.0",
|
||||
KubeadmVersion: "v1.11.0",
|
||||
DNSType: "coredns",
|
||||
DNSVersion: "1.1.3",
|
||||
DNSType: kubeadmapi.CoreDNS,
|
||||
DNSVersion: "1.2.6",
|
||||
EtcdVersion: "3.2.18",
|
||||
},
|
||||
},
|
||||
@ -265,9 +273,9 @@ func TestGetAvailableUpgrades(t *testing.T) {
|
||||
stablePatchVersion: "v1.10.5",
|
||||
stableVersion: "v1.11.1",
|
||||
},
|
||||
beforeDNSType: constants.CoreDNS,
|
||||
beforeDNSType: kubeadmapi.CoreDNS,
|
||||
beforeDNSVersion: "1.0.6",
|
||||
featureGates: make(map[string]bool),
|
||||
dnsType: kubeadmapi.CoreDNS,
|
||||
expectedUpgrades: []Upgrade{
|
||||
{
|
||||
Description: "version in the v1.10 series",
|
||||
@ -277,15 +285,15 @@ func TestGetAvailableUpgrades(t *testing.T) {
|
||||
"v1.10.3": 1,
|
||||
},
|
||||
KubeadmVersion: "v1.10.5",
|
||||
DNSType: "coredns",
|
||||
DNSType: kubeadmapi.CoreDNS,
|
||||
DNSVersion: "1.0.6",
|
||||
EtcdVersion: "3.1.12",
|
||||
},
|
||||
After: ClusterState{
|
||||
KubeVersion: "v1.10.5",
|
||||
KubeadmVersion: "v1.10.5", // Note: The kubeadm version mustn't be "downgraded" here
|
||||
DNSType: "coredns",
|
||||
DNSVersion: "1.1.3",
|
||||
DNSType: kubeadmapi.CoreDNS,
|
||||
DNSVersion: "1.2.6",
|
||||
EtcdVersion: "3.1.12",
|
||||
},
|
||||
},
|
||||
@ -297,15 +305,15 @@ func TestGetAvailableUpgrades(t *testing.T) {
|
||||
"v1.10.3": 1,
|
||||
},
|
||||
KubeadmVersion: "v1.10.5",
|
||||
DNSType: "coredns",
|
||||
DNSType: kubeadmapi.CoreDNS,
|
||||
DNSVersion: "1.0.6",
|
||||
EtcdVersion: "3.1.12",
|
||||
},
|
||||
After: ClusterState{
|
||||
KubeVersion: "v1.11.1",
|
||||
KubeadmVersion: "v1.11.1",
|
||||
DNSType: "coredns",
|
||||
DNSVersion: "1.1.3",
|
||||
DNSType: kubeadmapi.CoreDNS,
|
||||
DNSVersion: "1.2.6",
|
||||
EtcdVersion: "3.2.18",
|
||||
},
|
||||
},
|
||||
@ -325,9 +333,9 @@ func TestGetAvailableUpgrades(t *testing.T) {
|
||||
stableVersion: "v1.10.5",
|
||||
latestVersion: "v1.11.0-alpha.2",
|
||||
},
|
||||
beforeDNSType: constants.CoreDNS,
|
||||
beforeDNSType: kubeadmapi.CoreDNS,
|
||||
beforeDNSVersion: "v1.0.6",
|
||||
featureGates: make(map[string]bool),
|
||||
dnsType: kubeadmapi.CoreDNS,
|
||||
expectedUpgrades: []Upgrade{},
|
||||
allowExperimental: true,
|
||||
errExpected: false,
|
||||
@ -344,9 +352,9 @@ func TestGetAvailableUpgrades(t *testing.T) {
|
||||
stableVersion: "v1.10.5",
|
||||
latestVersion: "v1.11.0-alpha.2",
|
||||
},
|
||||
beforeDNSType: constants.CoreDNS,
|
||||
beforeDNSType: kubeadmapi.CoreDNS,
|
||||
beforeDNSVersion: "1.0.6",
|
||||
featureGates: make(map[string]bool),
|
||||
dnsType: kubeadmapi.CoreDNS,
|
||||
expectedUpgrades: []Upgrade{
|
||||
{
|
||||
Description: "experimental version",
|
||||
@ -356,15 +364,15 @@ func TestGetAvailableUpgrades(t *testing.T) {
|
||||
"v1.10.5": 1,
|
||||
},
|
||||
KubeadmVersion: "v1.10.5",
|
||||
DNSType: "coredns",
|
||||
DNSType: kubeadmapi.CoreDNS,
|
||||
DNSVersion: "1.0.6",
|
||||
EtcdVersion: "3.1.12",
|
||||
},
|
||||
After: ClusterState{
|
||||
KubeVersion: "v1.11.0-alpha.2",
|
||||
KubeadmVersion: "v1.11.0-alpha.2",
|
||||
DNSType: "coredns",
|
||||
DNSVersion: "1.1.3",
|
||||
DNSType: kubeadmapi.CoreDNS,
|
||||
DNSVersion: "1.2.6",
|
||||
EtcdVersion: "3.2.18",
|
||||
},
|
||||
},
|
||||
@ -384,9 +392,9 @@ func TestGetAvailableUpgrades(t *testing.T) {
|
||||
stableVersion: "v1.10.5",
|
||||
latestVersion: "v1.11.0-alpha.2",
|
||||
},
|
||||
beforeDNSType: constants.CoreDNS,
|
||||
beforeDNSType: kubeadmapi.CoreDNS,
|
||||
beforeDNSVersion: "1.0.6",
|
||||
featureGates: make(map[string]bool),
|
||||
dnsType: kubeadmapi.CoreDNS,
|
||||
expectedUpgrades: []Upgrade{
|
||||
{
|
||||
Description: "experimental version",
|
||||
@ -396,15 +404,15 @@ func TestGetAvailableUpgrades(t *testing.T) {
|
||||
"v1.10.5": 1,
|
||||
},
|
||||
KubeadmVersion: "v1.10.5",
|
||||
DNSType: "coredns",
|
||||
DNSType: kubeadmapi.CoreDNS,
|
||||
DNSVersion: "1.0.6",
|
||||
EtcdVersion: "3.1.12",
|
||||
},
|
||||
After: ClusterState{
|
||||
KubeVersion: "v1.11.0-alpha.2",
|
||||
KubeadmVersion: "v1.11.0-alpha.2",
|
||||
DNSType: "coredns",
|
||||
DNSVersion: "1.1.3",
|
||||
DNSType: kubeadmapi.CoreDNS,
|
||||
DNSVersion: "1.2.6",
|
||||
EtcdVersion: "3.2.18",
|
||||
},
|
||||
},
|
||||
@ -425,9 +433,9 @@ func TestGetAvailableUpgrades(t *testing.T) {
|
||||
latestDevBranchVersion: "v1.11.0-beta.1",
|
||||
latestVersion: "v1.12.0-alpha.0",
|
||||
},
|
||||
beforeDNSType: constants.CoreDNS,
|
||||
beforeDNSType: kubeadmapi.CoreDNS,
|
||||
beforeDNSVersion: "1.0.6",
|
||||
featureGates: make(map[string]bool),
|
||||
dnsType: kubeadmapi.CoreDNS,
|
||||
expectedUpgrades: []Upgrade{
|
||||
{
|
||||
Description: "experimental version",
|
||||
@ -437,15 +445,15 @@ func TestGetAvailableUpgrades(t *testing.T) {
|
||||
"v1.10.5": 1,
|
||||
},
|
||||
KubeadmVersion: "v1.10.5",
|
||||
DNSType: "coredns",
|
||||
DNSType: kubeadmapi.CoreDNS,
|
||||
DNSVersion: "1.0.6",
|
||||
EtcdVersion: "3.1.12",
|
||||
},
|
||||
After: ClusterState{
|
||||
KubeVersion: "v1.11.0-beta.1",
|
||||
KubeadmVersion: "v1.11.0-beta.1",
|
||||
DNSType: "coredns",
|
||||
DNSVersion: "1.1.3",
|
||||
DNSType: kubeadmapi.CoreDNS,
|
||||
DNSVersion: "1.2.6",
|
||||
EtcdVersion: "3.2.18",
|
||||
},
|
||||
},
|
||||
@ -466,9 +474,9 @@ func TestGetAvailableUpgrades(t *testing.T) {
|
||||
latestDevBranchVersion: "v1.11.0-rc.1",
|
||||
latestVersion: "v1.12.0-alpha.1",
|
||||
},
|
||||
beforeDNSType: constants.CoreDNS,
|
||||
beforeDNSType: kubeadmapi.CoreDNS,
|
||||
beforeDNSVersion: "1.0.6",
|
||||
featureGates: make(map[string]bool),
|
||||
dnsType: kubeadmapi.CoreDNS,
|
||||
expectedUpgrades: []Upgrade{
|
||||
{
|
||||
Description: "release candidate version",
|
||||
@ -478,15 +486,15 @@ func TestGetAvailableUpgrades(t *testing.T) {
|
||||
"v1.10.5": 1,
|
||||
},
|
||||
KubeadmVersion: "v1.10.5",
|
||||
DNSType: "coredns",
|
||||
DNSType: kubeadmapi.CoreDNS,
|
||||
DNSVersion: "1.0.6",
|
||||
EtcdVersion: "3.1.12",
|
||||
},
|
||||
After: ClusterState{
|
||||
KubeVersion: "v1.11.0-rc.1",
|
||||
KubeadmVersion: "v1.11.0-rc.1",
|
||||
DNSType: "coredns",
|
||||
DNSVersion: "1.1.3",
|
||||
DNSType: kubeadmapi.CoreDNS,
|
||||
DNSVersion: "1.2.6",
|
||||
EtcdVersion: "3.2.18",
|
||||
},
|
||||
},
|
||||
@ -507,9 +515,9 @@ func TestGetAvailableUpgrades(t *testing.T) {
|
||||
latestDevBranchVersion: "v1.11.6-rc.1",
|
||||
latestVersion: "v1.12.1-alpha.0",
|
||||
},
|
||||
beforeDNSType: constants.CoreDNS,
|
||||
beforeDNSType: kubeadmapi.CoreDNS,
|
||||
beforeDNSVersion: "1.0.6",
|
||||
featureGates: make(map[string]bool),
|
||||
dnsType: kubeadmapi.CoreDNS,
|
||||
expectedUpgrades: []Upgrade{
|
||||
{
|
||||
Description: "experimental version", // Note that this is considered an experimental version in this uncommon scenario
|
||||
@ -519,15 +527,15 @@ func TestGetAvailableUpgrades(t *testing.T) {
|
||||
"v1.10.5": 1,
|
||||
},
|
||||
KubeadmVersion: "v1.10.5",
|
||||
DNSType: "coredns",
|
||||
DNSType: kubeadmapi.CoreDNS,
|
||||
DNSVersion: "1.0.6",
|
||||
EtcdVersion: "3.1.12",
|
||||
},
|
||||
After: ClusterState{
|
||||
KubeVersion: "v1.11.6-rc.1",
|
||||
KubeadmVersion: "v1.11.6-rc.1",
|
||||
DNSType: "coredns",
|
||||
DNSVersion: "1.1.3",
|
||||
DNSType: kubeadmapi.CoreDNS,
|
||||
DNSVersion: "1.2.6",
|
||||
EtcdVersion: "3.2.18",
|
||||
},
|
||||
},
|
||||
@ -548,9 +556,9 @@ func TestGetAvailableUpgrades(t *testing.T) {
|
||||
latestDevBranchVersion: "v1.11.0-rc.1",
|
||||
latestVersion: "v1.12.0-alpha.2",
|
||||
},
|
||||
beforeDNSType: constants.CoreDNS,
|
||||
beforeDNSType: kubeadmapi.CoreDNS,
|
||||
beforeDNSVersion: "1.0.6",
|
||||
featureGates: make(map[string]bool),
|
||||
dnsType: kubeadmapi.CoreDNS,
|
||||
expectedUpgrades: []Upgrade{
|
||||
{
|
||||
Description: "release candidate version",
|
||||
@ -560,15 +568,15 @@ func TestGetAvailableUpgrades(t *testing.T) {
|
||||
"v1.10.5": 1,
|
||||
},
|
||||
KubeadmVersion: "v1.10.5",
|
||||
DNSType: "coredns",
|
||||
DNSType: kubeadmapi.CoreDNS,
|
||||
DNSVersion: "1.0.6",
|
||||
EtcdVersion: "3.1.12",
|
||||
},
|
||||
After: ClusterState{
|
||||
KubeVersion: "v1.11.0-rc.1",
|
||||
KubeadmVersion: "v1.11.0-rc.1",
|
||||
DNSType: "coredns",
|
||||
DNSVersion: "1.1.3",
|
||||
DNSType: kubeadmapi.CoreDNS,
|
||||
DNSVersion: "1.2.6",
|
||||
EtcdVersion: "3.2.18",
|
||||
},
|
||||
},
|
||||
@ -580,16 +588,16 @@ func TestGetAvailableUpgrades(t *testing.T) {
|
||||
"v1.10.5": 1,
|
||||
},
|
||||
KubeadmVersion: "v1.10.5",
|
||||
DNSType: "coredns",
|
||||
DNSType: kubeadmapi.CoreDNS,
|
||||
DNSVersion: "1.0.6",
|
||||
EtcdVersion: "3.1.12",
|
||||
},
|
||||
After: ClusterState{
|
||||
KubeVersion: "v1.12.0-alpha.2",
|
||||
KubeadmVersion: "v1.12.0-alpha.2",
|
||||
DNSType: "coredns",
|
||||
DNSVersion: "1.1.3",
|
||||
EtcdVersion: "3.2.18",
|
||||
DNSType: kubeadmapi.CoreDNS,
|
||||
DNSVersion: "1.2.6",
|
||||
EtcdVersion: "3.2.24",
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -621,9 +629,9 @@ func TestGetAvailableUpgrades(t *testing.T) {
|
||||
kubeadmVersion: "v1.11.1",
|
||||
}, "v1.12.1"),
|
||||
etcdClient: etcdClient,
|
||||
beforeDNSType: constants.CoreDNS,
|
||||
beforeDNSType: kubeadmapi.CoreDNS,
|
||||
beforeDNSVersion: "1.0.6",
|
||||
featureGates: make(map[string]bool),
|
||||
dnsType: kubeadmapi.CoreDNS,
|
||||
expectedUpgrades: []Upgrade{
|
||||
{
|
||||
Description: "version in the v1.11 series",
|
||||
@ -633,16 +641,16 @@ func TestGetAvailableUpgrades(t *testing.T) {
|
||||
"v1.11.0": 1,
|
||||
},
|
||||
KubeadmVersion: "v1.11.1",
|
||||
DNSType: "coredns",
|
||||
DNSType: kubeadmapi.CoreDNS,
|
||||
DNSVersion: "1.0.6",
|
||||
EtcdVersion: "3.1.12",
|
||||
},
|
||||
After: ClusterState{
|
||||
KubeVersion: "v1.12.1",
|
||||
KubeadmVersion: "v1.12.1",
|
||||
DNSType: "coredns",
|
||||
DNSVersion: "1.1.3",
|
||||
EtcdVersion: "3.2.18",
|
||||
DNSType: kubeadmapi.CoreDNS,
|
||||
DNSVersion: "1.2.6",
|
||||
EtcdVersion: "3.2.24",
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -658,9 +666,9 @@ func TestGetAvailableUpgrades(t *testing.T) {
|
||||
stableVersion: "v1.12.0",
|
||||
},
|
||||
etcdClient: etcdClient,
|
||||
beforeDNSType: constants.KubeDNS,
|
||||
beforeDNSType: kubeadmapi.KubeDNS,
|
||||
beforeDNSVersion: "1.14.7",
|
||||
featureGates: make(map[string]bool),
|
||||
dnsType: kubeadmapi.CoreDNS,
|
||||
expectedUpgrades: []Upgrade{
|
||||
{
|
||||
Description: "version in the v1.11 series",
|
||||
@ -670,16 +678,16 @@ func TestGetAvailableUpgrades(t *testing.T) {
|
||||
"v1.11.2": 1,
|
||||
},
|
||||
KubeadmVersion: "v1.12.0",
|
||||
DNSType: "kube-dns",
|
||||
DNSType: kubeadmapi.KubeDNS,
|
||||
DNSVersion: "1.14.7",
|
||||
EtcdVersion: "3.1.12",
|
||||
},
|
||||
After: ClusterState{
|
||||
KubeVersion: "v1.12.0",
|
||||
KubeadmVersion: "v1.12.0",
|
||||
DNSType: "coredns",
|
||||
DNSVersion: "1.1.3",
|
||||
EtcdVersion: "3.2.18",
|
||||
DNSType: kubeadmapi.CoreDNS,
|
||||
DNSVersion: "1.2.6",
|
||||
EtcdVersion: "3.2.24",
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -695,9 +703,9 @@ func TestGetAvailableUpgrades(t *testing.T) {
|
||||
stableVersion: "v1.12.0",
|
||||
},
|
||||
etcdClient: etcdClient,
|
||||
beforeDNSType: constants.KubeDNS,
|
||||
beforeDNSType: kubeadmapi.KubeDNS,
|
||||
beforeDNSVersion: "1.14.7",
|
||||
featureGates: map[string]bool{"CoreDNS": false},
|
||||
dnsType: kubeadmapi.KubeDNS,
|
||||
expectedUpgrades: []Upgrade{
|
||||
{
|
||||
Description: "version in the v1.11 series",
|
||||
@ -707,16 +715,16 @@ func TestGetAvailableUpgrades(t *testing.T) {
|
||||
"v1.11.2": 1,
|
||||
},
|
||||
KubeadmVersion: "v1.12.0",
|
||||
DNSType: "kube-dns",
|
||||
DNSType: kubeadmapi.KubeDNS,
|
||||
DNSVersion: "1.14.7",
|
||||
EtcdVersion: "3.1.12",
|
||||
},
|
||||
After: ClusterState{
|
||||
KubeVersion: "v1.12.0",
|
||||
KubeadmVersion: "v1.12.0",
|
||||
DNSType: "kube-dns",
|
||||
DNSVersion: "1.14.10",
|
||||
EtcdVersion: "3.2.18",
|
||||
DNSType: kubeadmapi.KubeDNS,
|
||||
DNSVersion: "1.14.13",
|
||||
EtcdVersion: "3.2.24",
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -724,17 +732,22 @@ func TestGetAvailableUpgrades(t *testing.T) {
|
||||
}
|
||||
|
||||
// Instantiating a fake etcd cluster for being able to get etcd version for a corresponding
|
||||
// kubernetes release.
|
||||
// Kubernetes release.
|
||||
for _, rt := range tests {
|
||||
t.Run(rt.name, func(t *testing.T) {
|
||||
|
||||
dnsName := constants.CoreDNSDeploymentName
|
||||
if rt.beforeDNSType == kubeadmapi.KubeDNS {
|
||||
dnsName = constants.KubeDNSDeploymentName
|
||||
}
|
||||
|
||||
client := clientsetfake.NewSimpleClientset(&apps.Deployment{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "Deployment",
|
||||
APIVersion: "apps/v1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: rt.beforeDNSType,
|
||||
Name: dnsName,
|
||||
Namespace: "kube-system",
|
||||
Labels: map[string]string{
|
||||
"k8s-app": "kube-dns",
|
||||
@ -753,7 +766,7 @@ func TestGetAvailableUpgrades(t *testing.T) {
|
||||
},
|
||||
})
|
||||
|
||||
actualUpgrades, actualErr := GetAvailableUpgrades(rt.vg, rt.allowExperimental, rt.allowRCs, rt.etcdClient, rt.featureGates, client)
|
||||
actualUpgrades, actualErr := GetAvailableUpgrades(rt.vg, rt.allowExperimental, rt.allowRCs, rt.etcdClient, rt.dnsType, client)
|
||||
if !reflect.DeepEqual(actualUpgrades, rt.expectedUpgrades) {
|
||||
t.Errorf("failed TestGetAvailableUpgrades\n\texpected upgrades: %v\n\tgot: %v", rt.expectedUpgrades, actualUpgrades)
|
||||
}
|
||||
|
57
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/upgrade/health.go
generated
vendored
57
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/upgrade/health.go
generated
vendored
@ -21,6 +21,8 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
apps "k8s.io/api/apps/v1"
|
||||
"k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@ -74,20 +76,11 @@ func CheckClusterHealth(client clientset.Interface, ignoreChecksErrors sets.Stri
|
||||
// TODO: Add a check for ComponentStatuses here?
|
||||
}
|
||||
|
||||
// Run slightly different health checks depending on control plane hosting type
|
||||
if IsControlPlaneSelfHosted(client) {
|
||||
healthChecks = append(healthChecks, &healthCheck{
|
||||
name: "ControlPlaneHealth",
|
||||
client: client,
|
||||
f: controlPlaneHealth,
|
||||
})
|
||||
} else {
|
||||
healthChecks = append(healthChecks, &healthCheck{
|
||||
name: "StaticPodManifest",
|
||||
client: client,
|
||||
f: staticPodManifestHealth,
|
||||
})
|
||||
}
|
||||
healthChecks = append(healthChecks, &healthCheck{
|
||||
name: "StaticPodManifest",
|
||||
client: client,
|
||||
f: staticPodManifestHealth,
|
||||
})
|
||||
|
||||
return preflight.RunChecks(healthChecks, os.Stderr, ignoreChecksErrors)
|
||||
}
|
||||
@ -102,7 +95,7 @@ func apiServerHealthy(client clientset.Interface) error {
|
||||
}
|
||||
client.Discovery().RESTClient().Get().AbsPath("/healthz").Do().StatusCode(&healthStatus)
|
||||
if healthStatus != http.StatusOK {
|
||||
return fmt.Errorf("the API Server is unhealthy; /healthz didn't return %q", "ok")
|
||||
return errors.Errorf("the API Server is unhealthy; /healthz didn't return %q", "ok")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -116,29 +109,16 @@ func masterNodesReady(client clientset.Interface) error {
|
||||
LabelSelector: selector.String(),
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("couldn't list masters in cluster: %v", err)
|
||||
return errors.Wrap(err, "couldn't list masters in cluster")
|
||||
}
|
||||
|
||||
if len(masters.Items) == 0 {
|
||||
return fmt.Errorf("failed to find any nodes with master role")
|
||||
return errors.New("failed to find any nodes with master role")
|
||||
}
|
||||
|
||||
notReadyMasters := getNotReadyNodes(masters.Items)
|
||||
if len(notReadyMasters) != 0 {
|
||||
return fmt.Errorf("there are NotReady masters in the cluster: %v", notReadyMasters)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// controlPlaneHealth ensures all control plane DaemonSets are healthy
|
||||
func controlPlaneHealth(client clientset.Interface) error {
|
||||
notReadyDaemonSets, err := getNotReadyDaemonSets(client)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(notReadyDaemonSets) != 0 {
|
||||
return fmt.Errorf("there are control plane DaemonSets in the cluster that are not ready: %v", notReadyDaemonSets)
|
||||
return errors.Errorf("there are NotReady masters in the cluster: %v", notReadyMasters)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -155,7 +135,7 @@ func staticPodManifestHealth(_ clientset.Interface) error {
|
||||
if len(nonExistentManifests) == 0 {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("The control plane seems to be Static Pod-hosted, but some of the manifests don't seem to exist on disk. This probably means you're running 'kubeadm upgrade' on a remote machine, which is not supported for a Static Pod-hosted cluster. Manifest files not found: %v", nonExistentManifests)
|
||||
return errors.Errorf("The control plane seems to be Static Pod-hosted, but some of the manifests don't seem to exist on disk. This probably means you're running 'kubeadm upgrade' on a remote machine, which is not supported for a Static Pod-hosted cluster. Manifest files not found: %v", nonExistentManifests)
|
||||
}
|
||||
|
||||
// IsControlPlaneSelfHosted returns whether the control plane is self hosted or not
|
||||
@ -165,7 +145,7 @@ func IsControlPlaneSelfHosted(client clientset.Interface) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// If there are no NotReady DaemonSets, we are using self-hosting
|
||||
// If there are no NotReady DaemonSets, we are using selfhosting
|
||||
return len(notReadyDaemonSets) == 0
|
||||
}
|
||||
|
||||
@ -176,11 +156,11 @@ func getNotReadyDaemonSets(client clientset.Interface) ([]error, error) {
|
||||
dsName := constants.AddSelfHostedPrefix(component)
|
||||
ds, err := client.AppsV1().DaemonSets(metav1.NamespaceSystem).Get(dsName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't get daemonset %q in the %s namespace", dsName, metav1.NamespaceSystem)
|
||||
return nil, errors.Errorf("couldn't get daemonset %q in the %s namespace", dsName, metav1.NamespaceSystem)
|
||||
}
|
||||
|
||||
if err := daemonSetHealth(&ds.Status); err != nil {
|
||||
notReadyDaemonSets = append(notReadyDaemonSets, fmt.Errorf("DaemonSet %q not healthy: %v", dsName, err))
|
||||
notReadyDaemonSets = append(notReadyDaemonSets, errors.Wrapf(err, "DaemonSet %q not healthy", dsName))
|
||||
}
|
||||
}
|
||||
return notReadyDaemonSets, nil
|
||||
@ -189,13 +169,14 @@ func getNotReadyDaemonSets(client clientset.Interface) ([]error, error) {
|
||||
// daemonSetHealth is a helper function for getting the health of a DaemonSet's status
|
||||
func daemonSetHealth(dsStatus *apps.DaemonSetStatus) error {
|
||||
if dsStatus.CurrentNumberScheduled != dsStatus.DesiredNumberScheduled {
|
||||
return fmt.Errorf("current number of scheduled Pods ('%d') doesn't match the amount of desired Pods ('%d')", dsStatus.CurrentNumberScheduled, dsStatus.DesiredNumberScheduled)
|
||||
return errors.Errorf("current number of scheduled Pods ('%d') doesn't match the amount of desired Pods ('%d')",
|
||||
dsStatus.CurrentNumberScheduled, dsStatus.DesiredNumberScheduled)
|
||||
}
|
||||
if dsStatus.NumberAvailable == 0 {
|
||||
return fmt.Errorf("no available Pods for DaemonSet")
|
||||
return errors.New("no available Pods for DaemonSet")
|
||||
}
|
||||
if dsStatus.NumberReady == 0 {
|
||||
return fmt.Errorf("no ready Pods for DaemonSet")
|
||||
return errors.New("no ready Pods for DaemonSet")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
29
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/upgrade/policy.go
generated
vendored
29
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/upgrade/policy.go
generated
vendored
@ -17,11 +17,12 @@ limitations under the License.
|
||||
package upgrade
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/version"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
"k8s.io/kubernetes/pkg/util/version"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -52,32 +53,32 @@ func EnforceVersionPolicies(versionGetter VersionGetter, newK8sVersionStr string
|
||||
clusterVersionStr, clusterVersion, err := versionGetter.ClusterVersion()
|
||||
if err != nil {
|
||||
// This case can't be forced: kubeadm has to be able to lookup cluster version for upgrades to work
|
||||
skewErrors.Mandatory = append(skewErrors.Mandatory, fmt.Errorf("Unable to fetch cluster version: %v", err))
|
||||
skewErrors.Mandatory = append(skewErrors.Mandatory, errors.Wrap(err, "Unable to fetch cluster version"))
|
||||
return skewErrors
|
||||
}
|
||||
|
||||
kubeadmVersionStr, kubeadmVersion, err := versionGetter.KubeadmVersion()
|
||||
if err != nil {
|
||||
// This case can't be forced: kubeadm has to be able to lookup its version for upgrades to work
|
||||
skewErrors.Mandatory = append(skewErrors.Mandatory, fmt.Errorf("Unable to fetch kubeadm version: %v", err))
|
||||
skewErrors.Mandatory = append(skewErrors.Mandatory, errors.Wrap(err, "Unable to fetch kubeadm version"))
|
||||
return skewErrors
|
||||
}
|
||||
|
||||
kubeletVersions, err := versionGetter.KubeletVersions()
|
||||
if err != nil {
|
||||
// This is a non-critical error; continue although kubeadm couldn't look this up
|
||||
skewErrors.Skippable = append(skewErrors.Skippable, fmt.Errorf("Unable to fetch kubelet version: %v", err))
|
||||
skewErrors.Skippable = append(skewErrors.Skippable, errors.Wrap(err, "Unable to fetch kubelet version"))
|
||||
}
|
||||
|
||||
// Make sure the new version is a supported version (higher than the minimum one supported)
|
||||
if constants.MinimumControlPlaneVersion.AtLeast(newK8sVersion) {
|
||||
// This must not happen, kubeadm always supports a minimum version; and we can't go below that
|
||||
skewErrors.Mandatory = append(skewErrors.Mandatory, fmt.Errorf("Specified version to upgrade to %q is equal to or lower than the minimum supported version %q. Please specify a higher version to upgrade to", newK8sVersionStr, clusterVersionStr))
|
||||
skewErrors.Mandatory = append(skewErrors.Mandatory, errors.Errorf("Specified version to upgrade to %q is equal to or lower than the minimum supported version %q. Please specify a higher version to upgrade to", newK8sVersionStr, clusterVersionStr))
|
||||
}
|
||||
|
||||
// kubeadm doesn't support upgrades between two minor versions; e.g. a v1.7 -> v1.9 upgrade is not supported right away
|
||||
if newK8sVersion.Minor() > clusterVersion.Minor()+MaximumAllowedMinorVersionUpgradeSkew {
|
||||
tooLargeUpgradeSkewErr := fmt.Errorf("Specified version to upgrade to %q is too high; kubeadm can upgrade only %d minor version at a time", newK8sVersionStr, MaximumAllowedMinorVersionUpgradeSkew)
|
||||
tooLargeUpgradeSkewErr := errors.Errorf("Specified version to upgrade to %q is too high; kubeadm can upgrade only %d minor version at a time", newK8sVersionStr, MaximumAllowedMinorVersionUpgradeSkew)
|
||||
// If the version that we're about to upgrade to is a released version, we should fully enforce this policy
|
||||
// If the version is a CI/dev/experimental version, it's okay to jump two minor version steps, but then require the -f flag
|
||||
if len(newK8sVersion.PreRelease()) == 0 {
|
||||
@ -89,7 +90,7 @@ func EnforceVersionPolicies(versionGetter VersionGetter, newK8sVersionStr string
|
||||
|
||||
// kubeadm doesn't support downgrades between two minor versions; e.g. a v1.9 -> v1.7 downgrade is not supported right away
|
||||
if newK8sVersion.Minor() < clusterVersion.Minor()-MaximumAllowedMinorVersionDowngradeSkew {
|
||||
tooLargeDowngradeSkewErr := fmt.Errorf("Specified version to downgrade to %q is too low; kubeadm can downgrade only %d minor version at a time", newK8sVersionStr, MaximumAllowedMinorVersionDowngradeSkew)
|
||||
tooLargeDowngradeSkewErr := errors.Errorf("Specified version to downgrade to %q is too low; kubeadm can downgrade only %d minor version at a time", newK8sVersionStr, MaximumAllowedMinorVersionDowngradeSkew)
|
||||
// If the version that we're about to downgrade to is a released version, we should fully enforce this policy
|
||||
// If the version is a CI/dev/experimental version, it's okay to jump two minor version steps, but then require the -f flag
|
||||
if len(newK8sVersion.PreRelease()) == 0 {
|
||||
@ -102,7 +103,7 @@ func EnforceVersionPolicies(versionGetter VersionGetter, newK8sVersionStr string
|
||||
// If the kubeadm version is lower than what we want to upgrade to; error
|
||||
if kubeadmVersion.LessThan(newK8sVersion) {
|
||||
if newK8sVersion.Minor() > kubeadmVersion.Minor() {
|
||||
tooLargeKubeadmSkew := fmt.Errorf("Specified version to upgrade to %q is at least one minor release higher than the kubeadm minor release (%d > %d). Such an upgrade is not supported", newK8sVersionStr, newK8sVersion.Minor(), kubeadmVersion.Minor())
|
||||
tooLargeKubeadmSkew := errors.Errorf("Specified version to upgrade to %q is at least one minor release higher than the kubeadm minor release (%d > %d). Such an upgrade is not supported", newK8sVersionStr, newK8sVersion.Minor(), kubeadmVersion.Minor())
|
||||
// This is unsupported; kubeadm has no idea how it should handle a newer minor release than itself
|
||||
// If the version is a CI/dev/experimental version though, lower the severity of this check, but then require the -f flag
|
||||
if len(newK8sVersion.PreRelease()) == 0 {
|
||||
@ -112,13 +113,13 @@ func EnforceVersionPolicies(versionGetter VersionGetter, newK8sVersionStr string
|
||||
}
|
||||
} else {
|
||||
// Upgrading to a higher patch version than kubeadm is ok if the user specifies --force. Not recommended, but possible.
|
||||
skewErrors.Skippable = append(skewErrors.Skippable, fmt.Errorf("Specified version to upgrade to %q is higher than the kubeadm version %q. Upgrade kubeadm first using the tool you used to install kubeadm", newK8sVersionStr, kubeadmVersionStr))
|
||||
skewErrors.Skippable = append(skewErrors.Skippable, errors.Errorf("Specified version to upgrade to %q is higher than the kubeadm version %q. Upgrade kubeadm first using the tool you used to install kubeadm", newK8sVersionStr, kubeadmVersionStr))
|
||||
}
|
||||
}
|
||||
|
||||
if kubeadmVersion.Major() > newK8sVersion.Major() ||
|
||||
kubeadmVersion.Minor() > newK8sVersion.Minor() {
|
||||
skewErrors.Skippable = append(skewErrors.Skippable, fmt.Errorf("Kubeadm version %s can only be used to upgrade to Kubernetes version %d.%d", kubeadmVersionStr, kubeadmVersion.Major(), kubeadmVersion.Minor()))
|
||||
skewErrors.Skippable = append(skewErrors.Skippable, errors.Errorf("Kubeadm version %s can only be used to upgrade to Kubernetes version %d.%d", kubeadmVersionStr, kubeadmVersion.Major(), kubeadmVersion.Minor()))
|
||||
}
|
||||
|
||||
// Detect if the version is unstable and the user didn't allow that
|
||||
@ -159,7 +160,7 @@ func detectUnstableVersionError(newK8sVersion *version.Version, newK8sVersionStr
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("Specified version to upgrade to %q is an unstable version and such upgrades weren't allowed via setting the --allow-*-upgrades flags", newK8sVersionStr)
|
||||
return errors.Errorf("Specified version to upgrade to %q is an unstable version and such upgrades weren't allowed via setting the --allow-*-upgrades flags", newK8sVersionStr)
|
||||
}
|
||||
|
||||
// detectTooOldKubelets errors out if the kubelet versions are so old that an unsupported skew would happen if the cluster was upgraded
|
||||
@ -169,7 +170,7 @@ func detectTooOldKubelets(newK8sVersion *version.Version, kubeletVersions map[st
|
||||
|
||||
kubeletVersion, err := version.ParseSemantic(versionStr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("couldn't parse kubelet version %s", versionStr)
|
||||
return errors.Errorf("couldn't parse kubelet version %s", versionStr)
|
||||
}
|
||||
|
||||
if newK8sVersion.Minor() > kubeletVersion.Minor()+MaximumAllowedMinorVersionKubeletSkew {
|
||||
@ -180,5 +181,5 @@ func detectTooOldKubelets(newK8sVersion *version.Version, kubeletVersions map[st
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("There are kubelets in this cluster that are too old that have these versions %v", tooOldKubeletVersions)
|
||||
return errors.Errorf("There are kubelets in this cluster that are too old that have these versions %v", tooOldKubeletVersions)
|
||||
}
|
||||
|
122
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/upgrade/policy_test.go
generated
vendored
122
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/upgrade/policy_test.go
generated
vendored
@ -19,7 +19,7 @@ package upgrade
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"k8s.io/kubernetes/pkg/util/version"
|
||||
"k8s.io/apimachinery/pkg/util/version"
|
||||
)
|
||||
|
||||
func TestEnforceVersionPolicies(t *testing.T) {
|
||||
@ -34,38 +34,38 @@ func TestEnforceVersionPolicies(t *testing.T) {
|
||||
{
|
||||
name: "minor upgrade",
|
||||
vg: &fakeVersionGetter{
|
||||
clusterVersion: "v1.10.3",
|
||||
kubeletVersion: "v1.10.3",
|
||||
kubeadmVersion: "v1.10.5",
|
||||
clusterVersion: "v1.12.3",
|
||||
kubeletVersion: "v1.12.3",
|
||||
kubeadmVersion: "v1.12.5",
|
||||
},
|
||||
newK8sVersion: "v1.10.5",
|
||||
newK8sVersion: "v1.12.5",
|
||||
},
|
||||
{
|
||||
name: "major upgrade",
|
||||
vg: &fakeVersionGetter{
|
||||
clusterVersion: "v1.10.3",
|
||||
kubeletVersion: "v1.10.2",
|
||||
kubeadmVersion: "v1.11.1",
|
||||
clusterVersion: "v1.12.3",
|
||||
kubeletVersion: "v1.12.2",
|
||||
kubeadmVersion: "v1.13.1",
|
||||
},
|
||||
newK8sVersion: "v1.11.0",
|
||||
newK8sVersion: "v1.13.0",
|
||||
},
|
||||
{
|
||||
name: "downgrade",
|
||||
vg: &fakeVersionGetter{
|
||||
clusterVersion: "v1.10.3",
|
||||
kubeletVersion: "v1.10.3",
|
||||
kubeadmVersion: "v1.10.3",
|
||||
clusterVersion: "v1.12.3",
|
||||
kubeletVersion: "v1.12.3",
|
||||
kubeadmVersion: "v1.12.3",
|
||||
},
|
||||
newK8sVersion: "v1.10.2",
|
||||
newK8sVersion: "v1.12.2",
|
||||
},
|
||||
{
|
||||
name: "same version upgrade",
|
||||
vg: &fakeVersionGetter{
|
||||
clusterVersion: "v1.10.3",
|
||||
kubeletVersion: "v1.10.3",
|
||||
kubeadmVersion: "v1.10.3",
|
||||
clusterVersion: "v1.12.3",
|
||||
kubeletVersion: "v1.12.3",
|
||||
kubeadmVersion: "v1.12.3",
|
||||
},
|
||||
newK8sVersion: "v1.10.3",
|
||||
newK8sVersion: "v1.12.3",
|
||||
},
|
||||
{
|
||||
name: "new version must be higher than v1.10.0",
|
||||
@ -81,114 +81,114 @@ func TestEnforceVersionPolicies(t *testing.T) {
|
||||
{
|
||||
name: "upgrading two minor versions in one go is not supported",
|
||||
vg: &fakeVersionGetter{
|
||||
clusterVersion: "v1.10.3",
|
||||
kubeletVersion: "v1.10.3",
|
||||
kubeadmVersion: "v1.12.0",
|
||||
clusterVersion: "v1.11.3",
|
||||
kubeletVersion: "v1.11.3",
|
||||
kubeadmVersion: "v1.13.0",
|
||||
},
|
||||
newK8sVersion: "v1.12.0",
|
||||
newK8sVersion: "v1.13.0",
|
||||
expectedMandatoryErrs: 1, // can't upgrade two minor versions
|
||||
expectedSkippableErrs: 1, // kubelet <-> apiserver skew too large
|
||||
},
|
||||
{
|
||||
name: "downgrading two minor versions in one go is not supported",
|
||||
vg: &fakeVersionGetter{
|
||||
clusterVersion: "v1.12.3",
|
||||
kubeletVersion: "v1.12.3",
|
||||
kubeadmVersion: "v1.12.0",
|
||||
clusterVersion: "v1.14.3",
|
||||
kubeletVersion: "v1.14.3",
|
||||
kubeadmVersion: "v1.14.0",
|
||||
},
|
||||
newK8sVersion: "v1.10.3",
|
||||
newK8sVersion: "v1.12.3",
|
||||
expectedMandatoryErrs: 1, // can't downgrade two minor versions
|
||||
expectedSkippableErrs: 1, // can't upgrade old k8s with newer kubeadm
|
||||
},
|
||||
{
|
||||
name: "kubeadm version must be higher than the new kube version. However, patch version skews may be forced",
|
||||
vg: &fakeVersionGetter{
|
||||
clusterVersion: "v1.10.3",
|
||||
kubeletVersion: "v1.10.3",
|
||||
kubeadmVersion: "v1.10.3",
|
||||
clusterVersion: "v1.12.3",
|
||||
kubeletVersion: "v1.12.3",
|
||||
kubeadmVersion: "v1.12.3",
|
||||
},
|
||||
newK8sVersion: "v1.10.5",
|
||||
newK8sVersion: "v1.12.5",
|
||||
expectedSkippableErrs: 1,
|
||||
},
|
||||
{
|
||||
name: "kubeadm version must be higher than the new kube version. Trying to upgrade k8s to a higher minor version than kubeadm itself should never be supported",
|
||||
vg: &fakeVersionGetter{
|
||||
clusterVersion: "v1.10.3",
|
||||
kubeletVersion: "v1.10.3",
|
||||
kubeadmVersion: "v1.10.3",
|
||||
clusterVersion: "v1.12.3",
|
||||
kubeletVersion: "v1.12.3",
|
||||
kubeadmVersion: "v1.12.3",
|
||||
},
|
||||
newK8sVersion: "v1.11.0",
|
||||
newK8sVersion: "v1.13.0",
|
||||
expectedMandatoryErrs: 1,
|
||||
},
|
||||
{
|
||||
name: "the maximum skew between the cluster version and the kubelet versions should be one minor version. This may be forced through though.",
|
||||
vg: &fakeVersionGetter{
|
||||
clusterVersion: "v1.10.3",
|
||||
kubeletVersion: "v1.9.8",
|
||||
kubeadmVersion: "v1.11.0",
|
||||
clusterVersion: "v1.12.3",
|
||||
kubeletVersion: "v1.11.8",
|
||||
kubeadmVersion: "v1.13.0",
|
||||
},
|
||||
newK8sVersion: "v1.11.0",
|
||||
newK8sVersion: "v1.13.0",
|
||||
expectedSkippableErrs: 1,
|
||||
},
|
||||
{
|
||||
name: "experimental upgrades supported if the flag is set",
|
||||
vg: &fakeVersionGetter{
|
||||
clusterVersion: "v1.10.3",
|
||||
kubeletVersion: "v1.10.3",
|
||||
kubeadmVersion: "v1.11.0-beta.1",
|
||||
clusterVersion: "v1.12.3",
|
||||
kubeletVersion: "v1.12.3",
|
||||
kubeadmVersion: "v1.13.0-beta.1",
|
||||
},
|
||||
newK8sVersion: "v1.11.0-beta.1",
|
||||
newK8sVersion: "v1.13.0-beta.1",
|
||||
allowExperimental: true,
|
||||
},
|
||||
{
|
||||
name: "release candidate upgrades supported if the flag is set",
|
||||
vg: &fakeVersionGetter{
|
||||
clusterVersion: "v1.10.3",
|
||||
kubeletVersion: "v1.10.3",
|
||||
kubeadmVersion: "v1.11.0-rc.1",
|
||||
clusterVersion: "v1.12.3",
|
||||
kubeletVersion: "v1.12.3",
|
||||
kubeadmVersion: "v1.13.0-rc.1",
|
||||
},
|
||||
newK8sVersion: "v1.11.0-rc.1",
|
||||
newK8sVersion: "v1.13.0-rc.1",
|
||||
allowRCs: true,
|
||||
},
|
||||
{
|
||||
name: "release candidate upgrades supported if the flag is set",
|
||||
vg: &fakeVersionGetter{
|
||||
clusterVersion: "v1.10.3",
|
||||
kubeletVersion: "v1.10.3",
|
||||
kubeadmVersion: "v1.11.0-rc.1",
|
||||
clusterVersion: "v1.12.3",
|
||||
kubeletVersion: "v1.12.3",
|
||||
kubeadmVersion: "v1.13.0-rc.1",
|
||||
},
|
||||
newK8sVersion: "v1.11.0-rc.1",
|
||||
newK8sVersion: "v1.13.0-rc.1",
|
||||
allowExperimental: true,
|
||||
},
|
||||
{
|
||||
name: "the user should not be able to upgrade to an experimental version if they haven't opted into that",
|
||||
vg: &fakeVersionGetter{
|
||||
clusterVersion: "v1.10.3",
|
||||
kubeletVersion: "v1.10.3",
|
||||
kubeadmVersion: "v1.11.0-beta.1",
|
||||
clusterVersion: "v1.12.3",
|
||||
kubeletVersion: "v1.12.3",
|
||||
kubeadmVersion: "v1.13.0-beta.1",
|
||||
},
|
||||
newK8sVersion: "v1.11.0-beta.1",
|
||||
newK8sVersion: "v1.13.0-beta.1",
|
||||
allowRCs: true,
|
||||
expectedSkippableErrs: 1,
|
||||
},
|
||||
{
|
||||
name: "the user should not be able to upgrade to an release candidate version if they haven't opted into that",
|
||||
vg: &fakeVersionGetter{
|
||||
clusterVersion: "v1.10.3",
|
||||
kubeletVersion: "v1.10.3",
|
||||
kubeadmVersion: "v1.11.0-rc.1",
|
||||
clusterVersion: "v1.12.3",
|
||||
kubeletVersion: "v1.12.3",
|
||||
kubeadmVersion: "v1.13.0-rc.1",
|
||||
},
|
||||
newK8sVersion: "v1.11.0-rc.1",
|
||||
newK8sVersion: "v1.13.0-rc.1",
|
||||
expectedSkippableErrs: 1,
|
||||
},
|
||||
{
|
||||
name: "the user can't use a newer minor version of kubeadm to upgrade an older version of kubeadm",
|
||||
vg: &fakeVersionGetter{
|
||||
clusterVersion: "v1.10.3",
|
||||
kubeletVersion: "v1.10.3",
|
||||
kubeadmVersion: "v1.11.0",
|
||||
clusterVersion: "v1.12.3",
|
||||
kubeletVersion: "v1.12.3",
|
||||
kubeadmVersion: "v1.13.0",
|
||||
},
|
||||
newK8sVersion: "v1.10.6",
|
||||
newK8sVersion: "v1.12.6",
|
||||
expectedSkippableErrs: 1, // can't upgrade old k8s with newer kubeadm
|
||||
},
|
||||
}
|
||||
|
88
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/upgrade/postupgrade.go
generated
vendored
88
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/upgrade/postupgrade.go
generated
vendored
@ -23,15 +23,16 @@ import (
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
pkgerrors "github.com/pkg/errors"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/errors"
|
||||
"k8s.io/apimachinery/pkg/util/version"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
certutil "k8s.io/client-go/util/cert"
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
kubeadmapiv1alpha2 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha2"
|
||||
kubeadmapiv1beta1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta1"
|
||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/features"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/dns"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/proxy"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/phases/bootstraptoken/clusterinfo"
|
||||
@ -39,18 +40,16 @@ import (
|
||||
certsphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/certs"
|
||||
kubeletphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/kubelet"
|
||||
patchnodephase "k8s.io/kubernetes/cmd/kubeadm/app/phases/patchnode"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/phases/selfhosting"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/phases/uploadconfig"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
|
||||
dryrunutil "k8s.io/kubernetes/cmd/kubeadm/app/util/dryrun"
|
||||
"k8s.io/kubernetes/pkg/util/version"
|
||||
)
|
||||
|
||||
var expiry = 180 * 24 * time.Hour
|
||||
|
||||
// PerformPostUpgradeTasks runs nearly the same functions as 'kubeadm init' would do
|
||||
// Note that the markmaster phase is left out, not needed, and no token is created as that doesn't belong to the upgrade
|
||||
func PerformPostUpgradeTasks(client clientset.Interface, cfg *kubeadmapi.MasterConfiguration, newK8sVer *version.Version, dryRun bool) error {
|
||||
func PerformPostUpgradeTasks(client clientset.Interface, cfg *kubeadmapi.InitConfiguration, newK8sVer *version.Version, dryRun bool) error {
|
||||
errs := []error{}
|
||||
|
||||
// Upload currently used configuration to the cluster
|
||||
@ -62,7 +61,7 @@ func PerformPostUpgradeTasks(client clientset.Interface, cfg *kubeadmapi.MasterC
|
||||
|
||||
// Create the new, version-branched kubelet ComponentConfig ConfigMap
|
||||
if err := kubeletphase.CreateConfigMap(cfg, client); err != nil {
|
||||
errs = append(errs, fmt.Errorf("error creating kubelet configuration ConfigMap: %v", err))
|
||||
errs = append(errs, pkgerrors.Wrap(err, "error creating kubelet configuration ConfigMap"))
|
||||
}
|
||||
|
||||
// Write the new kubelet config down to disk and the env file if needed
|
||||
@ -70,11 +69,11 @@ func PerformPostUpgradeTasks(client clientset.Interface, cfg *kubeadmapi.MasterC
|
||||
errs = append(errs, err)
|
||||
}
|
||||
|
||||
// Annotate the node with the crisocket information, sourced either from the MasterConfiguration struct or
|
||||
// Annotate the node with the crisocket information, sourced either from the InitConfiguration struct or
|
||||
// --cri-socket.
|
||||
// TODO: In the future we want to use something more official like NodeStatus or similar for detecting this properly
|
||||
if err := patchnodephase.AnnotateCRISocket(client, cfg.NodeRegistration.Name, cfg.NodeRegistration.CRISocket); err != nil {
|
||||
errs = append(errs, fmt.Errorf("error uploading crisocket: %v", err))
|
||||
errs = append(errs, pkgerrors.Wrap(err, "error uploading crisocket"))
|
||||
}
|
||||
|
||||
// Create/update RBAC rules that makes the bootstrap tokens able to post CSRs
|
||||
@ -92,11 +91,6 @@ func PerformPostUpgradeTasks(client clientset.Interface, cfg *kubeadmapi.MasterC
|
||||
errs = append(errs, err)
|
||||
}
|
||||
|
||||
// Upgrade to a self-hosted control plane if possible
|
||||
if err := upgradeToSelfHosting(client, cfg, dryRun); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
|
||||
// TODO: Is this needed to do here? I think that updating cluster info should probably be separate from a normal upgrade
|
||||
// Create the cluster-info ConfigMap with the associated RBAC rules
|
||||
// if err := clusterinfo.CreateBootstrapConfigMapIfNotExists(client, kubeadmconstants.GetAdminKubeConfigPath()); err != nil {
|
||||
@ -108,7 +102,7 @@ func PerformPostUpgradeTasks(client clientset.Interface, cfg *kubeadmapi.MasterC
|
||||
}
|
||||
|
||||
// Rotate the kube-apiserver cert and key if needed
|
||||
if err := backupAPIServerCertIfNeeded(cfg, dryRun); err != nil {
|
||||
if err := BackupAPIServerCertIfNeeded(cfg, dryRun); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
|
||||
@ -127,14 +121,14 @@ func PerformPostUpgradeTasks(client clientset.Interface, cfg *kubeadmapi.MasterC
|
||||
return errors.NewAggregate(errs)
|
||||
}
|
||||
|
||||
func removeOldDNSDeploymentIfAnotherDNSIsUsed(cfg *kubeadmapi.MasterConfiguration, client clientset.Interface, dryRun bool) error {
|
||||
func removeOldDNSDeploymentIfAnotherDNSIsUsed(cfg *kubeadmapi.InitConfiguration, client clientset.Interface, dryRun bool) error {
|
||||
return apiclient.TryRunCommand(func() error {
|
||||
installedDeploymentName := kubeadmconstants.KubeDNS
|
||||
deploymentToDelete := kubeadmconstants.CoreDNS
|
||||
installedDeploymentName := kubeadmconstants.KubeDNSDeploymentName
|
||||
deploymentToDelete := kubeadmconstants.CoreDNSDeploymentName
|
||||
|
||||
if features.Enabled(cfg.FeatureGates, features.CoreDNS) {
|
||||
installedDeploymentName = kubeadmconstants.CoreDNS
|
||||
deploymentToDelete = kubeadmconstants.KubeDNS
|
||||
if cfg.DNS.Type == kubeadmapi.CoreDNS {
|
||||
installedDeploymentName = kubeadmconstants.CoreDNSDeploymentName
|
||||
deploymentToDelete = kubeadmconstants.KubeDNSDeploymentName
|
||||
}
|
||||
|
||||
// If we're dry-running, we don't need to wait for the new DNS addon to become ready
|
||||
@ -144,7 +138,7 @@ func removeOldDNSDeploymentIfAnotherDNSIsUsed(cfg *kubeadmapi.MasterConfiguratio
|
||||
return err
|
||||
}
|
||||
if dnsDeployment.Status.ReadyReplicas == 0 {
|
||||
return fmt.Errorf("the DNS deployment isn't ready yet")
|
||||
return pkgerrors.New("the DNS deployment isn't ready yet")
|
||||
}
|
||||
}
|
||||
|
||||
@ -158,26 +152,13 @@ func removeOldDNSDeploymentIfAnotherDNSIsUsed(cfg *kubeadmapi.MasterConfiguratio
|
||||
}, 10)
|
||||
}
|
||||
|
||||
func upgradeToSelfHosting(client clientset.Interface, cfg *kubeadmapi.MasterConfiguration, dryRun bool) error {
|
||||
if features.Enabled(cfg.FeatureGates, features.SelfHosting) && !IsControlPlaneSelfHosted(client) {
|
||||
|
||||
waiter := getWaiter(dryRun, client)
|
||||
|
||||
// kubeadm will now convert the static Pod-hosted control plane into a self-hosted one
|
||||
fmt.Println("[self-hosted] Creating self-hosted control plane.")
|
||||
if err := selfhosting.CreateSelfHostedControlPlane(kubeadmconstants.GetStaticPodDirectory(), kubeadmconstants.KubernetesDir, cfg, client, waiter, dryRun); err != nil {
|
||||
return fmt.Errorf("error creating self hosted control plane: %v", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func backupAPIServerCertIfNeeded(cfg *kubeadmapi.MasterConfiguration, dryRun bool) error {
|
||||
certAndKeyDir := kubeadmapiv1alpha2.DefaultCertificatesDir
|
||||
// BackupAPIServerCertIfNeeded rotates the kube-apiserver certificate if older than 180 days
|
||||
func BackupAPIServerCertIfNeeded(cfg *kubeadmapi.InitConfiguration, dryRun bool) error {
|
||||
certAndKeyDir := kubeadmapiv1beta1.DefaultCertificatesDir
|
||||
shouldBackup, err := shouldBackupAPIServerCertAndKey(certAndKeyDir)
|
||||
if err != nil {
|
||||
// Don't fail the upgrade phase if failing to determine to backup kube-apiserver cert and key.
|
||||
return fmt.Errorf("[postupgrade] WARNING: failed to determine to backup kube-apiserver cert and key: %v", err)
|
||||
return pkgerrors.Wrap(err, "[postupgrade] WARNING: failed to determine to backup kube-apiserver cert and key")
|
||||
}
|
||||
|
||||
if !shouldBackup {
|
||||
@ -195,10 +176,14 @@ func backupAPIServerCertIfNeeded(cfg *kubeadmapi.MasterConfiguration, dryRun boo
|
||||
if err := backupAPIServerCertAndKey(certAndKeyDir); err != nil {
|
||||
fmt.Printf("[postupgrade] WARNING: failed to backup kube-apiserver cert and key: %v", err)
|
||||
}
|
||||
return certsphase.CreateAPIServerCertAndKeyFiles(cfg)
|
||||
return certsphase.CreateCertAndKeyFilesWithCA(
|
||||
&certsphase.KubeadmCertAPIServer,
|
||||
&certsphase.KubeadmCertRootCA,
|
||||
cfg,
|
||||
)
|
||||
}
|
||||
|
||||
func writeKubeletConfigFiles(client clientset.Interface, cfg *kubeadmapi.MasterConfiguration, newK8sVer *version.Version, dryRun bool) error {
|
||||
func writeKubeletConfigFiles(client clientset.Interface, cfg *kubeadmapi.InitConfiguration, newK8sVer *version.Version, dryRun bool) error {
|
||||
kubeletDir, err := getKubeletDir(dryRun)
|
||||
if err != nil {
|
||||
// The error here should never occur in reality, would only be thrown if /tmp doesn't exist on the machine.
|
||||
@ -211,7 +196,7 @@ func writeKubeletConfigFiles(client clientset.Interface, cfg *kubeadmapi.MasterC
|
||||
// *would* post the new kubelet-config-1.X configmap that doesn't exist now when we're trying to download it
|
||||
// again.
|
||||
if !(apierrors.IsNotFound(err) && dryRun) {
|
||||
errs = append(errs, fmt.Errorf("error downloading kubelet configuration from the ConfigMap: %v", err))
|
||||
errs = append(errs, pkgerrors.Wrap(err, "error downloading kubelet configuration from the ConfigMap"))
|
||||
}
|
||||
}
|
||||
|
||||
@ -224,8 +209,8 @@ func writeKubeletConfigFiles(client clientset.Interface, cfg *kubeadmapi.MasterC
|
||||
// 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
|
||||
// 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.NodeRegistration, cfg.FeatureGates, false, kubeletDir); err != nil {
|
||||
errs = append(errs, fmt.Errorf("error writing a dynamic environment file for the kubelet: %v", err))
|
||||
if err := kubeletphase.WriteKubeletDynamicEnvFile(cfg, false, kubeletDir); err != nil {
|
||||
errs = append(errs, pkgerrors.Wrap(err, "error writing a dynamic environment file for the kubelet"))
|
||||
}
|
||||
|
||||
if dryRun { // Print what contents would be written
|
||||
@ -235,15 +220,6 @@ func writeKubeletConfigFiles(client clientset.Interface, cfg *kubeadmapi.MasterC
|
||||
return errors.NewAggregate(errs)
|
||||
}
|
||||
|
||||
// getWaiter gets the right waiter implementation for the right occasion
|
||||
// TODO: Consolidate this with what's in init.go?
|
||||
func getWaiter(dryRun bool, client clientset.Interface) apiclient.Waiter {
|
||||
if dryRun {
|
||||
return dryrunutil.NewWaiter()
|
||||
}
|
||||
return apiclient.NewKubeWaiter(client, 30*time.Minute, os.Stdout)
|
||||
}
|
||||
|
||||
// getKubeletDir gets the kubelet directory based on whether the user is dry-running this command or not.
|
||||
// TODO: Consolidate this with similar funcs?
|
||||
func getKubeletDir(dryRun bool) (string, error) {
|
||||
@ -257,7 +233,7 @@ func getKubeletDir(dryRun bool) (string, error) {
|
||||
func backupAPIServerCertAndKey(certAndKeyDir string) error {
|
||||
subDir := filepath.Join(certAndKeyDir, "expired")
|
||||
if err := os.Mkdir(subDir, 0766); err != nil {
|
||||
return fmt.Errorf("failed to created backup directory %s: %v", subDir, err)
|
||||
return pkgerrors.Wrapf(err, "failed to created backup directory %s", subDir)
|
||||
}
|
||||
|
||||
filesToMove := map[string]string{
|
||||
@ -287,7 +263,7 @@ func rollbackFiles(files map[string]string, originalErr error) error {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("couldn't move these files: %v. Got errors: %v", files, errors.NewAggregate(errs))
|
||||
return pkgerrors.Errorf("couldn't move these files: %v. Got errors: %v", files, errors.NewAggregate(errs))
|
||||
}
|
||||
|
||||
// shouldBackupAPIServerCertAndKey checks if the cert of kube-apiserver will be expired in 180 days.
|
||||
@ -295,10 +271,10 @@ func shouldBackupAPIServerCertAndKey(certAndKeyDir string) (bool, error) {
|
||||
apiServerCert := filepath.Join(certAndKeyDir, kubeadmconstants.APIServerCertName)
|
||||
certs, err := certutil.CertsFromFile(apiServerCert)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("couldn't load the certificate file %s: %v", apiServerCert, err)
|
||||
return false, pkgerrors.Wrapf(err, "couldn't load the certificate file %s", apiServerCert)
|
||||
}
|
||||
if len(certs) == 0 {
|
||||
return false, fmt.Errorf("no certificate data found")
|
||||
return false, pkgerrors.New("no certificate data found")
|
||||
}
|
||||
|
||||
if time.Now().Sub(certs[0].NotBefore) > expiry {
|
||||
|
25
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/upgrade/postupgrade_test.go
generated
vendored
25
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/upgrade/postupgrade_test.go
generated
vendored
@ -27,7 +27,6 @@ import (
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
certsphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/certs"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/pkiutil"
|
||||
testutil "k8s.io/kubernetes/cmd/kubeadm/test"
|
||||
)
|
||||
|
||||
@ -130,9 +129,11 @@ func TestRollbackFiles(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestShouldBackupAPIServerCertAndKey(t *testing.T) {
|
||||
cfg := &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadmapi.API{AdvertiseAddress: "1.2.3.4"},
|
||||
Networking: kubeadmapi.Networking{ServiceSubnet: "10.96.0.0/12", DNSDomain: "cluster.local"},
|
||||
cfg := &kubeadmapi.InitConfiguration{
|
||||
LocalAPIEndpoint: kubeadmapi.APIEndpoint{AdvertiseAddress: "1.2.3.4"},
|
||||
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
|
||||
Networking: kubeadmapi.Networking{ServiceSubnet: "10.96.0.0/12", DNSDomain: "cluster.local"},
|
||||
},
|
||||
NodeRegistration: kubeadmapi.NodeRegistrationOptions{Name: "test-node"},
|
||||
}
|
||||
|
||||
@ -148,23 +149,21 @@ func TestShouldBackupAPIServerCertAndKey(t *testing.T) {
|
||||
expected: true,
|
||||
},
|
||||
} {
|
||||
caCert, caKey, err := certsphase.NewCACertAndKey()
|
||||
tmpdir := testutil.SetupTempDir(t)
|
||||
defer os.RemoveAll(tmpdir)
|
||||
cfg.CertificatesDir = tmpdir
|
||||
|
||||
caCert, caKey, err := certsphase.KubeadmCertRootCA.CreateAsCA(cfg)
|
||||
if err != nil {
|
||||
t.Fatalf("failed creation of ca cert and key: %v", err)
|
||||
}
|
||||
caCert.NotBefore = caCert.NotBefore.Add(-test.adjustedExpiry).UTC()
|
||||
apiCert, apiKey, err := certsphase.NewAPIServerCertAndKey(cfg, caCert, caKey)
|
||||
|
||||
err = certsphase.KubeadmCertAPIServer.CreateFromCA(cfg, caCert, caKey)
|
||||
if err != nil {
|
||||
t.Fatalf("Test %s: failed creation of cert and key: %v", desc, err)
|
||||
}
|
||||
|
||||
tmpdir := testutil.SetupTempDir(t)
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
if err := pkiutil.WriteCertAndKey(tmpdir, constants.APIServerCertAndKeyBaseName, apiCert, apiKey); err != nil {
|
||||
t.Fatalf("Test %s: failure while saving %s certificate and key: %v", desc, constants.APIServerCertAndKeyBaseName, err)
|
||||
}
|
||||
|
||||
certAndKey := []string{filepath.Join(tmpdir, constants.APIServerCertName), filepath.Join(tmpdir, constants.APIServerKeyName)}
|
||||
for _, path := range certAndKey {
|
||||
if _, err := os.Stat(path); os.IsNotExist(err) {
|
||||
|
26
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/upgrade/prepull.go
generated
vendored
26
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/upgrade/prepull.go
generated
vendored
@ -20,6 +20,7 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
apps "k8s.io/api/apps/v1"
|
||||
"k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@ -44,12 +45,12 @@ type Prepuller interface {
|
||||
// DaemonSetPrepuller makes sure the control plane images are available on all masters
|
||||
type DaemonSetPrepuller struct {
|
||||
client clientset.Interface
|
||||
cfg *kubeadmapi.MasterConfiguration
|
||||
cfg *kubeadmapi.ClusterConfiguration
|
||||
waiter apiclient.Waiter
|
||||
}
|
||||
|
||||
// NewDaemonSetPrepuller creates a new instance of the DaemonSetPrepuller struct
|
||||
func NewDaemonSetPrepuller(client clientset.Interface, waiter apiclient.Waiter, cfg *kubeadmapi.MasterConfiguration) *DaemonSetPrepuller {
|
||||
func NewDaemonSetPrepuller(client clientset.Interface, waiter apiclient.Waiter, cfg *kubeadmapi.ClusterConfiguration) *DaemonSetPrepuller {
|
||||
return &DaemonSetPrepuller{
|
||||
client: client,
|
||||
cfg: cfg,
|
||||
@ -59,12 +60,17 @@ func NewDaemonSetPrepuller(client clientset.Interface, waiter apiclient.Waiter,
|
||||
|
||||
// CreateFunc creates a DaemonSet for making the image available on every relevant node
|
||||
func (d *DaemonSetPrepuller) CreateFunc(component string) error {
|
||||
image := images.GetCoreImage(component, d.cfg.GetControlPlaneImageRepository(), d.cfg.KubernetesVersion, d.cfg.UnifiedControlPlaneImage)
|
||||
var image string
|
||||
if component == constants.Etcd {
|
||||
image = images.GetEtcdImage(d.cfg)
|
||||
} else {
|
||||
image = images.GetKubernetesImage(component, d.cfg)
|
||||
}
|
||||
ds := buildPrePullDaemonSet(component, image)
|
||||
|
||||
// Create the DaemonSet in the API Server
|
||||
if err := apiclient.CreateOrUpdateDaemonSet(d.client, ds); err != nil {
|
||||
return fmt.Errorf("unable to create a DaemonSet for prepulling the component %q: %v", component, err)
|
||||
return errors.Wrapf(err, "unable to create a DaemonSet for prepulling the component %q", component)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -79,15 +85,14 @@ func (d *DaemonSetPrepuller) WaitFunc(component string) {
|
||||
func (d *DaemonSetPrepuller) DeleteFunc(component string) error {
|
||||
dsName := addPrepullPrefix(component)
|
||||
if err := apiclient.DeleteDaemonSetForeground(d.client, metav1.NamespaceSystem, dsName); err != nil {
|
||||
return fmt.Errorf("unable to cleanup the DaemonSet used for prepulling %s: %v", component, err)
|
||||
return errors.Wrapf(err, "unable to cleanup the DaemonSet used for prepulling %s", component)
|
||||
}
|
||||
fmt.Printf("[upgrade/prepull] Prepulled image for component %s.\n", component)
|
||||
return nil
|
||||
}
|
||||
|
||||
// PrepullImagesInParallel creates DaemonSets synchronously but waits in parallel for the images to pull
|
||||
func PrepullImagesInParallel(kubePrepuller Prepuller, timeout time.Duration) error {
|
||||
componentsToPrepull := append(constants.MasterComponents, constants.Etcd)
|
||||
func PrepullImagesInParallel(kubePrepuller Prepuller, timeout time.Duration, componentsToPrepull []string) error {
|
||||
fmt.Printf("[upgrade/prepull] Will prepull images for components %v\n", componentsToPrepull)
|
||||
|
||||
timeoutChan := time.After(timeout)
|
||||
@ -126,7 +131,7 @@ func waitForItemsFromChan(timeoutChan <-chan time.Time, stringChan chan string,
|
||||
for {
|
||||
select {
|
||||
case <-timeoutChan:
|
||||
return fmt.Errorf("The prepull operation timed out")
|
||||
return errors.New("The prepull operation timed out")
|
||||
case result := <-stringChan:
|
||||
i++
|
||||
// If the cleanup function errors; error here as well
|
||||
@ -154,6 +159,11 @@ func buildPrePullDaemonSet(component, image string) *apps.DaemonSet {
|
||||
Namespace: metav1.NamespaceSystem,
|
||||
},
|
||||
Spec: apps.DaemonSetSpec{
|
||||
Selector: &metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{
|
||||
"k8s-app": addPrepullPrefix(component),
|
||||
},
|
||||
},
|
||||
Template: v1.PodTemplateSpec{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: map[string]string{
|
||||
|
13
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/upgrade/prepull_test.go
generated
vendored
13
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/upgrade/prepull_test.go
generated
vendored
@ -17,10 +17,13 @@ limitations under the License.
|
||||
package upgrade
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
//"k8s.io/kubernetes/pkg/util/version"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
//"k8s.io/apimachinery/pkg/util/version"
|
||||
)
|
||||
|
||||
// failedCreatePrepuller is a fake prepuller that errors for kube-controller-manager in the CreateFunc call
|
||||
@ -32,7 +35,7 @@ func NewFailedCreatePrepuller() Prepuller {
|
||||
|
||||
func (p *failedCreatePrepuller) CreateFunc(component string) error {
|
||||
if component == "kube-controller-manager" {
|
||||
return fmt.Errorf("boo")
|
||||
return errors.New("boo")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -77,7 +80,7 @@ func (p *failedDeletePrepuller) WaitFunc(component string) {}
|
||||
|
||||
func (p *failedDeletePrepuller) DeleteFunc(component string) error {
|
||||
if component == "kube-scheduler" {
|
||||
return fmt.Errorf("boo")
|
||||
return errors.New("boo")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -133,7 +136,7 @@ func TestPrepullImagesInParallel(t *testing.T) {
|
||||
|
||||
for _, rt := range tests {
|
||||
|
||||
actualErr := PrepullImagesInParallel(rt.p, rt.timeout)
|
||||
actualErr := PrepullImagesInParallel(rt.p, rt.timeout, append(constants.MasterComponents, constants.Etcd))
|
||||
if (actualErr != nil) != rt.expectedErr {
|
||||
t.Errorf(
|
||||
"failed TestPrepullImagesInParallel\n\texpected error: %t\n\tgot: %t",
|
||||
|
272
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/upgrade/selfhosted.go
generated
vendored
272
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/upgrade/selfhosted.go
generated
vendored
@ -1,272 +0,0 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package upgrade
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
apps "k8s.io/api/apps/v1"
|
||||
"k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/phases/controlplane"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/phases/selfhosting"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
|
||||
"k8s.io/kubernetes/pkg/util/version"
|
||||
)
|
||||
|
||||
const (
|
||||
// upgradeTempDSPrefix is the prefix added to the temporary DaemonSet's name used during the upgrade
|
||||
upgradeTempDSPrefix = "temp-upgrade-"
|
||||
|
||||
// upgradeTempLabel is the label key used for identifying the temporary component's DaemonSet
|
||||
upgradeTempLabel = "temp-upgrade-component"
|
||||
|
||||
// selfHostingWaitTimeout describes the maximum amount of time a self-hosting wait process should wait before timing out
|
||||
selfHostingWaitTimeout = 2 * time.Minute
|
||||
|
||||
// selfHostingFailureThreshold describes how many times kubeadm will retry creating the DaemonSets
|
||||
selfHostingFailureThreshold int = 10
|
||||
)
|
||||
|
||||
// controlPlaneComponentResources holds the relevant Pod and DaemonSet associated with a control plane component
|
||||
type controlPlaneComponentResources struct {
|
||||
pod *v1.Pod
|
||||
daemonSet *apps.DaemonSet
|
||||
}
|
||||
|
||||
// SelfHostedControlPlane upgrades a self-hosted control plane
|
||||
// It works as follows:
|
||||
// - The client gets the currently running DaemonSets and their associated Pods used for self-hosting the control plane
|
||||
// - A temporary DaemonSet for the component in question is created; but nearly identical to the DaemonSet for the self-hosted component running right now
|
||||
// - Why use this temporary DaemonSet? Because, the RollingUpdate strategy for upgrading DaemonSets first kills the old Pod, and then adds the new one
|
||||
// - This doesn't work for self-hosted upgrades, as if you remove the only API server for instance you have in the cluster, the cluster essentially goes down
|
||||
// - So instead, a nearly identical copy of the pre-upgrade DaemonSet is created and applied to the cluster. In the beginning, this duplicate DS is just idle
|
||||
// - kubeadm waits for the temporary DaemonSet's Pod to become Running
|
||||
// - kubeadm updates the real, self-hosted component. This will result in the pre-upgrade component Pod being removed from the cluster
|
||||
// - Luckily, the temporary, backup DaemonSet now kicks in and takes over and acts as the control plane. It recognizes that a new Pod should be created,
|
||||
// - as the "real" DaemonSet is being updated.
|
||||
// - kubeadm waits for the pre-upgrade Pod to become deleted. It now takes advantage of the backup/temporary component
|
||||
// - kubeadm waits for the new, upgraded DaemonSet to become Running.
|
||||
// - Now that the new, upgraded DaemonSet is Running, we can delete the backup/temporary DaemonSet
|
||||
// - Lastly, make sure the API /healthz endpoint still is reachable
|
||||
//
|
||||
// TL;DR; This is what the flow looks like in pseudo-code:
|
||||
// for [kube-apiserver, kube-controller-manager, kube-scheduler], do:
|
||||
// 1. Self-Hosted component v1 Running
|
||||
// -> Duplicate the DaemonSet manifest
|
||||
// 2. Self-Hosted component v1 Running (active). Backup component v1 Running (passive)
|
||||
// -> Upgrade the Self-Hosted component v1 to v2.
|
||||
// -> Self-Hosted component v1 is Deleted from the cluster
|
||||
// 3. Backup component v1 Running becomes active and completes the upgrade by creating the Self-Hosted component v2 Pod (passive)
|
||||
// -> Wait for Self-Hosted component v2 to become Running
|
||||
// 4. Backup component v1 Running (active). Self-Hosted component v2 Running (passive)
|
||||
// -> Backup component v1 is Deleted
|
||||
// 5. Wait for Self-Hosted component v2 Running to become active
|
||||
// 6. Repeat for all control plane components
|
||||
func SelfHostedControlPlane(client clientset.Interface, waiter apiclient.Waiter, cfg *kubeadmapi.MasterConfiguration, k8sVersion *version.Version) error {
|
||||
|
||||
// Adjust the timeout slightly to something self-hosting specific
|
||||
waiter.SetTimeout(selfHostingWaitTimeout)
|
||||
|
||||
// This function returns a map of DaemonSet objects ready to post to the API server
|
||||
newControlPlaneDaemonSets := BuildUpgradedDaemonSetsFromConfig(cfg, k8sVersion)
|
||||
|
||||
controlPlaneResources, err := getCurrentControlPlaneComponentResources(client)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, component := range constants.MasterComponents {
|
||||
// Make a shallow copy of the current DaemonSet in order to create a new, temporary one
|
||||
tempDS := *controlPlaneResources[component].daemonSet
|
||||
|
||||
// Mutate the temp daemonset a little to be suitable for this usage (change label selectors, etc)
|
||||
mutateTempDaemonSet(&tempDS, component)
|
||||
|
||||
// Create or update the DaemonSet in the API Server, and retry selfHostingFailureThreshold times if it errors out
|
||||
if err := apiclient.TryRunCommand(func() error {
|
||||
return apiclient.CreateOrUpdateDaemonSet(client, &tempDS)
|
||||
}, selfHostingFailureThreshold); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Wait for the temporary/backup self-hosted component to come up
|
||||
if err := waiter.WaitForPodsWithLabel(buildTempUpgradeDSLabelQuery(component)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
newDS := newControlPlaneDaemonSets[component]
|
||||
|
||||
// Upgrade the component's self-hosted resource
|
||||
// During this upgrade; the temporary/backup component will take over
|
||||
if err := apiclient.TryRunCommand(func() error {
|
||||
|
||||
if _, err := client.AppsV1().DaemonSets(newDS.ObjectMeta.Namespace).Update(newDS); err != nil {
|
||||
return fmt.Errorf("couldn't update self-hosted component's DaemonSet: %v", err)
|
||||
}
|
||||
return nil
|
||||
}, selfHostingFailureThreshold); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Wait for the component's old Pod to disappear
|
||||
oldPod := controlPlaneResources[component].pod
|
||||
if err := waiter.WaitForPodToDisappear(oldPod.ObjectMeta.Name); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Wait for the main, upgraded self-hosted component to come up
|
||||
// Here we're talking to the temporary/backup component; the upgraded component is in the process of starting up
|
||||
if err := waiter.WaitForPodsWithLabel(selfhosting.BuildSelfHostedComponentLabelQuery(component)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Delete the temporary DaemonSet, and retry selfHostingFailureThreshold times if it errors out
|
||||
// In order to pivot back to the upgraded API server, we kill the temporary/backup component
|
||||
if err := apiclient.TryRunCommand(func() error {
|
||||
return apiclient.DeleteDaemonSetForeground(client, tempDS.ObjectMeta.Namespace, tempDS.ObjectMeta.Name)
|
||||
}, selfHostingFailureThreshold); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Just as an extra safety check; make sure the API server is returning ok at the /healthz endpoint
|
||||
if err := waiter.WaitForAPI(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("[upgrade/apply] Self-hosted component %q upgraded successfully!\n", component)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// BuildUpgradedDaemonSetsFromConfig takes a config object and the current version and returns the DaemonSet objects to post to the master
|
||||
func BuildUpgradedDaemonSetsFromConfig(cfg *kubeadmapi.MasterConfiguration, k8sVersion *version.Version) map[string]*apps.DaemonSet {
|
||||
// Here the map of different mutators to use for the control plane's podspec is stored
|
||||
mutators := selfhosting.GetMutatorsFromFeatureGates(cfg.FeatureGates)
|
||||
// Get the new PodSpecs to use
|
||||
controlPlanePods := controlplane.GetStaticPodSpecs(cfg, k8sVersion)
|
||||
// Store the created DaemonSets in this map
|
||||
controlPlaneDaemonSets := map[string]*apps.DaemonSet{}
|
||||
|
||||
for _, component := range constants.MasterComponents {
|
||||
podSpec := controlPlanePods[component].Spec
|
||||
|
||||
// Build the full DaemonSet object from the PodSpec generated from the control plane phase and
|
||||
// using the self-hosting mutators available from the selfhosting phase
|
||||
ds := selfhosting.BuildDaemonSet(component, &podSpec, mutators)
|
||||
controlPlaneDaemonSets[component] = ds
|
||||
}
|
||||
return controlPlaneDaemonSets
|
||||
}
|
||||
|
||||
// addTempUpgradeDSPrefix adds the upgradeTempDSPrefix to the specified DaemonSet name
|
||||
func addTempUpgradeDSPrefix(currentName string) string {
|
||||
return fmt.Sprintf("%s%s", upgradeTempDSPrefix, currentName)
|
||||
}
|
||||
|
||||
// buildTempUpgradeLabels returns the label string-string map for identifying the temporary
|
||||
func buildTempUpgradeLabels(component string) map[string]string {
|
||||
return map[string]string{
|
||||
upgradeTempLabel: component,
|
||||
}
|
||||
}
|
||||
|
||||
// buildTempUpgradeDSLabelQuery creates the right query for matching
|
||||
func buildTempUpgradeDSLabelQuery(component string) string {
|
||||
return fmt.Sprintf("%s=%s", upgradeTempLabel, component)
|
||||
}
|
||||
|
||||
// mutateTempDaemonSet mutates the specified self-hosted DaemonSet for the specified component
|
||||
// in a way that makes it possible to post a nearly identical, temporary DaemonSet as a backup
|
||||
func mutateTempDaemonSet(tempDS *apps.DaemonSet, component string) {
|
||||
// Prefix the name of the temporary DaemonSet with upgradeTempDSPrefix
|
||||
tempDS.ObjectMeta.Name = addTempUpgradeDSPrefix(tempDS.ObjectMeta.Name)
|
||||
// Set .Labels to something else than the "real" self-hosted components have
|
||||
tempDS.ObjectMeta.Labels = buildTempUpgradeLabels(component)
|
||||
tempDS.Spec.Selector.MatchLabels = buildTempUpgradeLabels(component)
|
||||
tempDS.Spec.Template.ObjectMeta.Labels = buildTempUpgradeLabels(component)
|
||||
// Clean all unnecessary ObjectMeta fields
|
||||
tempDS.ObjectMeta = extractRelevantObjectMeta(tempDS.ObjectMeta)
|
||||
// Reset .Status as we're posting a new object
|
||||
tempDS.Status = apps.DaemonSetStatus{}
|
||||
}
|
||||
|
||||
// extractRelevantObjectMeta returns only the relevant parts of ObjectMeta required when creating
|
||||
// a new, identical resource. We should not POST ResourceVersion, UUIDs, etc., only the name, labels,
|
||||
// namespace and annotations should be preserved.
|
||||
func extractRelevantObjectMeta(ob metav1.ObjectMeta) metav1.ObjectMeta {
|
||||
return metav1.ObjectMeta{
|
||||
Name: ob.Name,
|
||||
Namespace: ob.Namespace,
|
||||
Labels: ob.Labels,
|
||||
Annotations: ob.Annotations,
|
||||
}
|
||||
}
|
||||
|
||||
// listPodsWithLabelSelector returns the relevant Pods for the given LabelSelector
|
||||
func listPodsWithLabelSelector(client clientset.Interface, kvLabel string) (*v1.PodList, error) {
|
||||
return client.CoreV1().Pods(metav1.NamespaceSystem).List(metav1.ListOptions{
|
||||
LabelSelector: kvLabel,
|
||||
})
|
||||
}
|
||||
|
||||
// getCurrentControlPlaneComponentResources returns a string-(Pod|DaemonSet) map for later use
|
||||
func getCurrentControlPlaneComponentResources(client clientset.Interface) (map[string]controlPlaneComponentResources, error) {
|
||||
controlPlaneResources := map[string]controlPlaneComponentResources{}
|
||||
|
||||
for _, component := range constants.MasterComponents {
|
||||
var podList *v1.PodList
|
||||
var currentDS *apps.DaemonSet
|
||||
|
||||
// Get the self-hosted pod associated with the component
|
||||
podLabelSelector := selfhosting.BuildSelfHostedComponentLabelQuery(component)
|
||||
if err := apiclient.TryRunCommand(func() error {
|
||||
var tryrunerr error
|
||||
podList, tryrunerr = listPodsWithLabelSelector(client, podLabelSelector)
|
||||
return tryrunerr // note that tryrunerr is most likely nil here (in successful cases)
|
||||
}, selfHostingFailureThreshold); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Make sure that there are only one Pod with this label selector; otherwise unexpected things can happen
|
||||
if len(podList.Items) > 1 {
|
||||
return nil, fmt.Errorf("too many pods with label selector %q found in the %s namespace", podLabelSelector, metav1.NamespaceSystem)
|
||||
}
|
||||
|
||||
// Get the component's DaemonSet object
|
||||
dsName := constants.AddSelfHostedPrefix(component)
|
||||
if err := apiclient.TryRunCommand(func() error {
|
||||
var tryrunerr error
|
||||
// Try to get the current self-hosted component
|
||||
currentDS, tryrunerr = client.AppsV1().DaemonSets(metav1.NamespaceSystem).Get(dsName, metav1.GetOptions{})
|
||||
return tryrunerr // note that tryrunerr is most likely nil here (in successful cases)
|
||||
}, selfHostingFailureThreshold); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Add the associated resources to the map to return later
|
||||
controlPlaneResources[component] = controlPlaneComponentResources{
|
||||
pod: &podList.Items[0],
|
||||
daemonSet: currentDS,
|
||||
}
|
||||
}
|
||||
return controlPlaneResources, nil
|
||||
}
|
163
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/upgrade/staticpods.go
generated
vendored
163
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/upgrade/staticpods.go
generated
vendored
@ -22,15 +22,24 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"k8s.io/apimachinery/pkg/util/version"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
certsphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/certs"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/renewal"
|
||||
controlplanephase "k8s.io/kubernetes/cmd/kubeadm/app/phases/controlplane"
|
||||
etcdphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/etcd"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/util"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
|
||||
etcdutil "k8s.io/kubernetes/cmd/kubeadm/app/util/etcd"
|
||||
"k8s.io/kubernetes/pkg/util/version"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/util/staticpod"
|
||||
)
|
||||
|
||||
const (
|
||||
// UpgradeManifestTimeout is timeout of upgrading the static pod manifest
|
||||
UpgradeManifestTimeout = 5 * time.Minute
|
||||
)
|
||||
|
||||
// StaticPodPathManager is responsible for tracking the directories used in the static pod upgrade transition
|
||||
@ -156,7 +165,7 @@ func (spm *KubeStaticPodPathManager) CleanupDirs() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func upgradeComponent(component string, waiter apiclient.Waiter, pathMgr StaticPodPathManager, cfg *kubeadmapi.MasterConfiguration, beforePodHash string, recoverManifests map[string]string, isTLSUpgrade bool) error {
|
||||
func upgradeComponent(component string, waiter apiclient.Waiter, pathMgr StaticPodPathManager, cfg *kubeadmapi.InitConfiguration, beforePodHash string, recoverManifests map[string]string, isTLSUpgrade bool) error {
|
||||
// Special treatment is required for etcd case, when rollbackOldManifests should roll back etcd
|
||||
// manifests only for the case when component is Etcd
|
||||
recoverEtcd := false
|
||||
@ -180,27 +189,8 @@ func upgradeComponent(component string, waiter apiclient.Waiter, pathMgr StaticP
|
||||
}
|
||||
}
|
||||
|
||||
// ensure etcd certs are generated for etcd and kube-apiserver
|
||||
if component == constants.Etcd || component == constants.KubeAPIServer {
|
||||
if err := certsphase.CreateEtcdCACertAndKeyFiles(cfg); err != nil {
|
||||
return fmt.Errorf("failed to upgrade the %s CA certificate and key: %v", constants.Etcd, err)
|
||||
}
|
||||
}
|
||||
if component == constants.Etcd {
|
||||
if err := certsphase.CreateEtcdServerCertAndKeyFiles(cfg); err != nil {
|
||||
return fmt.Errorf("failed to upgrade the %s certificate and key: %v", constants.Etcd, err)
|
||||
}
|
||||
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 {
|
||||
return fmt.Errorf("failed to upgrade the %s %s-client certificate and key: %v", constants.KubeAPIServer, constants.Etcd, err)
|
||||
}
|
||||
if err := renewCerts(cfg, component); err != nil {
|
||||
return errors.Wrapf(err, "failed to renew certificates for component %q", component)
|
||||
}
|
||||
|
||||
// The old manifest is here; in the /etc/kubernetes/manifests/
|
||||
@ -214,6 +204,16 @@ func upgradeComponent(component string, waiter apiclient.Waiter, pathMgr StaticP
|
||||
// Store the backup path in the recover list. If something goes wrong now, this component will be rolled back.
|
||||
recoverManifests[component] = backupManifestPath
|
||||
|
||||
// Skip upgrade if current and new manifests are equal
|
||||
equal, err := staticpod.ManifestFilesAreEqual(currentManifestPath, newManifestPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if equal {
|
||||
fmt.Printf("[upgrade/staticpods] current and new manifests of %s are equal, skipping upgrade\n", component)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Move the old manifest into the old-manifests directory
|
||||
if err := pathMgr.MoveFile(currentManifestPath, backupManifestPath); err != nil {
|
||||
return rollbackOldManifests(recoverManifests, err, pathMgr, recoverEtcd)
|
||||
@ -228,6 +228,7 @@ func upgradeComponent(component string, waiter apiclient.Waiter, pathMgr StaticP
|
||||
|
||||
if waitForComponentRestart {
|
||||
fmt.Println("[upgrade/staticpods] Waiting for the kubelet to restart the component")
|
||||
fmt.Printf("[upgrade/staticpods] This might take a minute or longer depending on the component/version gap (timeout %v)\n", UpgradeManifestTimeout)
|
||||
|
||||
// Wait for the mirror Pod hash to change; otherwise we'll run into race conditions here when the kubelet hasn't had time to
|
||||
// notice the removal of the Static Pod, leading to a false positive below where we check that the API endpoint is healthy
|
||||
@ -251,42 +252,50 @@ func upgradeComponent(component string, waiter apiclient.Waiter, pathMgr StaticP
|
||||
}
|
||||
|
||||
// performEtcdStaticPodUpgrade performs upgrade of etcd, it returns bool which indicates fatal error or not and the actual error.
|
||||
func performEtcdStaticPodUpgrade(waiter apiclient.Waiter, pathMgr StaticPodPathManager, cfg *kubeadmapi.MasterConfiguration, recoverManifests map[string]string, isTLSUpgrade bool, oldEtcdClient, newEtcdClient etcdutil.ClusterInterrogator) (bool, error) {
|
||||
func performEtcdStaticPodUpgrade(client clientset.Interface, waiter apiclient.Waiter, pathMgr StaticPodPathManager, cfg *kubeadmapi.InitConfiguration, recoverManifests map[string]string, isTLSUpgrade bool, oldEtcdClient, newEtcdClient etcdutil.ClusterInterrogator) (bool, error) {
|
||||
// Add etcd static pod spec only if external etcd is not configured
|
||||
if cfg.Etcd.External != nil {
|
||||
return false, fmt.Errorf("external etcd detected, won't try to change any etcd state")
|
||||
return false, errors.New("external etcd detected, won't try to change any etcd state")
|
||||
}
|
||||
|
||||
// Checking health state of etcd before proceeding with the upgrade
|
||||
_, err := oldEtcdClient.GetClusterStatus()
|
||||
if err != nil {
|
||||
return true, fmt.Errorf("etcd cluster is not healthy: %v", err)
|
||||
return true, errors.Wrap(err, "etcd cluster is not healthy")
|
||||
}
|
||||
|
||||
// Backing up etcd data store
|
||||
backupEtcdDir := pathMgr.BackupEtcdDir()
|
||||
runningEtcdDir := cfg.Etcd.Local.DataDir
|
||||
if err := util.CopyDir(runningEtcdDir, backupEtcdDir); err != nil {
|
||||
return true, fmt.Errorf("failed to back up etcd data: %v", err)
|
||||
return true, errors.Wrap(err, "failed to back up etcd data")
|
||||
}
|
||||
|
||||
// Need to check currently used version and version from constants, if differs then upgrade
|
||||
desiredEtcdVersion, err := constants.EtcdSupportedVersion(cfg.KubernetesVersion)
|
||||
if err != nil {
|
||||
return true, fmt.Errorf("failed to retrieve an etcd version for the target kubernetes version: %v", err)
|
||||
return true, errors.Wrap(err, "failed to retrieve an etcd version for the target Kubernetes version")
|
||||
}
|
||||
currentEtcdVersionStr, err := oldEtcdClient.GetVersion()
|
||||
|
||||
// gets the etcd version of the local/stacked etcd member running on the current machine
|
||||
currentEtcdVersions, err := oldEtcdClient.GetClusterVersions()
|
||||
if err != nil {
|
||||
return true, fmt.Errorf("failed to retrieve the current etcd version: %v", err)
|
||||
return true, errors.Wrap(err, "failed to retrieve the current etcd version")
|
||||
}
|
||||
currentEtcdVersionStr, ok := currentEtcdVersions[etcdutil.GetClientURL(cfg)]
|
||||
if !ok {
|
||||
fmt.Println(currentEtcdVersions)
|
||||
return true, errors.Wrap(err, "failed to retrieve the current etcd version")
|
||||
}
|
||||
|
||||
currentEtcdVersion, err := version.ParseSemantic(currentEtcdVersionStr)
|
||||
if err != nil {
|
||||
return true, fmt.Errorf("failed to parse the current etcd version(%s): %v", currentEtcdVersionStr, err)
|
||||
return true, errors.Wrapf(err, "failed to parse the current etcd version(%s)", currentEtcdVersionStr)
|
||||
}
|
||||
|
||||
// Comparing current etcd version with desired to catch the same version or downgrade condition and fail on them.
|
||||
if desiredEtcdVersion.LessThan(currentEtcdVersion) {
|
||||
return false, fmt.Errorf("the desired etcd version for this Kubernetes version %q is %q, but the current etcd version is %q. Won't downgrade etcd, instead just continue", cfg.KubernetesVersion, desiredEtcdVersion.String(), currentEtcdVersion.String())
|
||||
return false, errors.Errorf("the desired etcd version for this Kubernetes version %q is %q, but the current etcd version is %q. Won't downgrade etcd, instead just continue", cfg.KubernetesVersion, desiredEtcdVersion.String(), currentEtcdVersion.String())
|
||||
}
|
||||
// For the case when desired etcd version is the same as current etcd version
|
||||
if strings.Compare(desiredEtcdVersion.String(), currentEtcdVersion.String()) == 0 {
|
||||
@ -295,13 +304,13 @@ func performEtcdStaticPodUpgrade(waiter apiclient.Waiter, pathMgr StaticPodPathM
|
||||
|
||||
beforeEtcdPodHash, err := waiter.WaitForStaticPodSingleHash(cfg.NodeRegistration.Name, constants.Etcd)
|
||||
if err != nil {
|
||||
return true, fmt.Errorf("failed to get etcd pod's hash: %v", err)
|
||||
return true, errors.Wrap(err, "failed to get etcd pod's hash")
|
||||
}
|
||||
|
||||
// Write the updated etcd static Pod manifest into the temporary directory, at this point no etcd change
|
||||
// has occurred in any aspects.
|
||||
if err := etcdphase.CreateLocalEtcdStaticPodManifestFile(pathMgr.TempManifestDir(), cfg); err != nil {
|
||||
return true, fmt.Errorf("error creating local etcd static pod manifest file: %v", err)
|
||||
return true, errors.Wrap(err, "error creating local etcd static pod manifest file")
|
||||
}
|
||||
|
||||
// Waiter configurations for checking etcd status
|
||||
@ -330,7 +339,7 @@ func performEtcdStaticPodUpgrade(waiter apiclient.Waiter, pathMgr StaticPodPathM
|
||||
fmt.Println("[upgrade/etcd] Rolling back etcd data")
|
||||
if err := rollbackEtcdData(cfg, pathMgr); err != nil {
|
||||
// Even copying back datastore failed, no options for recovery left, bailing out
|
||||
return true, fmt.Errorf("fatal error rolling back local etcd cluster datadir: %v, the backup of etcd database is stored here:(%s)", err, backupEtcdDir)
|
||||
return true, errors.Errorf("fatal error rolling back local etcd cluster datadir: %v, the backup of etcd database is stored here:(%s)", err, backupEtcdDir)
|
||||
}
|
||||
fmt.Println("[upgrade/etcd] Etcd data rollback successful")
|
||||
|
||||
@ -339,7 +348,7 @@ func performEtcdStaticPodUpgrade(waiter apiclient.Waiter, pathMgr StaticPodPathM
|
||||
if _, err := oldEtcdClient.WaitForClusterAvailable(noDelay, retries, retryInterval); err != nil {
|
||||
fmt.Printf("[upgrade/etcd] Failed to healthcheck previous etcd: %v\n", err)
|
||||
// Nothing else left to try to recover etcd cluster
|
||||
return true, fmt.Errorf("fatal error rolling back local etcd cluster manifest: %v, the backup of etcd database is stored here:(%s)", err, backupEtcdDir)
|
||||
return true, errors.Wrapf(err, "fatal error rolling back local etcd cluster manifest, the backup of etcd database is stored here:(%s)", backupEtcdDir)
|
||||
}
|
||||
|
||||
// We've recovered to the previous etcd from this case
|
||||
@ -347,20 +356,16 @@ func performEtcdStaticPodUpgrade(waiter apiclient.Waiter, pathMgr StaticPodPathM
|
||||
fmt.Println("[upgrade/etcd] Etcd was rolled back and is now available")
|
||||
|
||||
// Since etcd cluster came back up with the old manifest
|
||||
return true, fmt.Errorf("fatal error when trying to upgrade the etcd cluster: %v, rolled the state back to pre-upgrade state", err)
|
||||
return true, errors.Wrap(err, "fatal error when trying to upgrade the etcd cluster, rolled the state back to pre-upgrade state")
|
||||
}
|
||||
|
||||
// Initialize the new etcd client if it wasn't pre-initialized
|
||||
if newEtcdClient == nil {
|
||||
client, err := etcdutil.NewFromStaticPod(
|
||||
[]string{"localhost:2379"},
|
||||
constants.GetStaticPodDirectory(),
|
||||
cfg.CertificatesDir,
|
||||
)
|
||||
etcdClient, err := etcdutil.NewFromCluster(client, cfg.CertificatesDir)
|
||||
if err != nil {
|
||||
return true, fmt.Errorf("fatal error creating etcd client: %v", err)
|
||||
return true, errors.Wrap(err, "fatal error creating etcd client")
|
||||
}
|
||||
newEtcdClient = client
|
||||
newEtcdClient = etcdClient
|
||||
}
|
||||
|
||||
// Checking health state of etcd after the upgrade
|
||||
@ -372,7 +377,7 @@ func performEtcdStaticPodUpgrade(waiter apiclient.Waiter, pathMgr StaticPodPathM
|
||||
fmt.Println("[upgrade/etcd] Rolling back etcd data")
|
||||
if err := rollbackEtcdData(cfg, pathMgr); err != nil {
|
||||
// Even copying back datastore failed, no options for recovery left, bailing out
|
||||
return true, fmt.Errorf("fatal error rolling back local etcd cluster datadir: %v, the backup of etcd database is stored here:(%s)", err, backupEtcdDir)
|
||||
return true, errors.Wrapf(err, "fatal error rolling back local etcd cluster datadir, the backup of etcd database is stored here:(%s)", backupEtcdDir)
|
||||
}
|
||||
fmt.Println("[upgrade/etcd] Etcd data rollback successful")
|
||||
|
||||
@ -386,19 +391,19 @@ func performEtcdStaticPodUpgrade(waiter apiclient.Waiter, pathMgr StaticPodPathM
|
||||
if _, err := oldEtcdClient.WaitForClusterAvailable(noDelay, retries, retryInterval); err != nil {
|
||||
fmt.Printf("[upgrade/etcd] Failed to healthcheck previous etcd: %v\n", err)
|
||||
// Nothing else left to try to recover etcd cluster
|
||||
return true, fmt.Errorf("fatal error rolling back local etcd cluster manifest: %v, the backup of etcd database is stored here:(%s)", err, backupEtcdDir)
|
||||
return true, errors.Wrapf(err, "fatal error rolling back local etcd cluster manifest, the backup of etcd database is stored here:(%s)", backupEtcdDir)
|
||||
}
|
||||
fmt.Println("[upgrade/etcd] Etcd was rolled back and is now available")
|
||||
|
||||
// We've successfully rolled back etcd, and now return an error describing that the upgrade failed
|
||||
return true, fmt.Errorf("fatal error upgrading local etcd cluster: %v, rolled the state back to pre-upgrade state", err)
|
||||
return true, errors.Wrap(err, "fatal error upgrading local etcd cluster, rolled the state back to pre-upgrade state")
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// StaticPodControlPlane upgrades a static pod-hosted control plane
|
||||
func StaticPodControlPlane(waiter apiclient.Waiter, pathMgr StaticPodPathManager, cfg *kubeadmapi.MasterConfiguration, etcdUpgrade bool, oldEtcdClient, newEtcdClient etcdutil.ClusterInterrogator) error {
|
||||
func StaticPodControlPlane(client clientset.Interface, waiter apiclient.Waiter, pathMgr StaticPodPathManager, cfg *kubeadmapi.InitConfiguration, etcdUpgrade bool, oldEtcdClient, newEtcdClient etcdutil.ClusterInterrogator) error {
|
||||
recoverManifests := map[string]string{}
|
||||
var isTLSUpgrade bool
|
||||
var isExternalEtcd bool
|
||||
@ -412,31 +417,27 @@ func StaticPodControlPlane(waiter apiclient.Waiter, pathMgr StaticPodPathManager
|
||||
if cfg.Etcd.External != nil {
|
||||
// External etcd
|
||||
isExternalEtcd = true
|
||||
client, err := etcdutil.New(
|
||||
etcdClient, err := etcdutil.New(
|
||||
cfg.Etcd.External.Endpoints,
|
||||
cfg.Etcd.External.CAFile,
|
||||
cfg.Etcd.External.CertFile,
|
||||
cfg.Etcd.External.KeyFile,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create etcd client for external etcd: %v", err)
|
||||
return errors.Wrap(err, "failed to create etcd client for external etcd")
|
||||
}
|
||||
oldEtcdClient = client
|
||||
oldEtcdClient = etcdClient
|
||||
// Since etcd is managed externally, the new etcd client will be the same as the old client
|
||||
if newEtcdClient == nil {
|
||||
newEtcdClient = client
|
||||
newEtcdClient = etcdClient
|
||||
}
|
||||
} else {
|
||||
// etcd Static Pod
|
||||
client, err := etcdutil.NewFromStaticPod(
|
||||
[]string{"localhost:2379"},
|
||||
constants.GetStaticPodDirectory(),
|
||||
cfg.CertificatesDir,
|
||||
)
|
||||
etcdClient, err := etcdutil.NewFromCluster(client, cfg.CertificatesDir)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create etcd client: %v", err)
|
||||
return errors.Wrap(err, "failed to create etcd client")
|
||||
}
|
||||
oldEtcdClient = client
|
||||
oldEtcdClient = etcdClient
|
||||
}
|
||||
}
|
||||
|
||||
@ -451,7 +452,7 @@ func StaticPodControlPlane(waiter apiclient.Waiter, pathMgr StaticPodPathManager
|
||||
}
|
||||
|
||||
// Perform etcd upgrade using common to all control plane components function
|
||||
fatal, err := performEtcdStaticPodUpgrade(waiter, pathMgr, cfg, recoverManifests, isTLSUpgrade, oldEtcdClient, newEtcdClient)
|
||||
fatal, err := performEtcdStaticPodUpgrade(client, waiter, pathMgr, cfg, recoverManifests, isTLSUpgrade, oldEtcdClient, newEtcdClient)
|
||||
if err != nil {
|
||||
if fatal {
|
||||
return err
|
||||
@ -464,7 +465,7 @@ func StaticPodControlPlane(waiter apiclient.Waiter, pathMgr StaticPodPathManager
|
||||
fmt.Printf("[upgrade/staticpods] Writing new Static Pod manifests to %q\n", pathMgr.TempManifestDir())
|
||||
err = controlplanephase.CreateInitStaticPodManifestFiles(pathMgr.TempManifestDir(), cfg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating init static pod manifest files: %v", err)
|
||||
return errors.Wrap(err, "error creating init static pod manifest files")
|
||||
}
|
||||
|
||||
for _, component := range constants.MasterComponents {
|
||||
@ -498,19 +499,51 @@ func rollbackOldManifests(oldManifests map[string]string, origErr error, pathMgr
|
||||
}
|
||||
}
|
||||
// Let the user know there were problems, but we tried to recover
|
||||
return fmt.Errorf("couldn't upgrade control plane. kubeadm has tried to recover everything into the earlier state. Errors faced: %v", errs)
|
||||
return errors.New("couldn't upgrade control plane. kubeadm has tried to recover everything into the earlier state. Errors faced")
|
||||
}
|
||||
|
||||
// rollbackEtcdData rolls back the the content of etcd folder if something went wrong.
|
||||
// rollbackEtcdData rolls back the content of etcd folder if something went wrong.
|
||||
// When the folder contents are successfully rolled back, nil is returned, otherwise an error is returned.
|
||||
func rollbackEtcdData(cfg *kubeadmapi.MasterConfiguration, pathMgr StaticPodPathManager) error {
|
||||
func rollbackEtcdData(cfg *kubeadmapi.InitConfiguration, pathMgr StaticPodPathManager) error {
|
||||
backupEtcdDir := pathMgr.BackupEtcdDir()
|
||||
runningEtcdDir := cfg.Etcd.Local.DataDir
|
||||
|
||||
if err := util.CopyDir(backupEtcdDir, runningEtcdDir); err != nil {
|
||||
// Let the user know there we're problems, but we tried to reçover
|
||||
return fmt.Errorf("couldn't recover etcd database with error: %v, the location of etcd backup: %s ", err, backupEtcdDir)
|
||||
return errors.Wrapf(err, "couldn't recover etcd database with error, the location of etcd backup: %s ", backupEtcdDir)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func renewCerts(cfg *kubeadmapi.InitConfiguration, component string) error {
|
||||
if cfg.Etcd.Local != nil {
|
||||
// ensure etcd certs are loaded for etcd and kube-apiserver
|
||||
if component == constants.Etcd || component == constants.KubeAPIServer {
|
||||
caCert, caKey, err := certsphase.LoadCertificateAuthority(cfg.CertificatesDir, certsphase.KubeadmCertEtcdCA.BaseName)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to upgrade the %s CA certificate and key", constants.Etcd)
|
||||
}
|
||||
renewer := renewal.NewFileRenewal(caCert, caKey)
|
||||
|
||||
if component == constants.Etcd {
|
||||
for _, cert := range []*certsphase.KubeadmCert{
|
||||
&certsphase.KubeadmCertEtcdServer,
|
||||
&certsphase.KubeadmCertEtcdPeer,
|
||||
&certsphase.KubeadmCertEtcdHealthcheck,
|
||||
} {
|
||||
if err := renewal.RenewExistingCert(cfg.CertificatesDir, cert.BaseName, renewer); err != nil {
|
||||
return errors.Wrapf(err, "failed to renew %s certificate and key", cert.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
if component == constants.KubeAPIServer {
|
||||
cert := certsphase.KubeadmCertEtcdAPIClient
|
||||
if err := renewal.RenewExistingCert(cfg.CertificatesDir, cert.BaseName, renewer); err != nil {
|
||||
return errors.Wrapf(err, "failed to renew %s certificate and key", cert.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
277
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/upgrade/staticpods_test.go
generated
vendored
277
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/upgrade/staticpods_test.go
generated
vendored
@ -20,6 +20,7 @@ import (
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
@ -28,16 +29,20 @@ import (
|
||||
|
||||
"github.com/coreos/etcd/clientv3"
|
||||
"github.com/coreos/etcd/pkg/transport"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
kubeadmscheme "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/scheme"
|
||||
kubeadmapiv1alpha2 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha2"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
certsphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/certs"
|
||||
controlplanephase "k8s.io/kubernetes/cmd/kubeadm/app/phases/controlplane"
|
||||
etcdphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/etcd"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
|
||||
configutil "k8s.io/kubernetes/cmd/kubeadm/app/util/config"
|
||||
etcdutil "k8s.io/kubernetes/cmd/kubeadm/app/util/etcd"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/util/pkiutil"
|
||||
testutil "k8s.io/kubernetes/cmd/kubeadm/test"
|
||||
certstestutil "k8s.io/kubernetes/cmd/kubeadm/test/certs"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -46,33 +51,36 @@ const (
|
||||
waitForPodsWithLabel = "wait-for-pods-with-label"
|
||||
|
||||
testConfiguration = `
|
||||
apiVersion: kubeadm.k8s.io/v1alpha2
|
||||
kind: MasterConfiguration
|
||||
api:
|
||||
advertiseAddress: 1.2.3.4
|
||||
apiVersion: kubeadm.k8s.io/v1beta1
|
||||
kind: InitConfiguration
|
||||
nodeRegistration:
|
||||
name: foo
|
||||
criSocket: ""
|
||||
localAPIEndpoint:
|
||||
advertiseAddress: 192.168.2.2
|
||||
bindPort: 6443
|
||||
apiServerCertSANs: null
|
||||
apiServerExtraArgs: null
|
||||
bootstrapTokens:
|
||||
- token: ce3aa5.5ec8455bb76b379f
|
||||
ttl: 24h
|
||||
---
|
||||
apiVersion: kubeadm.k8s.io/v1beta1
|
||||
kind: ClusterConfiguration
|
||||
|
||||
apiServer:
|
||||
certSANs: null
|
||||
extraArgs: null
|
||||
certificatesDir: %s
|
||||
controllerManagerExtraArgs: null
|
||||
etcd:
|
||||
local:
|
||||
dataDir: %s
|
||||
image: ""
|
||||
featureFlags: null
|
||||
imageRepository: k8s.gcr.io
|
||||
kubernetesVersion: %s
|
||||
networking:
|
||||
dnsDomain: cluster.local
|
||||
podSubnet: ""
|
||||
serviceSubnet: 10.96.0.0/12
|
||||
nodeRegistration:
|
||||
name: foo
|
||||
criSocket: ""
|
||||
schedulerExtraArgs: null
|
||||
token: ce3aa5.5ec8455bb76b379f
|
||||
tokenTTL: 24h
|
||||
unifiedControlPlaneImage: ""
|
||||
useHyperKubeImage: false
|
||||
`
|
||||
)
|
||||
|
||||
@ -125,6 +133,11 @@ func (w *fakeWaiter) WaitForHealthyKubelet(_ time.Duration, _ string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// WaitForKubeletAndFunc is a wrapper for WaitForHealthyKubelet that also blocks for a function
|
||||
func (w *fakeWaiter) WaitForKubeletAndFunc(f func() error) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type fakeStaticPodPathManager struct {
|
||||
kubernetesDir string
|
||||
realManifestDir string
|
||||
@ -137,22 +150,22 @@ type fakeStaticPodPathManager struct {
|
||||
func NewFakeStaticPodPathManager(moveFileFunc func(string, string) error) (StaticPodPathManager, error) {
|
||||
kubernetesDir, err := ioutil.TempDir("", "kubeadm-pathmanager-")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't create a temporary directory for the upgrade: %v", err)
|
||||
return nil, errors.Wrapf(err, "couldn't create a temporary directory for the upgrade")
|
||||
}
|
||||
|
||||
realManifestDir := filepath.Join(kubernetesDir, constants.ManifestsSubDirName)
|
||||
if err := os.Mkdir(realManifestDir, 0700); err != nil {
|
||||
return nil, fmt.Errorf("couldn't create a realManifestDir for the upgrade: %v", err)
|
||||
return nil, errors.Wrapf(err, "couldn't create a realManifestDir for the upgrade")
|
||||
}
|
||||
|
||||
upgradedManifestDir := filepath.Join(kubernetesDir, "upgraded-manifests")
|
||||
if err := os.Mkdir(upgradedManifestDir, 0700); err != nil {
|
||||
return nil, fmt.Errorf("couldn't create a upgradedManifestDir for the upgrade: %v", err)
|
||||
return nil, errors.Wrapf(err, "couldn't create a upgradedManifestDir for the upgrade")
|
||||
}
|
||||
|
||||
backupManifestDir := filepath.Join(kubernetesDir, "backup-manifests")
|
||||
if err := os.Mkdir(backupManifestDir, 0700); err != nil {
|
||||
return nil, fmt.Errorf("couldn't create a backupManifestDir for the upgrade: %v", err)
|
||||
return nil, errors.Wrap(err, "couldn't create a backupManifestDir for the upgrade")
|
||||
}
|
||||
|
||||
backupEtcdDir := filepath.Join(kubernetesDir, "kubeadm-backup-etcd")
|
||||
@ -227,14 +240,14 @@ func (c fakeTLSEtcdClient) WaitForClusterAvailable(delay time.Duration, retries
|
||||
|
||||
func (c fakeTLSEtcdClient) GetClusterStatus() (map[string]*clientv3.StatusResponse, error) {
|
||||
return map[string]*clientv3.StatusResponse{
|
||||
"foo": {
|
||||
"https://1.2.3.4:2379": {
|
||||
Version: "3.1.12",
|
||||
}}, nil
|
||||
}
|
||||
|
||||
func (c fakeTLSEtcdClient) GetClusterVersions() (map[string]string, error) {
|
||||
return map[string]string{
|
||||
"foo": "3.1.12",
|
||||
"https://1.2.3.4:2379": "3.1.12",
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -242,6 +255,12 @@ func (c fakeTLSEtcdClient) GetVersion() (string, error) {
|
||||
return "3.1.12", nil
|
||||
}
|
||||
|
||||
func (c fakeTLSEtcdClient) Sync() error { return nil }
|
||||
|
||||
func (c fakeTLSEtcdClient) AddMember(name string, peerAddrs string) ([]etcdutil.Member, error) {
|
||||
return []etcdutil.Member{}, nil
|
||||
}
|
||||
|
||||
type fakePodManifestEtcdClient struct{ ManifestDir, CertificatesDir string }
|
||||
|
||||
func (c fakePodManifestEtcdClient) HasTLS() bool {
|
||||
@ -268,13 +287,13 @@ func (c fakePodManifestEtcdClient) GetClusterStatus() (map[string]*clientv3.Stat
|
||||
}
|
||||
|
||||
return map[string]*clientv3.StatusResponse{
|
||||
"foo": {Version: "3.1.12"},
|
||||
"https://1.2.3.4:2379": {Version: "3.1.12"},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c fakePodManifestEtcdClient) GetClusterVersions() (map[string]string, error) {
|
||||
return map[string]string{
|
||||
"foo": "3.1.12",
|
||||
"https://1.2.3.4:2379": "3.1.12",
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -282,6 +301,12 @@ func (c fakePodManifestEtcdClient) GetVersion() (string, error) {
|
||||
return "3.1.12", nil
|
||||
}
|
||||
|
||||
func (c fakePodManifestEtcdClient) Sync() error { return nil }
|
||||
|
||||
func (c fakePodManifestEtcdClient) AddMember(name string, peerAddrs string) ([]etcdutil.Member, error) {
|
||||
return []etcdutil.Member{}, nil
|
||||
}
|
||||
|
||||
func TestStaticPodControlPlane(t *testing.T) {
|
||||
tests := []struct {
|
||||
description string
|
||||
@ -306,7 +331,7 @@ func TestStaticPodControlPlane(t *testing.T) {
|
||||
{
|
||||
description: "any wait error should result in a rollback and an abort",
|
||||
waitErrsToReturn: map[string]error{
|
||||
waitForHashes: fmt.Errorf("boo! failed"),
|
||||
waitForHashes: errors.New("boo! failed"),
|
||||
waitForHashChange: nil,
|
||||
waitForPodsWithLabel: nil,
|
||||
},
|
||||
@ -320,7 +345,7 @@ func TestStaticPodControlPlane(t *testing.T) {
|
||||
description: "any wait error should result in a rollback and an abort",
|
||||
waitErrsToReturn: map[string]error{
|
||||
waitForHashes: nil,
|
||||
waitForHashChange: fmt.Errorf("boo! failed"),
|
||||
waitForHashChange: errors.New("boo! failed"),
|
||||
waitForPodsWithLabel: nil,
|
||||
},
|
||||
moveFileFunc: func(oldPath, newPath string) error {
|
||||
@ -334,7 +359,7 @@ func TestStaticPodControlPlane(t *testing.T) {
|
||||
waitErrsToReturn: map[string]error{
|
||||
waitForHashes: nil,
|
||||
waitForHashChange: nil,
|
||||
waitForPodsWithLabel: fmt.Errorf("boo! failed"),
|
||||
waitForPodsWithLabel: errors.New("boo! failed"),
|
||||
},
|
||||
moveFileFunc: func(oldPath, newPath string) error {
|
||||
return os.Rename(oldPath, newPath)
|
||||
@ -352,7 +377,7 @@ func TestStaticPodControlPlane(t *testing.T) {
|
||||
moveFileFunc: func(oldPath, newPath string) error {
|
||||
// fail for kube-apiserver move
|
||||
if strings.Contains(newPath, "kube-apiserver") {
|
||||
return fmt.Errorf("moving the kube-apiserver file failed")
|
||||
return errors.New("moving the kube-apiserver file failed")
|
||||
}
|
||||
return os.Rename(oldPath, newPath)
|
||||
},
|
||||
@ -369,7 +394,7 @@ func TestStaticPodControlPlane(t *testing.T) {
|
||||
moveFileFunc: func(oldPath, newPath string) error {
|
||||
// fail for kube-controller-manager move
|
||||
if strings.Contains(newPath, "kube-controller-manager") {
|
||||
return fmt.Errorf("moving the kube-apiserver file failed")
|
||||
return errors.New("moving the kube-apiserver file failed")
|
||||
}
|
||||
return os.Rename(oldPath, newPath)
|
||||
},
|
||||
@ -386,7 +411,7 @@ func TestStaticPodControlPlane(t *testing.T) {
|
||||
moveFileFunc: func(oldPath, newPath string) error {
|
||||
// fail for kube-scheduler move
|
||||
if strings.Contains(newPath, "kube-scheduler") {
|
||||
return fmt.Errorf("moving the kube-apiserver file failed")
|
||||
return errors.New("moving the kube-apiserver file failed")
|
||||
}
|
||||
return os.Rename(oldPath, newPath)
|
||||
},
|
||||
@ -415,32 +440,21 @@ func TestStaticPodControlPlane(t *testing.T) {
|
||||
}
|
||||
defer os.RemoveAll(tmpEtcdDataDir)
|
||||
|
||||
oldcfg, err := getConfig("v1.9.0", tempCertsDir, tmpEtcdDataDir)
|
||||
oldcfg, err := getConfig("v1.12.0", tempCertsDir, tmpEtcdDataDir)
|
||||
if err != nil {
|
||||
t.Fatalf("couldn't create config: %v", err)
|
||||
}
|
||||
|
||||
// Initialize PKI minus any etcd certificates to simulate etcd PKI upgrade
|
||||
certActions := []func(cfg *kubeadmapi.MasterConfiguration) error{
|
||||
certsphase.CreateCACertAndKeyFiles,
|
||||
certsphase.CreateAPIServerCertAndKeyFiles,
|
||||
certsphase.CreateAPIServerKubeletClientCertAndKeyFiles,
|
||||
// certsphase.CreateEtcdCACertAndKeyFiles,
|
||||
// certsphase.CreateEtcdServerCertAndKeyFiles,
|
||||
// certsphase.CreateEtcdPeerCertAndKeyFiles,
|
||||
// certsphase.CreateEtcdHealthcheckClientCertAndKeyFiles,
|
||||
// certsphase.CreateAPIServerEtcdClientCertAndKeyFiles,
|
||||
certsphase.CreateServiceAccountKeyAndPublicKeyFiles,
|
||||
certsphase.CreateFrontProxyCACertAndKeyFiles,
|
||||
certsphase.CreateFrontProxyClientCertAndKeyFiles,
|
||||
tree, err := certsphase.GetCertsWithoutEtcd().AsMap().CertTree()
|
||||
if err != nil {
|
||||
t.Fatalf("couldn't get cert tree: %v", err)
|
||||
}
|
||||
for _, action := range certActions {
|
||||
err := action(oldcfg)
|
||||
if err != nil {
|
||||
t.Fatalf("couldn't initialize pre-upgrade certificate: %v", err)
|
||||
}
|
||||
|
||||
if err := tree.CreateTree(oldcfg); err != nil {
|
||||
t.Fatalf("couldn't get create cert tree: %v", err)
|
||||
}
|
||||
fmt.Printf("Wrote certs to %s\n", oldcfg.CertificatesDir)
|
||||
|
||||
t.Logf("Wrote certs to %s\n", oldcfg.CertificatesDir)
|
||||
|
||||
// Initialize the directory with v1.7 manifests; should then be upgraded to v1.8 using the method
|
||||
err = controlplanephase.CreateInitStaticPodManifestFiles(pathMgr.RealManifestDir(), oldcfg)
|
||||
@ -457,12 +471,29 @@ func TestStaticPodControlPlane(t *testing.T) {
|
||||
t.Fatalf("couldn't read temp file: %v", err)
|
||||
}
|
||||
|
||||
newcfg, err := getConfig("v1.10.0", tempCertsDir, tmpEtcdDataDir)
|
||||
newcfg, err := getConfig("v1.13.0", tempCertsDir, tmpEtcdDataDir)
|
||||
if err != nil {
|
||||
t.Fatalf("couldn't create config: %v", err)
|
||||
}
|
||||
|
||||
// create the kubeadm etcd certs
|
||||
caCert, caKey, err := certsphase.KubeadmCertEtcdCA.CreateAsCA(newcfg)
|
||||
if err != nil {
|
||||
t.Fatalf("couldn't create new CA certificate: %v", err)
|
||||
}
|
||||
for _, cert := range []*certsphase.KubeadmCert{
|
||||
&certsphase.KubeadmCertEtcdServer,
|
||||
&certsphase.KubeadmCertEtcdPeer,
|
||||
&certsphase.KubeadmCertEtcdHealthcheck,
|
||||
&certsphase.KubeadmCertEtcdAPIClient,
|
||||
} {
|
||||
if err := cert.CreateFromCA(newcfg, caCert, caKey); err != nil {
|
||||
t.Fatalf("couldn't create certificate %s: %v", cert.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
actualErr := StaticPodControlPlane(
|
||||
nil,
|
||||
waiter,
|
||||
pathMgr,
|
||||
newcfg,
|
||||
@ -492,10 +523,11 @@ func TestStaticPodControlPlane(t *testing.T) {
|
||||
|
||||
if (oldHash != newHash) != rt.manifestShouldChange {
|
||||
t.Errorf(
|
||||
"failed StaticPodControlPlane\n%s\n\texpected manifest change: %t\n\tgot: %t",
|
||||
"failed StaticPodControlPlane\n%s\n\texpected manifest change: %t\n\tgot: %t\n\tnewHash: %v",
|
||||
rt.description,
|
||||
rt.manifestShouldChange,
|
||||
(oldHash != newHash),
|
||||
newHash,
|
||||
)
|
||||
}
|
||||
return
|
||||
@ -513,15 +545,26 @@ func getAPIServerHash(dir string) (string, error) {
|
||||
return fmt.Sprintf("%x", sha256.Sum256(fileBytes)), nil
|
||||
}
|
||||
|
||||
// TODO: Make this test function use the rest of the "official" API machinery helper funcs we have inside of kubeadm
|
||||
func getConfig(version, certsDir, etcdDataDir string) (*kubeadmapi.MasterConfiguration, error) {
|
||||
externalcfg := &kubeadmapiv1alpha2.MasterConfiguration{}
|
||||
internalcfg := &kubeadmapi.MasterConfiguration{}
|
||||
if err := runtime.DecodeInto(kubeadmscheme.Codecs.UniversalDecoder(), []byte(fmt.Sprintf(testConfiguration, certsDir, etcdDataDir, version)), externalcfg); err != nil {
|
||||
return nil, fmt.Errorf("unable to decode config: %v", err)
|
||||
func getConfig(version, certsDir, etcdDataDir string) (*kubeadmapi.InitConfiguration, error) {
|
||||
configBytes := []byte(fmt.Sprintf(testConfiguration, certsDir, etcdDataDir, version))
|
||||
|
||||
// Unmarshal the config
|
||||
cfg, err := configutil.BytesToInternalConfig(configBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
kubeadmscheme.Scheme.Convert(externalcfg, internalcfg, nil)
|
||||
return internalcfg, nil
|
||||
|
||||
// Applies dynamic defaults to settings not provided with flags
|
||||
if err = configutil.SetInitDynamicDefaults(cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Validates cfg (flags/configs + defaults + dynamic defaults)
|
||||
if err = validation.ValidateInitConfiguration(cfg).ToAggregate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
func getTempDir(t *testing.T, name string) (string, func()) {
|
||||
@ -601,3 +644,113 @@ func TestCleanupDirs(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRenewCerts(t *testing.T) {
|
||||
caCert, caKey := certstestutil.SetupCertificateAuthorithy(t)
|
||||
t.Run("all certs exist, should be rotated", func(t *testing.T) {
|
||||
})
|
||||
tests := []struct {
|
||||
name string
|
||||
component string
|
||||
skipCreateCA bool
|
||||
shouldErrorOnRenew bool
|
||||
certsShouldExist []*certsphase.KubeadmCert
|
||||
}{
|
||||
{
|
||||
name: "all certs exist, should be rotated",
|
||||
component: constants.Etcd,
|
||||
certsShouldExist: []*certsphase.KubeadmCert{
|
||||
&certsphase.KubeadmCertEtcdServer,
|
||||
&certsphase.KubeadmCertEtcdPeer,
|
||||
&certsphase.KubeadmCertEtcdHealthcheck,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "just renew API cert",
|
||||
component: constants.KubeAPIServer,
|
||||
certsShouldExist: []*certsphase.KubeadmCert{
|
||||
&certsphase.KubeadmCertEtcdAPIClient,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ignores other compnonents",
|
||||
skipCreateCA: true,
|
||||
component: constants.KubeScheduler,
|
||||
},
|
||||
{
|
||||
name: "missing a cert to renew",
|
||||
component: constants.Etcd,
|
||||
shouldErrorOnRenew: true,
|
||||
certsShouldExist: []*certsphase.KubeadmCert{
|
||||
&certsphase.KubeadmCertEtcdServer,
|
||||
&certsphase.KubeadmCertEtcdPeer,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no CA, cannot continue",
|
||||
component: constants.Etcd,
|
||||
skipCreateCA: true,
|
||||
shouldErrorOnRenew: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
// Setup up basic requities
|
||||
tmpDir := testutil.SetupTempDir(t)
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
cfg := testutil.GetDefaultInternalConfig(t)
|
||||
cfg.CertificatesDir = tmpDir
|
||||
|
||||
if !test.skipCreateCA {
|
||||
if err := pkiutil.WriteCertAndKey(tmpDir, constants.EtcdCACertAndKeyBaseName, caCert, caKey); err != nil {
|
||||
t.Fatalf("couldn't write out CA: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Create expected certs
|
||||
for _, kubeCert := range test.certsShouldExist {
|
||||
if err := kubeCert.CreateFromCA(cfg, caCert, caKey); err != nil {
|
||||
t.Fatalf("couldn't renew certificate %q: %v", kubeCert.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Load expected certs to check if serial numbers changes
|
||||
certMaps := make(map[*certsphase.KubeadmCert]big.Int)
|
||||
for _, kubeCert := range test.certsShouldExist {
|
||||
cert, err := pkiutil.TryLoadCertFromDisk(tmpDir, kubeCert.BaseName)
|
||||
if err != nil {
|
||||
t.Fatalf("couldn't load certificate %q: %v", kubeCert.Name, err)
|
||||
}
|
||||
certMaps[kubeCert] = *cert.SerialNumber
|
||||
}
|
||||
|
||||
// Renew everything
|
||||
err := renewCerts(cfg, test.component)
|
||||
if test.shouldErrorOnRenew {
|
||||
if err == nil {
|
||||
t.Fatal("expected renewal error, got nothing")
|
||||
}
|
||||
// expected error, got error
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("couldn't renew certificates: %v", err)
|
||||
}
|
||||
|
||||
// See if the certificate serial numbers change
|
||||
for kubeCert, cert := range certMaps {
|
||||
newCert, err := pkiutil.TryLoadCertFromDisk(tmpDir, kubeCert.BaseName)
|
||||
if err != nil {
|
||||
t.Errorf("couldn't load new certificate %q: %v", kubeCert.Name, err)
|
||||
continue
|
||||
}
|
||||
if cert.Cmp(newCert.SerialNumber) == 0 {
|
||||
t.Errorf("certifitate %v was not reissued", kubeCert.Name)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
|
18
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/upgrade/versiongetter.go
generated
vendored
18
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/upgrade/versiongetter.go
generated
vendored
@ -20,11 +20,13 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
versionutil "k8s.io/apimachinery/pkg/util/version"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
|
||||
versionutil "k8s.io/kubernetes/pkg/util/version"
|
||||
"k8s.io/kubernetes/pkg/version"
|
||||
)
|
||||
|
||||
@ -59,13 +61,13 @@ func NewKubeVersionGetter(client clientset.Interface, writer io.Writer) VersionG
|
||||
func (g *KubeVersionGetter) ClusterVersion() (string, *versionutil.Version, error) {
|
||||
clusterVersionInfo, err := g.client.Discovery().ServerVersion()
|
||||
if err != nil {
|
||||
return "", nil, fmt.Errorf("Couldn't fetch cluster version from the API Server: %v", err)
|
||||
return "", nil, errors.Wrap(err, "Couldn't fetch cluster version from the API Server")
|
||||
}
|
||||
fmt.Fprintf(g.w, "[upgrade/versions] Cluster version: %s\n", clusterVersionInfo.String())
|
||||
|
||||
clusterVersion, err := versionutil.ParseSemantic(clusterVersionInfo.String())
|
||||
if err != nil {
|
||||
return "", nil, fmt.Errorf("Couldn't parse cluster version: %v", err)
|
||||
return "", nil, errors.Wrap(err, "Couldn't parse cluster version")
|
||||
}
|
||||
return clusterVersionInfo.String(), clusterVersion, nil
|
||||
}
|
||||
@ -77,7 +79,7 @@ func (g *KubeVersionGetter) KubeadmVersion() (string, *versionutil.Version, erro
|
||||
|
||||
kubeadmVersion, err := versionutil.ParseSemantic(kubeadmVersionInfo.String())
|
||||
if err != nil {
|
||||
return "", nil, fmt.Errorf("Couldn't parse kubeadm version: %v", err)
|
||||
return "", nil, errors.Wrap(err, "Couldn't parse kubeadm version")
|
||||
}
|
||||
return kubeadmVersionInfo.String(), kubeadmVersion, nil
|
||||
}
|
||||
@ -86,7 +88,7 @@ func (g *KubeVersionGetter) KubeadmVersion() (string, *versionutil.Version, erro
|
||||
func (g *KubeVersionGetter) VersionFromCILabel(ciVersionLabel, description string) (string, *versionutil.Version, error) {
|
||||
versionStr, err := kubeadmutil.KubernetesReleaseVersion(ciVersionLabel)
|
||||
if err != nil {
|
||||
return "", nil, fmt.Errorf("Couldn't fetch latest %s from the internet: %v", description, err)
|
||||
return "", nil, errors.Wrapf(err, "Couldn't fetch latest %s from the internet", description)
|
||||
}
|
||||
|
||||
if description != "" {
|
||||
@ -95,7 +97,7 @@ func (g *KubeVersionGetter) VersionFromCILabel(ciVersionLabel, description strin
|
||||
|
||||
ver, err := versionutil.ParseSemantic(versionStr)
|
||||
if err != nil {
|
||||
return "", nil, fmt.Errorf("Couldn't parse latest %s: %v", description, err)
|
||||
return "", nil, errors.Wrapf(err, "Couldn't parse latest %s", description)
|
||||
}
|
||||
return versionStr, ver, nil
|
||||
}
|
||||
@ -104,7 +106,7 @@ func (g *KubeVersionGetter) VersionFromCILabel(ciVersionLabel, description strin
|
||||
func (g *KubeVersionGetter) KubeletVersions() (map[string]uint16, error) {
|
||||
nodes, err := g.client.CoreV1().Nodes().List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't list all nodes in cluster")
|
||||
return nil, errors.New("couldn't list all nodes in cluster")
|
||||
}
|
||||
return computeKubeletVersions(nodes.Items), nil
|
||||
}
|
||||
@ -145,7 +147,7 @@ func (o *OfflineVersionGetter) VersionFromCILabel(ciVersionLabel, description st
|
||||
}
|
||||
ver, err := versionutil.ParseSemantic(o.version)
|
||||
if err != nil {
|
||||
return "", nil, fmt.Errorf("Couldn't parse version %s: %v", description, err)
|
||||
return "", nil, errors.Wrapf(err, "Couldn't parse version %s", description)
|
||||
}
|
||||
return o.version, ver, nil
|
||||
}
|
||||
|
25
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/uploadconfig/BUILD
generated
vendored
25
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/uploadconfig/BUILD
generated
vendored
@ -12,14 +12,14 @@ go_library(
|
||||
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/phases/uploadconfig",
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
|
||||
"//cmd/kubeadm/app/apis/kubeadm/scheme:go_default_library",
|
||||
"//cmd/kubeadm/app/apis/kubeadm/v1alpha2:go_default_library",
|
||||
"//cmd/kubeadm/app/constants:go_default_library",
|
||||
"//cmd/kubeadm/app/util:go_default_library",
|
||||
"//cmd/kubeadm/app/util/apiclient:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//cmd/kubeadm/app/util/config:go_default_library",
|
||||
"//pkg/apis/rbac/v1:go_default_library",
|
||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||
"//staging/src/k8s.io/api/rbac/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@ -43,12 +43,13 @@ go_test(
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
|
||||
"//cmd/kubeadm/app/apis/kubeadm/scheme:go_default_library",
|
||||
"//cmd/kubeadm/app/apis/kubeadm/v1alpha2:go_default_library",
|
||||
"//cmd/kubeadm/app/apis/kubeadm/v1beta1:go_default_library",
|
||||
"//cmd/kubeadm/app/constants:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes/fake:go_default_library",
|
||||
"//vendor/k8s.io/client-go/testing:go_default_library",
|
||||
"//cmd/kubeadm/app/util/config:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/testing:go_default_library",
|
||||
],
|
||||
)
|
||||
|
104
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/uploadconfig/uploadconfig.go
generated
vendored
104
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/uploadconfig/uploadconfig.go
generated
vendored
@ -20,43 +20,109 @@ import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
rbac "k8s.io/api/rbac/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/scheme"
|
||||
kubeadmscheme "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/scheme"
|
||||
kubeadmapiv1alpha2 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha2"
|
||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/util"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
|
||||
configutil "k8s.io/kubernetes/cmd/kubeadm/app/util/config"
|
||||
rbachelper "k8s.io/kubernetes/pkg/apis/rbac/v1"
|
||||
)
|
||||
|
||||
// UploadConfiguration saves the MasterConfiguration used for later reference (when upgrading for instance)
|
||||
func UploadConfiguration(cfg *kubeadmapi.MasterConfiguration, client clientset.Interface) error {
|
||||
const (
|
||||
// NodesKubeadmConfigClusterRoleName sets the name for the ClusterRole that allows
|
||||
// the bootstrap tokens to access the kubeadm-config ConfigMap during the node bootstrap/discovery
|
||||
// or during upgrade nodes
|
||||
NodesKubeadmConfigClusterRoleName = "kubeadm:nodes-kubeadm-config"
|
||||
)
|
||||
|
||||
fmt.Printf("[uploadconfig] storing the configuration used in ConfigMap %q in the %q Namespace\n", kubeadmconstants.MasterConfigurationConfigMap, metav1.NamespaceSystem)
|
||||
// UploadConfiguration saves the InitConfiguration used for later reference (when upgrading for instance)
|
||||
func UploadConfiguration(cfg *kubeadmapi.InitConfiguration, client clientset.Interface) error {
|
||||
fmt.Printf("[uploadconfig] storing the configuration used in ConfigMap %q in the %q Namespace\n", kubeadmconstants.KubeadmConfigConfigMap, metav1.NamespaceSystem)
|
||||
|
||||
// Convert cfg to the external version as that's the only version of the API that can be deserialized later
|
||||
externalcfg := &kubeadmapiv1alpha2.MasterConfiguration{}
|
||||
kubeadmscheme.Scheme.Convert(cfg, externalcfg, nil)
|
||||
// Prepare the ClusterConfiguration for upload
|
||||
// The components store their config in their own ConfigMaps, then reset the .ComponentConfig struct;
|
||||
// We don't want to mutate the cfg itself, so create a copy of it using .DeepCopy of it first
|
||||
clusterConfigurationToUpload := cfg.ClusterConfiguration.DeepCopy()
|
||||
clusterConfigurationToUpload.ComponentConfigs = kubeadmapi.ComponentConfigs{}
|
||||
|
||||
// Removes sensitive info from the data that will be stored in the config map
|
||||
externalcfg.BootstrapTokens = nil
|
||||
// Clear the NodeRegistration object.
|
||||
externalcfg.NodeRegistration = kubeadmapiv1alpha2.NodeRegistrationOptions{}
|
||||
|
||||
cfgYaml, err := util.MarshalToYamlForCodecs(externalcfg, kubeadmapiv1alpha2.SchemeGroupVersion, scheme.Codecs)
|
||||
// Marshal the ClusterConfiguration into YAML
|
||||
clusterConfigurationYaml, err := configutil.MarshalKubeadmConfigObject(clusterConfigurationToUpload)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return apiclient.CreateOrUpdateConfigMap(client, &v1.ConfigMap{
|
||||
// Prepare the ClusterStatus for upload
|
||||
// Gets the current cluster status
|
||||
// TODO: use configmap locks on this object on the get before the update.
|
||||
clusterStatus, err := configutil.GetClusterStatus(client)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Updates the ClusterStatus with the current control plane instance
|
||||
if clusterStatus.APIEndpoints == nil {
|
||||
clusterStatus.APIEndpoints = map[string]kubeadmapi.APIEndpoint{}
|
||||
}
|
||||
clusterStatus.APIEndpoints[cfg.NodeRegistration.Name] = cfg.LocalAPIEndpoint
|
||||
|
||||
// Marshal the ClusterStatus back into YAML
|
||||
clusterStatusYaml, err := configutil.MarshalKubeadmConfigObject(clusterStatus)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = apiclient.CreateOrUpdateConfigMap(client, &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: kubeadmconstants.MasterConfigurationConfigMap,
|
||||
Name: kubeadmconstants.KubeadmConfigConfigMap,
|
||||
Namespace: metav1.NamespaceSystem,
|
||||
},
|
||||
Data: map[string]string{
|
||||
kubeadmconstants.MasterConfigurationConfigMapKey: string(cfgYaml),
|
||||
kubeadmconstants.ClusterConfigurationConfigMapKey: string(clusterConfigurationYaml),
|
||||
kubeadmconstants.ClusterStatusConfigMapKey: string(clusterStatusYaml),
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Ensure that the NodesKubeadmConfigClusterRoleName exists
|
||||
err = apiclient.CreateOrUpdateRole(client, &rbac.Role{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: NodesKubeadmConfigClusterRoleName,
|
||||
Namespace: metav1.NamespaceSystem,
|
||||
},
|
||||
Rules: []rbac.PolicyRule{
|
||||
rbachelper.NewRule("get").Groups("").Resources("configmaps").Names(kubeadmconstants.KubeadmConfigConfigMap).RuleOrDie(),
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Binds the NodesKubeadmConfigClusterRoleName to all the bootstrap tokens
|
||||
// that are members of the system:bootstrappers:kubeadm:default-node-token group
|
||||
// and to all nodes
|
||||
return apiclient.CreateOrUpdateRoleBinding(client, &rbac.RoleBinding{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: NodesKubeadmConfigClusterRoleName,
|
||||
Namespace: metav1.NamespaceSystem,
|
||||
},
|
||||
RoleRef: rbac.RoleRef{
|
||||
APIGroup: rbac.GroupName,
|
||||
Kind: "Role",
|
||||
Name: NodesKubeadmConfigClusterRoleName,
|
||||
},
|
||||
Subjects: []rbac.Subject{
|
||||
{
|
||||
Kind: rbac.GroupKind,
|
||||
Name: kubeadmconstants.NodeBootstrapTokenAuthGroup,
|
||||
},
|
||||
{
|
||||
Kind: rbac.GroupKind,
|
||||
Name: kubeadmconstants.NodesGroup,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
83
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/uploadconfig/uploadconfig_test.go
generated
vendored
83
vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/uploadconfig/uploadconfig_test.go
generated
vendored
@ -17,6 +17,7 @@ limitations under the License.
|
||||
package uploadconfig
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
@ -26,8 +27,9 @@ import (
|
||||
core "k8s.io/client-go/testing"
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
kubeadmscheme "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/scheme"
|
||||
kubeadmapiv1alpha2 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha2"
|
||||
kubeadmapiv1beta1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta1"
|
||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
configutil "k8s.io/kubernetes/cmd/kubeadm/app/util/config"
|
||||
)
|
||||
|
||||
func TestUploadConfiguration(t *testing.T) {
|
||||
@ -61,22 +63,42 @@ func TestUploadConfiguration(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
cfg := &kubeadmapi.MasterConfiguration{
|
||||
KubernetesVersion: "v1.10.3",
|
||||
BootstrapTokens: []kubeadmapi.BootstrapToken{
|
||||
t.Run(tt.name, func(t2 *testing.T) {
|
||||
initialcfg := &kubeadmapiv1beta1.InitConfiguration{
|
||||
LocalAPIEndpoint: kubeadmapiv1beta1.APIEndpoint{
|
||||
AdvertiseAddress: "1.2.3.4",
|
||||
},
|
||||
ClusterConfiguration: kubeadmapiv1beta1.ClusterConfiguration{
|
||||
KubernetesVersion: "v1.12.10",
|
||||
},
|
||||
BootstrapTokens: []kubeadmapiv1beta1.BootstrapToken{
|
||||
{
|
||||
Token: &kubeadmapi.BootstrapTokenString{
|
||||
Token: &kubeadmapiv1beta1.BootstrapTokenString{
|
||||
ID: "abcdef",
|
||||
Secret: "abcdef0123456789",
|
||||
},
|
||||
},
|
||||
},
|
||||
NodeRegistration: kubeadmapi.NodeRegistrationOptions{
|
||||
NodeRegistration: kubeadmapiv1beta1.NodeRegistrationOptions{
|
||||
Name: "node-foo",
|
||||
CRISocket: "/var/run/custom-cri.sock",
|
||||
},
|
||||
}
|
||||
cfg, err := configutil.ConfigFileAndDefaultsToInternalConfig("", initialcfg)
|
||||
|
||||
// cleans up component config to make cfg and decodedcfg comparable (now component config are not stored anymore in kubeadm-config config map)
|
||||
cfg.ComponentConfigs = kubeadmapi.ComponentConfigs{}
|
||||
|
||||
if err != nil {
|
||||
t2.Fatalf("UploadConfiguration() error = %v", err)
|
||||
}
|
||||
|
||||
status := &kubeadmapi.ClusterStatus{
|
||||
APIEndpoints: map[string]kubeadmapi.APIEndpoint{
|
||||
"node-foo": cfg.LocalAPIEndpoint,
|
||||
},
|
||||
}
|
||||
|
||||
client := clientsetfake.NewSimpleClientset()
|
||||
if tt.errOnCreate != nil {
|
||||
client.PrependReactor("create", "configmaps", func(action core.Action) (bool, runtime.Object, error) {
|
||||
@ -85,7 +107,7 @@ func TestUploadConfiguration(t *testing.T) {
|
||||
}
|
||||
// For idempotent test, we check the result of the second call.
|
||||
if err := UploadConfiguration(cfg, client); !tt.updateExisting && (err != nil) != tt.errExpected {
|
||||
t.Errorf("UploadConfiguration() error = %v, wantErr %v", err, tt.errExpected)
|
||||
t2.Fatalf("UploadConfiguration() error = %v, wantErr %v", err, tt.errExpected)
|
||||
}
|
||||
if tt.updateExisting {
|
||||
if tt.errOnUpdate != nil {
|
||||
@ -94,49 +116,40 @@ func TestUploadConfiguration(t *testing.T) {
|
||||
})
|
||||
}
|
||||
if err := UploadConfiguration(cfg, client); (err != nil) != tt.errExpected {
|
||||
t.Errorf("UploadConfiguration() error = %v", err)
|
||||
t2.Fatalf("UploadConfiguration() error = %v", err)
|
||||
}
|
||||
}
|
||||
if tt.verifyResult {
|
||||
masterCfg, err := client.CoreV1().ConfigMaps(metav1.NamespaceSystem).Get(kubeadmconstants.MasterConfigurationConfigMap, metav1.GetOptions{})
|
||||
masterCfg, err := client.CoreV1().ConfigMaps(metav1.NamespaceSystem).Get(kubeadmconstants.KubeadmConfigConfigMap, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
t.Errorf("Fail to query ConfigMap error = %v", err)
|
||||
t2.Fatalf("Fail to query ConfigMap error = %v", err)
|
||||
}
|
||||
configData := masterCfg.Data[kubeadmconstants.MasterConfigurationConfigMapKey]
|
||||
configData := masterCfg.Data[kubeadmconstants.ClusterConfigurationConfigMapKey]
|
||||
if configData == "" {
|
||||
t.Errorf("Fail to find ConfigMap key")
|
||||
t2.Fatal("Fail to find ClusterConfigurationConfigMapKey key")
|
||||
}
|
||||
|
||||
decodedExtCfg := &kubeadmapiv1alpha2.MasterConfiguration{}
|
||||
decodedCfg := &kubeadmapi.MasterConfiguration{}
|
||||
|
||||
if err := runtime.DecodeInto(kubeadmscheme.Codecs.UniversalDecoder(), []byte(configData), decodedExtCfg); err != nil {
|
||||
t.Errorf("unable to decode config from bytes: %v", err)
|
||||
}
|
||||
// Default and convert to the internal version
|
||||
kubeadmscheme.Scheme.Default(decodedExtCfg)
|
||||
kubeadmscheme.Scheme.Convert(decodedExtCfg, decodedCfg, nil)
|
||||
|
||||
if decodedCfg.KubernetesVersion != cfg.KubernetesVersion {
|
||||
t.Errorf("Decoded value doesn't match, decoded = %#v, expected = %#v", decodedCfg.KubernetesVersion, cfg.KubernetesVersion)
|
||||
decodedCfg := &kubeadmapi.ClusterConfiguration{}
|
||||
if err := runtime.DecodeInto(kubeadmscheme.Codecs.UniversalDecoder(), []byte(configData), decodedCfg); err != nil {
|
||||
t2.Fatalf("unable to decode config from bytes: %v", err)
|
||||
}
|
||||
|
||||
// If the decoded cfg has a BootstrapTokens array, verify the sensitive information we had isn't still there.
|
||||
if len(decodedCfg.BootstrapTokens) > 0 && decodedCfg.BootstrapTokens[0].Token != nil && decodedCfg.BootstrapTokens[0].Token.String() == cfg.BootstrapTokens[0].Token.String() {
|
||||
t.Errorf("Decoded value contains .BootstrapTokens (sensitive info), decoded = %#v, expected = empty", decodedCfg.BootstrapTokens)
|
||||
if !reflect.DeepEqual(decodedCfg, &cfg.ClusterConfiguration) {
|
||||
t2.Errorf("the initial and decoded ClusterConfiguration didn't match")
|
||||
}
|
||||
|
||||
// Make sure no information from NodeRegistrationOptions was uploaded.
|
||||
if decodedCfg.NodeRegistration.Name == cfg.NodeRegistration.Name || decodedCfg.NodeRegistration.CRISocket != kubeadmapiv1alpha2.DefaultCRISocket {
|
||||
t.Errorf("Decoded value contains .NodeRegistration (node-specific info shouldn't be uploaded), decoded = %#v, expected = empty", decodedCfg.NodeRegistration)
|
||||
statusData := masterCfg.Data[kubeadmconstants.ClusterStatusConfigMapKey]
|
||||
if statusData == "" {
|
||||
t2.Fatal("failed to find ClusterStatusConfigMapKey key")
|
||||
}
|
||||
|
||||
if decodedExtCfg.Kind != "MasterConfiguration" {
|
||||
t.Errorf("Expected kind MasterConfiguration, got %v", decodedExtCfg.Kind)
|
||||
decodedStatus := &kubeadmapi.ClusterStatus{}
|
||||
if err := runtime.DecodeInto(kubeadmscheme.Codecs.UniversalDecoder(), []byte(statusData), decodedStatus); err != nil {
|
||||
t2.Fatalf("unable to decode status from bytes: %v", err)
|
||||
}
|
||||
|
||||
if decodedExtCfg.APIVersion != "kubeadm.k8s.io/v1alpha2" {
|
||||
t.Errorf("Expected apiVersion kubeadm.k8s.io/v1alpha2, got %v", decodedExtCfg.APIVersion)
|
||||
if !reflect.DeepEqual(decodedStatus, status) {
|
||||
t2.Error("the initial and decoded ClusterStatus didn't match")
|
||||
}
|
||||
}
|
||||
})
|
||||
|
Reference in New Issue
Block a user