vendor updates

This commit is contained in:
Serguei Bezverkhi
2018-03-06 17:33:18 -05:00
parent 4b3ebc171b
commit e9033989a0
5854 changed files with 248382 additions and 119809 deletions

View File

@ -44,7 +44,6 @@ filegroup(
"//cmd/kubeadm/app/phases/kubelet:all-srcs",
"//cmd/kubeadm/app/phases/markmaster:all-srcs",
"//cmd/kubeadm/app/phases/selfhosting:all-srcs",
"//cmd/kubeadm/app/phases/token:all-srcs",
"//cmd/kubeadm/app/phases/upgrade:all-srcs",
"//cmd/kubeadm/app/phases/uploadconfig:all-srcs",
"//cmd/kubeadm/app/preflight:all-srcs",

View File

@ -11,13 +11,13 @@ go_library(
"doc.go",
"register.go",
"types.go",
"well_known_labels.go",
"zz_generated.deepcopy.go",
],
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm",
deps = [
"//pkg/kubelet/apis/kubeletconfig/v1alpha1:go_default_library",
"//pkg/kubelet/apis/kubeletconfig/v1beta1:go_default_library",
"//pkg/proxy/apis/kubeproxyconfig/v1alpha1: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/apimachinery/pkg/runtime/schema:go_default_library",

View File

@ -11,7 +11,7 @@ go_library(
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/fuzzer",
deps = [
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
"//pkg/kubelet/apis/kubeletconfig/v1alpha1:go_default_library",
"//pkg/kubelet/apis/kubeletconfig/v1beta1:go_default_library",
"//pkg/proxy/apis/kubeproxyconfig/v1alpha1:go_default_library",
"//pkg/util/pointer:go_default_library",
"//vendor/github.com/google/gofuzz:go_default_library",

View File

@ -24,7 +24,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
kubeletconfigv1alpha1 "k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/v1alpha1"
kubeletconfigv1beta1 "k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/v1beta1"
kubeproxyconfigv1alpha1 "k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig/v1alpha1"
utilpointer "k8s.io/kubernetes/pkg/util/pointer"
)
@ -36,14 +36,19 @@ func Funcs(codecs runtimeserializer.CodecFactory) []interface{} {
c.FuzzNoCustom(obj)
obj.KubernetesVersion = "v10"
obj.API.BindPort = 20
obj.TokenTTL = &metav1.Duration{Duration: 1 * time.Hour}
obj.API.AdvertiseAddress = "foo"
obj.Networking.ServiceSubnet = "foo"
obj.Networking.DNSDomain = "foo"
obj.AuthorizationModes = []string{"foo"}
obj.CertificatesDir = "foo"
obj.APIServerCertSANs = []string{"foo"}
obj.Etcd.ServerCertSANs = []string{"foo"}
obj.Etcd.PeerCertSANs = []string{"foo"}
obj.Token = "foo"
obj.CRISocket = "foo"
obj.TokenTTL = &metav1.Duration{Duration: 1 * time.Hour}
obj.TokenUsages = []string{"foo"}
obj.TokenGroups = []string{"foo"}
obj.Etcd.Image = "foo"
obj.Etcd.DataDir = "foo"
obj.ImageRepository = "foo"
@ -64,22 +69,20 @@ func Funcs(codecs runtimeserializer.CodecFactory) []interface{} {
OperatorVersion: "v0.1.0",
}
obj.KubeletConfiguration = kubeadm.KubeletConfiguration{
BaseConfig: &kubeletconfigv1alpha1.KubeletConfiguration{
PodManifestPath: "foo",
AllowPrivileged: utilpointer.BoolPtr(true),
ClusterDNS: []string{"foo"},
ClusterDomain: "foo",
Authorization: kubeletconfigv1alpha1.KubeletAuthorization{Mode: "foo"},
Authentication: kubeletconfigv1alpha1.KubeletAuthentication{
X509: kubeletconfigv1alpha1.KubeletX509Authentication{ClientCAFile: "foo"},
BaseConfig: &kubeletconfigv1beta1.KubeletConfiguration{
StaticPodPath: "foo",
ClusterDNS: []string{"foo"},
ClusterDomain: "foo",
Authorization: kubeletconfigv1beta1.KubeletAuthorization{Mode: "foo"},
Authentication: kubeletconfigv1beta1.KubeletAuthentication{
X509: kubeletconfigv1beta1.KubeletX509Authentication{ClientCAFile: "foo"},
},
CAdvisorPort: utilpointer.Int32Ptr(0),
},
}
kubeletconfigv1alpha1.SetDefaults_KubeletConfiguration(obj.KubeletConfiguration.BaseConfig)
kubeletconfigv1beta1.SetDefaults_KubeletConfiguration(obj.KubeletConfiguration.BaseConfig)
obj.KubeProxy = kubeadm.KubeProxy{
Config: &kubeproxyconfigv1alpha1.KubeProxyConfiguration{
FeatureGates: "foo",
FeatureGates: map[string]bool{"foo": true},
BindAddress: "foo",
HealthzBindAddress: "foo:10256",
MetricsBindAddress: "foo:",
@ -112,16 +115,21 @@ func Funcs(codecs runtimeserializer.CodecFactory) []interface{} {
ConfigSyncPeriod: metav1.Duration{Duration: 1},
},
}
obj.AuditPolicyConfiguration = kubeadm.AuditPolicyConfiguration{
Path: "foo",
LogDir: "/foo",
LogMaxAge: utilpointer.Int32Ptr(0),
}
},
func(obj *kubeadm.NodeConfiguration, c fuzz.Continue) {
c.FuzzNoCustom(obj)
obj.CACertPath = "foo"
obj.CACertPath = "foo"
obj.DiscoveryFile = "foo"
obj.DiscoveryToken = "foo"
obj.DiscoveryTokenAPIServers = []string{"foo"}
obj.TLSBootstrapToken = "foo"
obj.Token = "foo"
obj.CRISocket = "foo"
},
}
}

View File

@ -39,8 +39,7 @@ filegroup(
go_test(
name = "go_default_test",
srcs = ["install_test.go"],
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/install",
library = ":go_default_library",
embed = [":go_default_library"],
deps = [
"//cmd/kubeadm/app/apis/kubeadm/fuzzer:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/testing/roundtrip:go_default_library",

View File

@ -17,8 +17,9 @@ limitations under the License.
package kubeadm
import (
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
kubeletconfigv1alpha1 "k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/v1alpha1"
kubeletconfigv1beta1 "k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/v1beta1"
kubeproxyconfigv1alpha1 "k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig/v1alpha1"
)
@ -29,87 +30,172 @@ import (
type MasterConfiguration struct {
metav1.TypeMeta
API API
KubeProxy KubeProxy
Etcd Etcd
// API holds configuration for the k8s apiserver.
API API
// KubeProxy holds configuration for the k8s service proxy.
KubeProxy KubeProxy
// Etcd holds configuration for etcd.
Etcd Etcd
// KubeletConfiguration holds configuration for the kubelet.
KubeletConfiguration KubeletConfiguration
Networking Networking
KubernetesVersion string
CloudProvider string
NodeName string
AuthorizationModes []string
// Networking holds configuration for the networking topology of the cluster.
Networking Networking
// KubernetesVersion is the target version of the control plane.
KubernetesVersion string
// CloudProvider is the name of the cloud provider.
CloudProvider string
// NodeName is the name of the node that will host the k8s control plane.
// Defaults to the hostname if not provided.
NodeName string
// AuthorizationModes is a set of authorization modes used inside the cluster.
// If not specified, defaults to Node and RBAC, meaning both the node
// authorizer and RBAC are enabled.
AuthorizationModes []string
// NoTaintMaster will, if set, suppress the tainting of the
// master node allowing workloads to be run on it (e.g. in
// single node configurations).
NoTaintMaster bool
Token string
// Mark the controller and api server pods as privileged as some cloud
// controllers like openstack need escalated privileges under some conditions
// example - loading a config drive to fetch node information.
PrivilegedPods bool
// Token is used for establishing bidirectional trust between nodes and masters.
// Used for joining nodes in the cluster.
Token string
// TokenTTL defines the ttl for Token. Defaults to 24h.
TokenTTL *metav1.Duration
// TokenUsages describes the ways in which this token can be used.
TokenUsages []string
// Extra groups that this token will authenticate as when used for authentication
TokenGroups []string
APIServerExtraArgs map[string]string
// CRISocket is used to retrieve container runtime info.
CRISocket string
// APIServerExtraArgs is a set of extra flags to pass to the API Server or override
// default ones in form of <flagname>=<value>.
// TODO: This is temporary and ideally we would like to switch all components to
// use ComponentConfig + ConfigMaps.
APIServerExtraArgs map[string]string
// ControllerManagerExtraArgs is a set of extra flags to pass to the Controller Manager
// or override default ones in form of <flagname>=<value>
// TODO: This is temporary and ideally we would like to switch all components to
// use ComponentConfig + ConfigMaps.
ControllerManagerExtraArgs map[string]string
SchedulerExtraArgs map[string]string
// SchedulerExtraArgs is a set of extra flags to pass to the Scheduler or override
// default ones in form of <flagname>=<value>
// TODO: This is temporary and ideally we would like to switch all components to
// use ComponentConfig + ConfigMaps.
SchedulerExtraArgs map[string]string
APIServerExtraVolumes []HostPathMount
// APIServerExtraVolumes is an extra set of host volumes mounted to the API server.
APIServerExtraVolumes []HostPathMount
// ControllerManagerExtraVolumes is an extra set of host volumes mounted to the
// Controller Manager.
ControllerManagerExtraVolumes []HostPathMount
SchedulerExtraVolumes []HostPathMount
// SchedulerExtraVolumes is an extra set of host volumes mounted to the scheduler.
SchedulerExtraVolumes []HostPathMount
// APIServerCertSANs sets extra Subject Alternative Names for the API Server signing cert
// APIServerCertSANs sets extra Subject Alternative Names for the API Server
// signing cert.
APIServerCertSANs []string
// CertificatesDir specifies where to store or look for all required certificates
// CertificatesDir specifies where to store or look for all required certificates.
CertificatesDir string
// ImageRepository what container registry to pull control plane images from
// ImagePullPolicy for control plane images. Can be Always, IfNotPresent or Never.
ImagePullPolicy v1.PullPolicy
// ImageRepository is the container registry to pull control plane images from.
ImageRepository string
// Container registry for core images generated by CI
// CIImageRepository is the container registry for core images generated by CI.
// Useful for running kubeadm with images from CI builds.
// +k8s:conversion-gen=false
CIImageRepository string
// UnifiedControlPlaneImage specifies if a specific container image should be used for all control plane components
// UnifiedControlPlaneImage specifies if a specific container image should be
// used for all control plane components.
UnifiedControlPlaneImage string
// FeatureGates enabled by the user
// AuditPolicyConfiguration defines the options for the api server audit system.
AuditPolicyConfiguration AuditPolicyConfiguration
// FeatureGates enabled by the user.
FeatureGates map[string]bool
}
// API struct contains elements of API server address.
type API struct {
// AdvertiseAddress sets the address for the API server to advertise.
// AdvertiseAddress sets the IP address for the API server to advertise.
AdvertiseAddress string
// BindPort sets the secure port for the API Server to bind to
// ControlPlaneEndpoint sets the DNS address for the API server
ControlPlaneEndpoint string
// BindPort sets the secure port for the API Server to bind to.
// Defaults to 6443.
BindPort int32
}
// TokenDiscovery contains elements needed for token discovery
// TokenDiscovery contains elements needed for token discovery.
type TokenDiscovery struct {
ID string
Secret string
Addresses []string
// ID is the first part of a bootstrap token. Considered public information.
// It is used when referring to a token without leaking the secret part.
ID string
// Secret is the second part of a bootstrap token. Should only be shared
// with trusted parties.
Secret string
// TODO: Seems unused. Remove?
// Addresses []string
}
// Networking contains elements describing cluster's networking configuration
// Networking contains elements describing cluster's networking configuration.
type Networking struct {
// ServiceSubnet is the subnet used by k8s services. Defaults to "10.96.0.0/12".
ServiceSubnet string
PodSubnet string
DNSDomain string
// PodSubnet is the subnet used by pods.
PodSubnet string
// DNSDomain is the dns domain used by k8s services. Defaults to "cluster.local".
DNSDomain string
}
// Etcd contains elements describing Etcd configuration
// Etcd contains elements describing Etcd configuration.
type Etcd struct {
// Endpoints of etcd members. Useful for using external etcd.
// If not provided, kubeadm will run etcd in a static pod.
Endpoints []string
CAFile string
CertFile string
KeyFile string
DataDir string
// CAFile is an SSL Certificate Authority file used to secure etcd communication.
CAFile string
// CertFile is an SSL certification file used to secure etcd communication.
CertFile string
// KeyFile is an SSL key file used to secure etcd communication.
KeyFile string
// DataDir is the directory etcd will place its data.
// Defaults to "/var/lib/etcd".
DataDir string
// ExtraArgs are extra arguments provided to the etcd binary
// when run inside a static pod.
ExtraArgs map[string]string
// Image specifies which container image to use for running etcd. If empty, automatically populated by kubeadm using the image repository and default etcd version
Image string
// Image specifies which container image to use for running etcd.
// If empty, automatically populated by kubeadm using the image
// repository and default etcd version.
Image string
// SelfHosted holds configuration for self-hosting etcd.
SelfHosted *SelfHostedEtcd
// ServerCertSANs sets extra Subject Alternative Names for the etcd server
// signing cert. This is currently used for the etcd static-pod.
ServerCertSANs []string
// PeerCertSANs sets extra Subject Alternative Names for the etcd peer
// signing cert. This is currently used for the etcd static-pod.
PeerCertSANs []string
}
// SelfHostedEtcd describes options required to configure self-hosted etcd
// SelfHostedEtcd describes options required to configure self-hosted etcd.
type SelfHostedEtcd struct {
// CertificatesDir represents the directory where all etcd TLS assets are stored. By default this is
// a dir names "etcd" in the main CertificatesDir value.
// CertificatesDir represents the directory where all etcd TLS assets are stored.
// Defaults to "/etc/kubernetes/pki/etcd".
CertificatesDir string
// ClusterServiceName is the name of the service that load balances the etcd cluster
// ClusterServiceName is the name of the service that load balances the etcd cluster.
ClusterServiceName string
// EtcdVersion is the version of etcd running in the cluster.
EtcdVersion string
@ -119,18 +205,35 @@ type SelfHostedEtcd struct {
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// NodeConfiguration contains elements describing a particular node
// NodeConfiguration contains elements describing a particular node.
// TODO: This struct should be replaced by dynamic kubelet configuration.
type NodeConfiguration struct {
metav1.TypeMeta
CACertPath string
DiscoveryFile string
// CACertPath is the path to the SSL certificate authority used to
// secure comunications between node and master.
// Defaults to "/etc/kubernetes/pki/ca.crt".
CACertPath string
// DiscoveryFile is a file or url to a kubeconfig file from which to
// load cluster information.
DiscoveryFile string
// DiscoveryToken is a token used to validate cluster information
// fetched from the master.
DiscoveryToken string
// Currently we only pay attention to one api server but hope to support >1 in the future
// DiscoveryTokenAPIServers is a set of IPs to API servers from which info
// will be fetched. Currently we only pay attention to one API server but
// hope to support >1 in the future.
DiscoveryTokenAPIServers []string
NodeName string
TLSBootstrapToken string
Token string
// NodeName is the name of the node to join the cluster. Defaults
// to the name of the host.
NodeName string
// TLSBootstrapToken is a token used for TLS bootstrapping.
// Defaults to Token.
TLSBootstrapToken string
// Token is used for both discovery and TLS bootstrapping.
Token string
// CRISocket is used to retrieve container runtime info.
CRISocket string
// DiscoveryTokenCACertHashes specifies a set of public key pins to verify
// when token-based discovery is used. The root CA found during discovery
@ -147,13 +250,13 @@ type NodeConfiguration struct {
// the security of kubeadm since other nodes can impersonate the master.
DiscoveryTokenUnsafeSkipCAVerification bool
// FeatureGates enabled by the user
// FeatureGates enabled by the user.
FeatureGates map[string]bool
}
// KubeletConfiguration contains elements describing initial remote configuration of kubelet
// KubeletConfiguration contains elements describing initial remote configuration of kubelet.
type KubeletConfiguration struct {
BaseConfig *kubeletconfigv1alpha1.KubeletConfiguration
BaseConfig *kubeletconfigv1beta1.KubeletConfiguration
}
// GetControlPlaneImageRepository returns name of image repository
@ -169,14 +272,29 @@ func (cfg *MasterConfiguration) GetControlPlaneImageRepository() string {
}
// HostPathMount contains elements describing volumes that are mounted from the
// host
// host.
type HostPathMount struct {
Name string
HostPath string
// Name of the volume inside the pod template.
Name string
// HostPath is the path in the host that will be mounted inside
// the pod.
HostPath string
// MountPath is the path inside the pod where hostPath will be mounted.
MountPath string
}
// KubeProxy contains elements describing the proxy configuration
// KubeProxy contains elements describing the proxy configuration.
type KubeProxy struct {
Config *kubeproxyconfigv1alpha1.KubeProxyConfiguration
}
// AuditPolicyConfiguration holds the options for configuring the api server audit policy.
type AuditPolicyConfiguration struct {
// Path is the local path to an audit policy.
Path string
// LogDir is the local path to the directory where logs should be stored.
LogDir string
// LogMaxAge is the number of days logs will be stored for. 0 indicates forever.
LogMaxAge *int32
//TODO(chuckha) add other options for audit policy.
}

View File

@ -4,7 +4,6 @@ go_library(
name = "go_default_library",
srcs = [
"defaults.go",
"defaults_unix.go",
"doc.go",
"register.go",
"types.go",
@ -12,7 +11,37 @@ go_library(
"zz_generated.deepcopy.go",
"zz_generated.defaults.go",
] + select({
"@io_bazel_rules_go//go/platform:windows_amd64": [
"@io_bazel_rules_go//go/platform:android": [
"defaults_unix.go",
],
"@io_bazel_rules_go//go/platform:darwin": [
"defaults_unix.go",
],
"@io_bazel_rules_go//go/platform:dragonfly": [
"defaults_unix.go",
],
"@io_bazel_rules_go//go/platform:freebsd": [
"defaults_unix.go",
],
"@io_bazel_rules_go//go/platform:linux": [
"defaults_unix.go",
],
"@io_bazel_rules_go//go/platform:nacl": [
"defaults_unix.go",
],
"@io_bazel_rules_go//go/platform:netbsd": [
"defaults_unix.go",
],
"@io_bazel_rules_go//go/platform:openbsd": [
"defaults_unix.go",
],
"@io_bazel_rules_go//go/platform:plan9": [
"defaults_unix.go",
],
"@io_bazel_rules_go//go/platform:solaris": [
"defaults_unix.go",
],
"@io_bazel_rules_go//go/platform:windows": [
"defaults_windows.go",
],
"//conditions:default": [],
@ -24,10 +53,10 @@ go_library(
"//cmd/kubeadm/app/constants:go_default_library",
"//cmd/kubeadm/app/features:go_default_library",
"//pkg/kubelet/apis/kubeletconfig/scheme:go_default_library",
"//pkg/kubelet/apis/kubeletconfig/v1alpha1:go_default_library",
"//pkg/kubelet/apis/kubeletconfig/v1beta1:go_default_library",
"//pkg/proxy/apis/kubeproxyconfig/scheme:go_default_library",
"//pkg/proxy/apis/kubeproxyconfig/v1alpha1:go_default_library",
"//pkg/util/pointer: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/conversion:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",

View File

@ -25,10 +25,9 @@ import (
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
"k8s.io/kubernetes/cmd/kubeadm/app/features"
kubeletscheme "k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/scheme"
kubeletconfigv1alpha1 "k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/v1alpha1"
kubeletconfigv1beta1 "k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/v1beta1"
kubeproxyscheme "k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig/scheme"
kubeproxyconfigv1alpha1 "k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig/v1alpha1"
utilpointer "k8s.io/kubernetes/pkg/util/pointer"
)
const (
@ -47,9 +46,11 @@ const (
// DefaultCertificatesDir defines default certificate directory
DefaultCertificatesDir = "/etc/kubernetes/pki"
// DefaultImageRepository defines default image registry
DefaultImageRepository = "gcr.io/google_containers"
DefaultImageRepository = "k8s.gcr.io"
// DefaultManifestsDir defines default manifests directory
DefaultManifestsDir = "/etc/kubernetes/manifests"
// DefaultCRISocket defines the default cri socket
DefaultCRISocket = "/var/run/dockershim.sock"
// DefaultEtcdDataDir defines default location of etcd where static pods will save data to
DefaultEtcdDataDir = "/var/lib/etcd"
@ -65,10 +66,16 @@ const (
DefaultProxyBindAddressv4 = "0.0.0.0"
// DefaultProxyBindAddressv6 is the default bind address when the advertise address is v6
DefaultProxyBindAddressv6 = "::"
// KubeproxyKubeConfigFileName efines the file name for the kube-proxy's KubeConfig file
// KubeproxyKubeConfigFileName defines the file name for the kube-proxy's KubeConfig file
KubeproxyKubeConfigFileName = "/var/lib/kube-proxy/kubeconfig.conf"
)
var (
// DefaultAuditPolicyLogMaxAge is defined as a var so its address can be taken
// It is the number of days to store audit logs
DefaultAuditPolicyLogMaxAge = int32(2)
)
func addDefaultingFuncs(scheme *runtime.Scheme) error {
return RegisterDefaults(scheme)
}
@ -105,6 +112,18 @@ func SetDefaults_MasterConfiguration(obj *MasterConfiguration) {
}
}
if obj.CRISocket == "" {
obj.CRISocket = DefaultCRISocket
}
if len(obj.TokenUsages) == 0 {
obj.TokenUsages = constants.DefaultTokenUsages
}
if len(obj.TokenGroups) == 0 {
obj.TokenGroups = constants.DefaultTokenGroups
}
if obj.ImageRepository == "" {
obj.ImageRepository = DefaultImageRepository
}
@ -118,6 +137,7 @@ func SetDefaults_MasterConfiguration(obj *MasterConfiguration) {
SetDefaults_KubeletConfiguration(obj)
}
SetDefaults_ProxyConfiguration(obj)
SetDefaults_AuditPolicyConfiguration(obj)
}
// SetDefaults_ProxyConfiguration assigns default values for the Proxy
@ -147,6 +167,9 @@ func SetDefaults_NodeConfiguration(obj *NodeConfiguration) {
if len(obj.DiscoveryToken) == 0 && len(obj.DiscoveryFile) == 0 {
obj.DiscoveryToken = obj.Token
}
if obj.CRISocket == "" {
obj.CRISocket = DefaultCRISocket
}
// Make sure file URLs become paths
if len(obj.DiscoveryFile) != 0 {
u, err := url.Parse(obj.DiscoveryFile)
@ -180,13 +203,10 @@ func SetDefaultsEtcdSelfHosted(obj *MasterConfiguration) {
// SetDefaults_KubeletConfiguration assigns default values to kubelet
func SetDefaults_KubeletConfiguration(obj *MasterConfiguration) {
if obj.KubeletConfiguration.BaseConfig == nil {
obj.KubeletConfiguration.BaseConfig = &kubeletconfigv1alpha1.KubeletConfiguration{}
obj.KubeletConfiguration.BaseConfig = &kubeletconfigv1beta1.KubeletConfiguration{}
}
if obj.KubeletConfiguration.BaseConfig.PodManifestPath == "" {
obj.KubeletConfiguration.BaseConfig.PodManifestPath = DefaultManifestsDir
}
if obj.KubeletConfiguration.BaseConfig.AllowPrivileged == nil {
obj.KubeletConfiguration.BaseConfig.AllowPrivileged = utilpointer.BoolPtr(true)
if obj.KubeletConfiguration.BaseConfig.StaticPodPath == "" {
obj.KubeletConfiguration.BaseConfig.StaticPodPath = DefaultManifestsDir
}
if obj.KubeletConfiguration.BaseConfig.ClusterDNS == nil {
dnsIP, err := constants.GetDNSIP(obj.Networking.ServiceSubnet)
@ -200,17 +220,24 @@ func SetDefaults_KubeletConfiguration(obj *MasterConfiguration) {
obj.KubeletConfiguration.BaseConfig.ClusterDomain = DefaultServiceDNSDomain
}
if obj.KubeletConfiguration.BaseConfig.Authorization.Mode == "" {
obj.KubeletConfiguration.BaseConfig.Authorization.Mode = kubeletconfigv1alpha1.KubeletAuthorizationModeWebhook
obj.KubeletConfiguration.BaseConfig.Authorization.Mode = kubeletconfigv1beta1.KubeletAuthorizationModeWebhook
}
if obj.KubeletConfiguration.BaseConfig.Authentication.X509.ClientCAFile == "" {
obj.KubeletConfiguration.BaseConfig.Authentication.X509.ClientCAFile = DefaultCACertPath
}
if obj.KubeletConfiguration.BaseConfig.CAdvisorPort == nil {
obj.KubeletConfiguration.BaseConfig.CAdvisorPort = utilpointer.Int32Ptr(0)
}
scheme, _, _ := kubeletscheme.NewSchemeAndCodecs()
if scheme != nil {
scheme.Default(obj.KubeletConfiguration.BaseConfig)
}
}
// SetDefaults_AuditPolicyConfiguration sets default values for the AuditPolicyConfiguration
func SetDefaults_AuditPolicyConfiguration(obj *MasterConfiguration) {
if obj.AuditPolicyConfiguration.LogDir == "" {
obj.AuditPolicyConfiguration.LogDir = constants.StaticPodAuditPolicyLogDir
}
if obj.AuditPolicyConfiguration.LogMaxAge == nil {
obj.AuditPolicyConfiguration.LogMaxAge = &DefaultAuditPolicyLogMaxAge
}
}

View File

@ -17,8 +17,9 @@ limitations under the License.
package v1alpha1
import (
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
kubeletconfigv1alpha1 "k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/v1alpha1"
kubeletconfigv1beta1 "k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/v1beta1"
kubeproxyconfigv1alpha1 "k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig/v1alpha1"
)
@ -29,82 +30,162 @@ import (
type MasterConfiguration struct {
metav1.TypeMeta `json:",inline"`
API API `json:"api"`
KubeProxy KubeProxy `json:"kubeProxy"`
Etcd Etcd `json:"etcd"`
// API holds configuration for the k8s apiserver.
API API `json:"api"`
// KubeProxy holds configuration for the k8s service proxy.
KubeProxy KubeProxy `json:"kubeProxy"`
// Etcd holds configuration for etcd.
Etcd Etcd `json:"etcd"`
// KubeletConfiguration holds configuration for the kubelet.
KubeletConfiguration KubeletConfiguration `json:"kubeletConfiguration"`
Networking Networking `json:"networking"`
KubernetesVersion string `json:"kubernetesVersion"`
CloudProvider string `json:"cloudProvider"`
NodeName string `json:"nodeName"`
AuthorizationModes []string `json:"authorizationModes,omitempty"`
// Networking holds configuration for the networking topology of the cluster.
Networking Networking `json:"networking"`
// KubernetesVersion is the target version of the control plane.
KubernetesVersion string `json:"kubernetesVersion"`
// CloudProvider is the name of the cloud provider.
CloudProvider string `json:"cloudProvider"`
// NodeName is the name of the node that will host the k8s control plane.
// Defaults to the hostname if not provided.
NodeName string `json:"nodeName"`
// AuthorizationModes is a set of authorization modes used inside the cluster.
// If not specified, defaults to Node and RBAC, meaning both the node
// authorizer and RBAC are enabled.
AuthorizationModes []string `json:"authorizationModes,omitempty"`
// NoTaintMaster will, if set, suppress the tainting of the
// master node allowing workloads to be run on it (e.g. in
// single node configurations).
NoTaintMaster bool `json:"noTaintMaster,omitempty"`
Token string `json:"token"`
// Mark the controller and api server pods as privileged as some cloud
// controllers like openstack need escalated privileges under some conditions
// example - loading a config drive to fetch node information
PrivilegedPods bool `json:"privilegedPods"`
// Token is used for establishing bidirectional trust between nodes and masters.
// Used for joining nodes in the cluster.
Token string `json:"token"`
// TokenTTL defines the ttl for Token. Defaults to 24h.
TokenTTL *metav1.Duration `json:"tokenTTL,omitempty"`
// TokenUsages describes the ways in which this token can be used.
TokenUsages []string `json:"tokenUsages,omitempty"`
// Extra groups that this token will authenticate as when used for authentication
TokenGroups []string `json:"tokenGroups,omitempty"`
APIServerExtraArgs map[string]string `json:"apiServerExtraArgs,omitempty"`
// CRISocket is used to retrieve container runtime info.
CRISocket string `json:"criSocket,omitempty"`
// APIServerExtraArgs is a set of extra flags to pass to the API Server or override
// default ones in form of <flagname>=<value>.
// TODO: This is temporary and ideally we would like to switch all components to
// use ComponentConfig + ConfigMaps.
APIServerExtraArgs map[string]string `json:"apiServerExtraArgs,omitempty"`
// ControllerManagerExtraArgs is a set of extra flags to pass to the Controller Manager
// or override default ones in form of <flagname>=<value>
// TODO: This is temporary and ideally we would like to switch all components to
// use ComponentConfig + ConfigMaps.
ControllerManagerExtraArgs map[string]string `json:"controllerManagerExtraArgs,omitempty"`
SchedulerExtraArgs map[string]string `json:"schedulerExtraArgs,omitempty"`
// SchedulerExtraArgs is a set of extra flags to pass to the Scheduler or override
// default ones in form of <flagname>=<value>
// TODO: This is temporary and ideally we would like to switch all components to
// use ComponentConfig + ConfigMaps.
SchedulerExtraArgs map[string]string `json:"schedulerExtraArgs,omitempty"`
APIServerExtraVolumes []HostPathMount `json:"apiServerExtraVolumes,omitempty"`
// APIServerExtraVolumes is an extra set of host volumes mounted to the API server.
APIServerExtraVolumes []HostPathMount `json:"apiServerExtraVolumes,omitempty"`
// ControllerManagerExtraVolumes is an extra set of host volumes mounted to the
// Controller Manager.
ControllerManagerExtraVolumes []HostPathMount `json:"controllerManagerExtraVolumes,omitempty"`
SchedulerExtraVolumes []HostPathMount `json:"schedulerExtraVolumes,omitempty"`
// SchedulerExtraVolumes is an extra set of host volumes mounted to the scheduler.
SchedulerExtraVolumes []HostPathMount `json:"schedulerExtraVolumes,omitempty"`
// APIServerCertSANs sets extra Subject Alternative Names for the API Server signing cert
// APIServerCertSANs sets extra Subject Alternative Names for the API Server signing cert.
APIServerCertSANs []string `json:"apiServerCertSANs,omitempty"`
// CertificatesDir specifies where to store or look for all required certificates
// CertificatesDir specifies where to store or look for all required certificates.
CertificatesDir string `json:"certificatesDir"`
// ImageRepository what container registry to pull control plane images from
ImageRepository string `json:"imageRepository"`
// UnifiedControlPlaneImage specifies if a specific container image should be used for all control plane components
// ImagePullPolicy that control plane images. Can be Always, IfNotPresent or Never.
ImagePullPolicy v1.PullPolicy `json:"imagePullPolicy,omitempty"`
// UnifiedControlPlaneImage specifies if a specific container image should
// be used for all control plane components.
UnifiedControlPlaneImage string `json:"unifiedControlPlaneImage"`
// FeatureGates enabled by the user
// AuditPolicyConfiguration defines the options for the api server audit system
AuditPolicyConfiguration AuditPolicyConfiguration `json:"auditPolicy"`
// FeatureGates enabled by the user.
FeatureGates map[string]bool `json:"featureGates,omitempty"`
}
// API struct contains elements of API server address.
type API struct {
// AdvertiseAddress sets the address for the API server to advertise.
// AdvertiseAddress sets the IP address for the API server to advertise.
AdvertiseAddress string `json:"advertiseAddress"`
// BindPort sets the secure port for the API Server to bind to
// ControlPlaneEndpoint sets the DNS address for the API server
ControlPlaneEndpoint string `json:"controlPlaneEndpoint"`
// BindPort sets the secure port for the API Server to bind to.
// Defaults to 6443.
BindPort int32 `json:"bindPort"`
}
// TokenDiscovery contains elements needed for token discovery
// TokenDiscovery contains elements needed for token discovery.
type TokenDiscovery struct {
ID string `json:"id"`
Secret string `json:"secret"`
Addresses []string `json:"addresses"`
// ID is the first part of a bootstrap token. Considered public information.
// It is used when referring to a token without leaking the secret part.
ID string `json:"id"`
// Secret is the second part of a bootstrap token. Should only be shared
// with trusted parties.
Secret string `json:"secret"`
// TODO: Seems unused. Remove?
// Addresses []string `json:"addresses"`
}
// Networking contains elements describing cluster's networking configuration
type Networking struct {
// ServiceSubnet is the subnet used by k8s services. Defaults to "10.96.0.0/12".
ServiceSubnet string `json:"serviceSubnet"`
PodSubnet string `json:"podSubnet"`
DNSDomain string `json:"dnsDomain"`
// PodSubnet is the subnet used by pods.
PodSubnet string `json:"podSubnet"`
// DNSDomain is the dns domain used by k8s services. Defaults to "cluster.local".
DNSDomain string `json:"dnsDomain"`
}
// Etcd contains elements describing Etcd configuration
// Etcd contains elements describing Etcd configuration.
type Etcd struct {
Endpoints []string `json:"endpoints"`
CAFile string `json:"caFile"`
CertFile string `json:"certFile"`
KeyFile string `json:"keyFile"`
DataDir string `json:"dataDir"`
// Endpoints of etcd members. Useful for using external etcd.
// If not provided, kubeadm will run etcd in a static pod.
Endpoints []string `json:"endpoints"`
// CAFile is an SSL Certificate Authority file used to secure etcd communication.
CAFile string `json:"caFile"`
// CertFile is an SSL certification file used to secure etcd communication.
CertFile string `json:"certFile"`
// KeyFile is an SSL key file used to secure etcd communication.
KeyFile string `json:"keyFile"`
// DataDir is the directory etcd will place its data.
// Defaults to "/var/lib/etcd".
DataDir string `json:"dataDir"`
// ExtraArgs are extra arguments provided to the etcd binary
// when run inside a static pod.
ExtraArgs map[string]string `json:"extraArgs,omitempty"`
// Image specifies which container image to use for running etcd. If empty, automatically populated by kubeadm using the image repository and default etcd version
Image string `json:"image"`
// Image specifies which container image to use for running etcd.
// If empty, automatically populated by kubeadm using the image
// repository and default etcd version.
Image string `json:"image"`
// SelfHosted holds configuration for self-hosting etcd.
SelfHosted *SelfHostedEtcd `json:"selfHosted,omitempty"`
// ServerCertSANs sets extra Subject Alternative Names for the etcd server signing cert.
ServerCertSANs []string `json:"serverCertSANs,omitempty"`
// PeerCertSANs sets extra Subject Alternative Names for the etcd peer signing cert.
PeerCertSANs []string `json:"peerCertSANs,omitempty"`
}
// SelfHostedEtcd describes options required to configure self-hosted etcd
// SelfHostedEtcd describes options required to configure self-hosted etcd.
type SelfHostedEtcd struct {
// CertificatesDir represents the directory where all etcd TLS assets are stored. By default this is
// a dir names "etcd" in the main CertificatesDir value.
// CertificatesDir represents the directory where all etcd TLS assets are stored.
// Defaults to "/etc/kubernetes/pki/etcd".
CertificatesDir string `json:"certificatesDir"`
// ClusterServiceName is the name of the service that load balances the etcd cluster
// ClusterServiceName is the name of the service that load balances the etcd cluster.
ClusterServiceName string `json:"clusterServiceName"`
// EtcdVersion is the version of etcd running in the cluster.
EtcdVersion string `json:"etcdVersion"`
@ -114,17 +195,35 @@ type SelfHostedEtcd struct {
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// NodeConfiguration contains elements describing a particular node
// NodeConfiguration contains elements describing a particular node.
// TODO: This struct should be replaced by dynamic kubelet configuration.
type NodeConfiguration struct {
metav1.TypeMeta `json:",inline"`
CACertPath string `json:"caCertPath"`
DiscoveryFile string `json:"discoveryFile"`
DiscoveryToken string `json:"discoveryToken"`
// CACertPath is the path to the SSL certificate authority used to
// secure comunications between node and master.
// Defaults to "/etc/kubernetes/pki/ca.crt".
CACertPath string `json:"caCertPath"`
// DiscoveryFile is a file or url to a kubeconfig file from which to
// load cluster information.
DiscoveryFile string `json:"discoveryFile"`
// DiscoveryToken is a token used to validate cluster information
// fetched from the master.
DiscoveryToken string `json:"discoveryToken"`
// DiscoveryTokenAPIServers is a set of IPs to API servers from which info
// will be fetched. Currently we only pay attention to one API server but
// hope to support >1 in the future.
DiscoveryTokenAPIServers []string `json:"discoveryTokenAPIServers,omitempty"`
NodeName string `json:"nodeName"`
TLSBootstrapToken string `json:"tlsBootstrapToken"`
Token string `json:"token"`
// NodeName is the name of the node to join the cluster. Defaults
// to the name of the host.
NodeName string `json:"nodeName"`
// TLSBootstrapToken is a token used for TLS bootstrapping.
// Defaults to Token.
TLSBootstrapToken string `json:"tlsBootstrapToken"`
// Token is used for both discovery and TLS bootstrapping.
Token string `json:"token"`
// CRISocket is used to retrieve container runtime info.
CRISocket string `json:"criSocket,omitempty"`
// DiscoveryTokenCACertHashes specifies a set of public key pins to verify
// when token-based discovery is used. The root CA found during discovery
@ -141,24 +240,39 @@ type NodeConfiguration struct {
// the security of kubeadm since other nodes can impersonate the master.
DiscoveryTokenUnsafeSkipCAVerification bool `json:"discoveryTokenUnsafeSkipCAVerification"`
// FeatureGates enabled by the user
// FeatureGates enabled by the user.
FeatureGates map[string]bool `json:"featureGates,omitempty"`
}
// KubeletConfiguration contains elements describing initial remote configuration of kubelet
// KubeletConfiguration contains elements describing initial remote configuration of kubelet.
type KubeletConfiguration struct {
BaseConfig *kubeletconfigv1alpha1.KubeletConfiguration `json:"baseConfig,omitempty"`
BaseConfig *kubeletconfigv1beta1.KubeletConfiguration `json:"baseConfig,omitempty"`
}
// HostPathMount contains elements describing volumes that are mounted from the
// host
// host.
type HostPathMount struct {
Name string `json:"name"`
HostPath string `json:"hostPath"`
// Name of the volume inside the pod template.
Name string `json:"name"`
// HostPath is the path in the host that will be mounted inside
// the pod.
HostPath string `json:"hostPath"`
// MountPath is the path inside the pod where hostPath will be mounted.
MountPath string `json:"mountPath"`
}
// KubeProxy contains elements describing the proxy configuration
// KubeProxy contains elements describing the proxy configuration.
type KubeProxy struct {
Config *kubeproxyconfigv1alpha1.KubeProxyConfiguration `json:"config,omitempty"`
}
// AuditPolicyConfiguration holds the options for configuring the api server audit policy.
type AuditPolicyConfiguration struct {
// Path is the local path to an audit policy.
Path string `json:"path"`
// LogDir is the local path to the directory where logs should be stored.
LogDir string `json:"logDir"`
// LogMaxAge is the number of days logs will be stored for. 0 indicates forever.
LogMaxAge *int32 `json:"logMaxAge,omitempty"`
//TODO(chuckha) add other options for audit policy.
}

View File

@ -16,18 +16,20 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
// This file was autogenerated by conversion-gen. Do not edit it manually!
// Code generated by conversion-gen. DO NOT EDIT.
package v1alpha1
import (
unsafe "unsafe"
core_v1 "k8s.io/api/core/v1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
conversion "k8s.io/apimachinery/pkg/conversion"
runtime "k8s.io/apimachinery/pkg/runtime"
kubeadm "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
kubeletconfig_v1alpha1 "k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/v1alpha1"
v1beta1 "k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/v1beta1"
kubeproxyconfig_v1alpha1 "k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig/v1alpha1"
unsafe "unsafe"
)
func init() {
@ -40,6 +42,8 @@ func RegisterConversions(scheme *runtime.Scheme) error {
return scheme.AddGeneratedConversionFuncs(
Convert_v1alpha1_API_To_kubeadm_API,
Convert_kubeadm_API_To_v1alpha1_API,
Convert_v1alpha1_AuditPolicyConfiguration_To_kubeadm_AuditPolicyConfiguration,
Convert_kubeadm_AuditPolicyConfiguration_To_v1alpha1_AuditPolicyConfiguration,
Convert_v1alpha1_Etcd_To_kubeadm_Etcd,
Convert_kubeadm_Etcd_To_v1alpha1_Etcd,
Convert_v1alpha1_HostPathMount_To_kubeadm_HostPathMount,
@ -63,6 +67,7 @@ func RegisterConversions(scheme *runtime.Scheme) error {
func autoConvert_v1alpha1_API_To_kubeadm_API(in *API, out *kubeadm.API, s conversion.Scope) error {
out.AdvertiseAddress = in.AdvertiseAddress
out.ControlPlaneEndpoint = in.ControlPlaneEndpoint
out.BindPort = in.BindPort
return nil
}
@ -74,6 +79,7 @@ func Convert_v1alpha1_API_To_kubeadm_API(in *API, out *kubeadm.API, s conversion
func autoConvert_kubeadm_API_To_v1alpha1_API(in *kubeadm.API, out *API, s conversion.Scope) error {
out.AdvertiseAddress = in.AdvertiseAddress
out.ControlPlaneEndpoint = in.ControlPlaneEndpoint
out.BindPort = in.BindPort
return nil
}
@ -83,6 +89,30 @@ func Convert_kubeadm_API_To_v1alpha1_API(in *kubeadm.API, out *API, s conversion
return autoConvert_kubeadm_API_To_v1alpha1_API(in, out, s)
}
func autoConvert_v1alpha1_AuditPolicyConfiguration_To_kubeadm_AuditPolicyConfiguration(in *AuditPolicyConfiguration, out *kubeadm.AuditPolicyConfiguration, s conversion.Scope) error {
out.Path = in.Path
out.LogDir = in.LogDir
out.LogMaxAge = (*int32)(unsafe.Pointer(in.LogMaxAge))
return nil
}
// Convert_v1alpha1_AuditPolicyConfiguration_To_kubeadm_AuditPolicyConfiguration is an autogenerated conversion function.
func Convert_v1alpha1_AuditPolicyConfiguration_To_kubeadm_AuditPolicyConfiguration(in *AuditPolicyConfiguration, out *kubeadm.AuditPolicyConfiguration, s conversion.Scope) error {
return autoConvert_v1alpha1_AuditPolicyConfiguration_To_kubeadm_AuditPolicyConfiguration(in, out, s)
}
func autoConvert_kubeadm_AuditPolicyConfiguration_To_v1alpha1_AuditPolicyConfiguration(in *kubeadm.AuditPolicyConfiguration, out *AuditPolicyConfiguration, s conversion.Scope) error {
out.Path = in.Path
out.LogDir = in.LogDir
out.LogMaxAge = (*int32)(unsafe.Pointer(in.LogMaxAge))
return nil
}
// Convert_kubeadm_AuditPolicyConfiguration_To_v1alpha1_AuditPolicyConfiguration is an autogenerated conversion function.
func Convert_kubeadm_AuditPolicyConfiguration_To_v1alpha1_AuditPolicyConfiguration(in *kubeadm.AuditPolicyConfiguration, out *AuditPolicyConfiguration, s conversion.Scope) error {
return autoConvert_kubeadm_AuditPolicyConfiguration_To_v1alpha1_AuditPolicyConfiguration(in, out, s)
}
func autoConvert_v1alpha1_Etcd_To_kubeadm_Etcd(in *Etcd, out *kubeadm.Etcd, s conversion.Scope) error {
out.Endpoints = *(*[]string)(unsafe.Pointer(&in.Endpoints))
out.CAFile = in.CAFile
@ -92,6 +122,8 @@ func autoConvert_v1alpha1_Etcd_To_kubeadm_Etcd(in *Etcd, out *kubeadm.Etcd, s co
out.ExtraArgs = *(*map[string]string)(unsafe.Pointer(&in.ExtraArgs))
out.Image = in.Image
out.SelfHosted = (*kubeadm.SelfHostedEtcd)(unsafe.Pointer(in.SelfHosted))
out.ServerCertSANs = *(*[]string)(unsafe.Pointer(&in.ServerCertSANs))
out.PeerCertSANs = *(*[]string)(unsafe.Pointer(&in.PeerCertSANs))
return nil
}
@ -109,6 +141,8 @@ func autoConvert_kubeadm_Etcd_To_v1alpha1_Etcd(in *kubeadm.Etcd, out *Etcd, s co
out.ExtraArgs = *(*map[string]string)(unsafe.Pointer(&in.ExtraArgs))
out.Image = in.Image
out.SelfHosted = (*SelfHostedEtcd)(unsafe.Pointer(in.SelfHosted))
out.ServerCertSANs = *(*[]string)(unsafe.Pointer(&in.ServerCertSANs))
out.PeerCertSANs = *(*[]string)(unsafe.Pointer(&in.PeerCertSANs))
return nil
}
@ -162,7 +196,7 @@ func Convert_kubeadm_KubeProxy_To_v1alpha1_KubeProxy(in *kubeadm.KubeProxy, out
}
func autoConvert_v1alpha1_KubeletConfiguration_To_kubeadm_KubeletConfiguration(in *KubeletConfiguration, out *kubeadm.KubeletConfiguration, s conversion.Scope) error {
out.BaseConfig = (*kubeletconfig_v1alpha1.KubeletConfiguration)(unsafe.Pointer(in.BaseConfig))
out.BaseConfig = (*v1beta1.KubeletConfiguration)(unsafe.Pointer(in.BaseConfig))
return nil
}
@ -172,7 +206,7 @@ func Convert_v1alpha1_KubeletConfiguration_To_kubeadm_KubeletConfiguration(in *K
}
func autoConvert_kubeadm_KubeletConfiguration_To_v1alpha1_KubeletConfiguration(in *kubeadm.KubeletConfiguration, out *KubeletConfiguration, s conversion.Scope) error {
out.BaseConfig = (*kubeletconfig_v1alpha1.KubeletConfiguration)(unsafe.Pointer(in.BaseConfig))
out.BaseConfig = (*v1beta1.KubeletConfiguration)(unsafe.Pointer(in.BaseConfig))
return nil
}
@ -201,8 +235,13 @@ func autoConvert_v1alpha1_MasterConfiguration_To_kubeadm_MasterConfiguration(in
out.CloudProvider = in.CloudProvider
out.NodeName = in.NodeName
out.AuthorizationModes = *(*[]string)(unsafe.Pointer(&in.AuthorizationModes))
out.NoTaintMaster = in.NoTaintMaster
out.PrivilegedPods = in.PrivilegedPods
out.Token = in.Token
out.TokenTTL = (*v1.Duration)(unsafe.Pointer(in.TokenTTL))
out.TokenUsages = *(*[]string)(unsafe.Pointer(&in.TokenUsages))
out.TokenGroups = *(*[]string)(unsafe.Pointer(&in.TokenGroups))
out.CRISocket = in.CRISocket
out.APIServerExtraArgs = *(*map[string]string)(unsafe.Pointer(&in.APIServerExtraArgs))
out.ControllerManagerExtraArgs = *(*map[string]string)(unsafe.Pointer(&in.ControllerManagerExtraArgs))
out.SchedulerExtraArgs = *(*map[string]string)(unsafe.Pointer(&in.SchedulerExtraArgs))
@ -212,7 +251,11 @@ func autoConvert_v1alpha1_MasterConfiguration_To_kubeadm_MasterConfiguration(in
out.APIServerCertSANs = *(*[]string)(unsafe.Pointer(&in.APIServerCertSANs))
out.CertificatesDir = in.CertificatesDir
out.ImageRepository = in.ImageRepository
out.ImagePullPolicy = core_v1.PullPolicy(in.ImagePullPolicy)
out.UnifiedControlPlaneImage = in.UnifiedControlPlaneImage
if err := Convert_v1alpha1_AuditPolicyConfiguration_To_kubeadm_AuditPolicyConfiguration(&in.AuditPolicyConfiguration, &out.AuditPolicyConfiguration, s); err != nil {
return err
}
out.FeatureGates = *(*map[string]bool)(unsafe.Pointer(&in.FeatureGates))
return nil
}
@ -242,8 +285,13 @@ func autoConvert_kubeadm_MasterConfiguration_To_v1alpha1_MasterConfiguration(in
out.CloudProvider = in.CloudProvider
out.NodeName = in.NodeName
out.AuthorizationModes = *(*[]string)(unsafe.Pointer(&in.AuthorizationModes))
out.NoTaintMaster = in.NoTaintMaster
out.PrivilegedPods = in.PrivilegedPods
out.Token = in.Token
out.TokenTTL = (*v1.Duration)(unsafe.Pointer(in.TokenTTL))
out.TokenUsages = *(*[]string)(unsafe.Pointer(&in.TokenUsages))
out.TokenGroups = *(*[]string)(unsafe.Pointer(&in.TokenGroups))
out.CRISocket = in.CRISocket
out.APIServerExtraArgs = *(*map[string]string)(unsafe.Pointer(&in.APIServerExtraArgs))
out.ControllerManagerExtraArgs = *(*map[string]string)(unsafe.Pointer(&in.ControllerManagerExtraArgs))
out.SchedulerExtraArgs = *(*map[string]string)(unsafe.Pointer(&in.SchedulerExtraArgs))
@ -252,9 +300,13 @@ func autoConvert_kubeadm_MasterConfiguration_To_v1alpha1_MasterConfiguration(in
out.SchedulerExtraVolumes = *(*[]HostPathMount)(unsafe.Pointer(&in.SchedulerExtraVolumes))
out.APIServerCertSANs = *(*[]string)(unsafe.Pointer(&in.APIServerCertSANs))
out.CertificatesDir = in.CertificatesDir
out.ImagePullPolicy = core_v1.PullPolicy(in.ImagePullPolicy)
out.ImageRepository = in.ImageRepository
// INFO: in.CIImageRepository opted out of conversion generation
out.UnifiedControlPlaneImage = in.UnifiedControlPlaneImage
if err := Convert_kubeadm_AuditPolicyConfiguration_To_v1alpha1_AuditPolicyConfiguration(&in.AuditPolicyConfiguration, &out.AuditPolicyConfiguration, s); err != nil {
return err
}
out.FeatureGates = *(*map[string]bool)(unsafe.Pointer(&in.FeatureGates))
return nil
}
@ -296,6 +348,7 @@ func autoConvert_v1alpha1_NodeConfiguration_To_kubeadm_NodeConfiguration(in *Nod
out.NodeName = in.NodeName
out.TLSBootstrapToken = in.TLSBootstrapToken
out.Token = in.Token
out.CRISocket = in.CRISocket
out.DiscoveryTokenCACertHashes = *(*[]string)(unsafe.Pointer(&in.DiscoveryTokenCACertHashes))
out.DiscoveryTokenUnsafeSkipCAVerification = in.DiscoveryTokenUnsafeSkipCAVerification
out.FeatureGates = *(*map[string]bool)(unsafe.Pointer(&in.FeatureGates))
@ -315,6 +368,7 @@ func autoConvert_kubeadm_NodeConfiguration_To_v1alpha1_NodeConfiguration(in *kub
out.NodeName = in.NodeName
out.TLSBootstrapToken = in.TLSBootstrapToken
out.Token = in.Token
out.CRISocket = in.CRISocket
out.DiscoveryTokenCACertHashes = *(*[]string)(unsafe.Pointer(&in.DiscoveryTokenCACertHashes))
out.DiscoveryTokenUnsafeSkipCAVerification = in.DiscoveryTokenUnsafeSkipCAVerification
out.FeatureGates = *(*map[string]bool)(unsafe.Pointer(&in.FeatureGates))
@ -355,7 +409,6 @@ func Convert_kubeadm_SelfHostedEtcd_To_v1alpha1_SelfHostedEtcd(in *kubeadm.SelfH
func autoConvert_v1alpha1_TokenDiscovery_To_kubeadm_TokenDiscovery(in *TokenDiscovery, out *kubeadm.TokenDiscovery, s conversion.Scope) error {
out.ID = in.ID
out.Secret = in.Secret
out.Addresses = *(*[]string)(unsafe.Pointer(&in.Addresses))
return nil
}
@ -367,7 +420,6 @@ func Convert_v1alpha1_TokenDiscovery_To_kubeadm_TokenDiscovery(in *TokenDiscover
func autoConvert_kubeadm_TokenDiscovery_To_v1alpha1_TokenDiscovery(in *kubeadm.TokenDiscovery, out *TokenDiscovery, s conversion.Scope) error {
out.ID = in.ID
out.Secret = in.Secret
out.Addresses = *(*[]string)(unsafe.Pointer(&in.Addresses))
return nil
}

View File

@ -16,14 +16,14 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
// This file was autogenerated by deepcopy-gen. Do not edit it manually!
// Code generated by deepcopy-gen. DO NOT EDIT.
package v1alpha1
import (
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
kubeletconfig_v1alpha1 "k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/v1alpha1"
v1beta1 "k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/v1beta1"
kubeproxyconfig_v1alpha1 "k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig/v1alpha1"
)
@ -43,6 +43,31 @@ func (in *API) DeepCopy() *API {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *AuditPolicyConfiguration) DeepCopyInto(out *AuditPolicyConfiguration) {
*out = *in
if in.LogMaxAge != nil {
in, out := &in.LogMaxAge, &out.LogMaxAge
if *in == nil {
*out = nil
} else {
*out = new(int32)
**out = **in
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AuditPolicyConfiguration.
func (in *AuditPolicyConfiguration) DeepCopy() *AuditPolicyConfiguration {
if in == nil {
return nil
}
out := new(AuditPolicyConfiguration)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Etcd) DeepCopyInto(out *Etcd) {
*out = *in
@ -67,6 +92,16 @@ func (in *Etcd) DeepCopyInto(out *Etcd) {
**out = **in
}
}
if in.ServerCertSANs != nil {
in, out := &in.ServerCertSANs, &out.ServerCertSANs
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.PeerCertSANs != nil {
in, out := &in.PeerCertSANs, &out.PeerCertSANs
*out = make([]string, len(*in))
copy(*out, *in)
}
return
}
@ -129,7 +164,7 @@ func (in *KubeletConfiguration) DeepCopyInto(out *KubeletConfiguration) {
if *in == nil {
*out = nil
} else {
*out = new(kubeletconfig_v1alpha1.KubeletConfiguration)
*out = new(v1beta1.KubeletConfiguration)
(*in).DeepCopyInto(*out)
}
}
@ -169,6 +204,16 @@ func (in *MasterConfiguration) DeepCopyInto(out *MasterConfiguration) {
**out = **in
}
}
if in.TokenUsages != nil {
in, out := &in.TokenUsages, &out.TokenUsages
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.TokenGroups != nil {
in, out := &in.TokenGroups, &out.TokenGroups
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.APIServerExtraArgs != nil {
in, out := &in.APIServerExtraArgs, &out.APIServerExtraArgs
*out = make(map[string]string, len(*in))
@ -210,6 +255,7 @@ func (in *MasterConfiguration) DeepCopyInto(out *MasterConfiguration) {
*out = make([]string, len(*in))
copy(*out, *in)
}
in.AuditPolicyConfiguration.DeepCopyInto(&out.AuditPolicyConfiguration)
if in.FeatureGates != nil {
in, out := &in.FeatureGates, &out.FeatureGates
*out = make(map[string]bool, len(*in))
@ -234,9 +280,8 @@ func (in *MasterConfiguration) DeepCopy() *MasterConfiguration {
func (in *MasterConfiguration) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
} else {
return nil
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
@ -293,9 +338,8 @@ func (in *NodeConfiguration) DeepCopy() *NodeConfiguration {
func (in *NodeConfiguration) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
} else {
return nil
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
@ -317,11 +361,6 @@ func (in *SelfHostedEtcd) DeepCopy() *SelfHostedEtcd {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TokenDiscovery) DeepCopyInto(out *TokenDiscovery) {
*out = *in
if in.Addresses != nil {
in, out := &in.Addresses, &out.Addresses
*out = make([]string, len(*in))
copy(*out, *in)
}
return
}

View File

@ -16,13 +16,13 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
// This file was autogenerated by defaulter-gen. Do not edit it manually!
// Code generated by defaulter-gen. DO NOT EDIT.
package v1alpha1
import (
runtime "k8s.io/apimachinery/pkg/runtime"
kubeletconfig_v1alpha1 "k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/v1alpha1"
v1beta1 "k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/v1beta1"
kubeproxyconfig_v1alpha1 "k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig/v1alpha1"
)
@ -41,7 +41,7 @@ func SetObjectDefaults_MasterConfiguration(in *MasterConfiguration) {
kubeproxyconfig_v1alpha1.SetDefaults_KubeProxyConfiguration(in.KubeProxy.Config)
}
if in.KubeletConfiguration.BaseConfig != nil {
kubeletconfig_v1alpha1.SetDefaults_KubeletConfiguration(in.KubeletConfiguration.BaseConfig)
v1beta1.SetDefaults_KubeletConfiguration(in.KubeletConfiguration.BaseConfig)
}
}

View File

@ -25,17 +25,18 @@ go_library(
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/validation:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
"//vendor/k8s.io/client-go/tools/bootstrap/token/api:go_default_library",
"//vendor/k8s.io/client-go/tools/bootstrap/token/util:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = ["validation_test.go"],
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation",
library = ":go_default_library",
embed = [":go_default_library"],
deps = [
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
"//pkg/kubelet/apis/kubeletconfig/v1alpha1:go_default_library",
"//pkg/kubelet/apis/kubeletconfig/v1beta1:go_default_library",
"//pkg/proxy/apis/kubeproxyconfig/v1alpha1:go_default_library",
"//pkg/util/pointer:go_default_library",
"//vendor/github.com/spf13/pflag:go_default_library",

View File

@ -29,6 +29,8 @@ import (
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/validation"
"k8s.io/apimachinery/pkg/util/validation/field"
bootstrapapi "k8s.io/client-go/tools/bootstrap/token/api"
bootstraputil "k8s.io/client-go/tools/bootstrap/token/util"
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
"k8s.io/kubernetes/cmd/kubeadm/app/features"
@ -53,6 +55,7 @@ var cloudproviders = []string{
"azure",
"cloudstack",
"gce",
"external", // Support for out-of-tree cloud providers
"openstack",
"ovirt",
"photon",
@ -71,10 +74,14 @@ func ValidateMasterConfiguration(c *kubeadm.MasterConfiguration) field.ErrorList
allErrs = append(allErrs, ValidateCloudProvider(c.CloudProvider, field.NewPath("cloudprovider"))...)
allErrs = append(allErrs, ValidateAuthorizationModes(c.AuthorizationModes, field.NewPath("authorization-modes"))...)
allErrs = append(allErrs, ValidateNetworking(&c.Networking, field.NewPath("networking"))...)
allErrs = append(allErrs, ValidateAPIServerCertSANs(c.APIServerCertSANs, field.NewPath("cert-altnames"))...)
allErrs = append(allErrs, ValidateCertSANs(c.APIServerCertSANs, field.NewPath("api-server-cert-altnames"))...)
allErrs = append(allErrs, ValidateCertSANs(c.Etcd.ServerCertSANs, field.NewPath("etcd-server-cert-altnames"))...)
allErrs = append(allErrs, ValidateCertSANs(c.Etcd.PeerCertSANs, field.NewPath("etcd-peer-cert-altnames"))...)
allErrs = append(allErrs, ValidateAbsolutePath(c.CertificatesDir, field.NewPath("certificates-dir"))...)
allErrs = append(allErrs, ValidateNodeName(c.NodeName, field.NewPath("node-name"))...)
allErrs = append(allErrs, ValidateToken(c.Token, field.NewPath("token"))...)
allErrs = append(allErrs, ValidateTokenUsages(c.TokenUsages, field.NewPath("tokenUsages"))...)
allErrs = append(allErrs, ValidateTokenGroups(c.TokenUsages, c.TokenGroups, field.NewPath("tokenGroups"))...)
allErrs = append(allErrs, ValidateFeatureGates(c.FeatureGates, field.NewPath("feature-gates"))...)
allErrs = append(allErrs, ValidateAPIEndpoint(c, field.NewPath("api-endpoint"))...)
allErrs = append(allErrs, ValidateProxy(c, field.NewPath("kube-proxy"))...)
@ -227,8 +234,41 @@ func ValidateToken(t string, fldPath *field.Path) field.ErrorList {
return allErrs
}
// ValidateAPIServerCertSANs validates alternative names
func ValidateAPIServerCertSANs(altnames []string, fldPath *field.Path) field.ErrorList {
// ValidateTokenGroups validates token groups
func ValidateTokenGroups(usages []string, groups []string, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
// adding groups only makes sense for authentication
usagesSet := sets.NewString(usages...)
usageAuthentication := strings.TrimPrefix(bootstrapapi.BootstrapTokenUsageAuthentication, bootstrapapi.BootstrapTokenUsagePrefix)
if len(groups) > 0 && !usagesSet.Has(usageAuthentication) {
allErrs = append(allErrs, field.Invalid(fldPath, groups, fmt.Sprintf("token groups cannot be specified unless --usages includes %q", usageAuthentication)))
}
// validate any extra group names
for _, group := range groups {
if err := bootstraputil.ValidateBootstrapGroupName(group); err != nil {
allErrs = append(allErrs, field.Invalid(fldPath, groups, err.Error()))
}
}
return allErrs
}
// ValidateTokenUsages validates token usages
func ValidateTokenUsages(usages []string, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
// validate usages
if err := bootstraputil.ValidateUsages(usages); err != nil {
allErrs = append(allErrs, field.Invalid(fldPath, usages, err.Error()))
}
return allErrs
}
// ValidateCertSANs validates alternative names
func ValidateCertSANs(altnames []string, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
for _, altname := range altnames {
if len(validation.IsDNS1123Subdomain(altname)) != 0 && net.ParseIP(altname) == nil {
@ -350,7 +390,7 @@ func ValidateAPIEndpoint(c *kubeadm.MasterConfiguration, fldPath *field.Path) fi
endpoint, err := kubeadmutil.GetMasterEndpoint(c)
if err != nil {
allErrs = append(allErrs, field.Invalid(fldPath, endpoint, "Invalid API Endpoint"))
allErrs = append(allErrs, field.Invalid(fldPath, endpoint, err.Error()))
}
return allErrs
}

View File

@ -17,6 +17,9 @@ limitations under the License.
package validation
import (
"io/ioutil"
"os"
"strings"
"testing"
"time"
@ -25,7 +28,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/validation/field"
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
kubeletconfigv1alpha1 "k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/v1alpha1"
kubeletconfigv1beta1 "k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/v1beta1"
kubeproxyconfigv1alpha1 "k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig/v1alpha1"
utilpointer "k8s.io/kubernetes/pkg/util/pointer"
)
@ -36,12 +39,13 @@ func TestValidateTokenDiscovery(t *testing.T) {
f *field.Path
expected bool
}{
{&kubeadm.NodeConfiguration{Token: "772ef5.6b6baab1d4a0a171", DiscoveryTokenAPIServers: []string{"192.168.122.100:9898"}}, nil, true},
{&kubeadm.NodeConfiguration{Token: ".6b6baab1d4a0a171", DiscoveryTokenAPIServers: []string{"192.168.122.100:9898"}}, nil, false},
{&kubeadm.NodeConfiguration{Token: "772ef5.", DiscoveryTokenAPIServers: []string{"192.168.122.100:9898"}}, nil, false},
{&kubeadm.NodeConfiguration{Token: "772ef5.6b6baab1d4a0a171", DiscoveryTokenAPIServers: []string{"2001:db8::100:9898"}}, nil, true},
{&kubeadm.NodeConfiguration{Token: ".6b6baab1d4a0a171", DiscoveryTokenAPIServers: []string{"2001:db8::100:9898"}}, nil, false},
{&kubeadm.NodeConfiguration{Token: "772ef5.", DiscoveryTokenAPIServers: []string{"2001:db8::100:9898"}}, nil, false},
{&kubeadm.NodeConfiguration{Token: "772ef5.6b6baab1d4a0a171", DiscoveryTokenAPIServers: []string{"192.168.122.100:6443"}}, nil, true},
{&kubeadm.NodeConfiguration{Token: ".6b6baab1d4a0a171", DiscoveryTokenAPIServers: []string{"192.168.122.100:6443"}}, nil, false},
{&kubeadm.NodeConfiguration{Token: "772ef5.", DiscoveryTokenAPIServers: []string{"192.168.122.100:6443"}}, nil, false},
{&kubeadm.NodeConfiguration{Token: "772ef5.6b6baab1d4a0a171", DiscoveryTokenAPIServers: []string{"2001:db8::100:6443"}}, nil, true},
{&kubeadm.NodeConfiguration{Token: ".6b6baab1d4a0a171", DiscoveryTokenAPIServers: []string{"2001:db8::100:6443"}}, nil, false},
{&kubeadm.NodeConfiguration{Token: "772ef5.", DiscoveryTokenAPIServers: []string{"2001:db8::100:6443"}}, nil, false},
{&kubeadm.NodeConfiguration{Token: "abcdef.1234567890123456@foobar", DiscoveryTokenAPIServers: []string{"192.168.122.100:6443"}}, nil, false},
}
for _, rt := range tests {
err := ValidateToken(rt.c.Token, rt.f).ToAggregate()
@ -55,6 +59,51 @@ func TestValidateTokenDiscovery(t *testing.T) {
}
}
func TestValidateValidateTokenUsages(t *testing.T) {
var tests = []struct {
u []string
f *field.Path
expected bool
}{
{[]string{}, nil, true}, // supported (no usages)
{[]string{"signing", "authentication"}, nil, true}, // supported
{[]string{"something else"}, nil, false}, // usage not supported
}
for _, rt := range tests {
actual := ValidateTokenUsages(rt.u, rt.f)
if (len(actual) == 0) != rt.expected {
t.Errorf(
"failed ValidateTokenUsages:\n\texpected: %t\n\t actual: %t",
rt.expected,
(len(actual) == 0),
)
}
}
}
func TestValidateTokenGroups(t *testing.T) {
var tests = []struct {
u []string
g []string
f *field.Path
expected bool
}{
{[]string{"some usage"}, []string{"some group"}, nil, false}, // groups doesn't makes sense if usage authentication
{[]string{"authentication"}, []string{"some group"}, nil, false}, // group not supported
{[]string{"authentication"}, []string{"system:bootstrappers:anygroup"}, nil, true}, // supported
}
for _, rt := range tests {
actual := ValidateTokenGroups(rt.u, rt.g, rt.f)
if (len(actual) == 0) != rt.expected {
t.Errorf(
"failed ValidateTokenGroups:\n\texpected: %t\n\t actual: %t",
rt.expected,
(len(actual) == 0),
)
}
}
}
func TestValidateAuthorizationModes(t *testing.T) {
var tests = []struct {
s []string
@ -130,7 +179,7 @@ func TestValidateCloudProvider(t *testing.T) {
}
}
func TestValidateAPIServerCertSANs(t *testing.T) {
func TestValidateCertSANs(t *testing.T) {
var tests = []struct {
sans []string
expected bool
@ -144,10 +193,10 @@ func TestValidateAPIServerCertSANs(t *testing.T) {
{[]string{"my-hostname2", "my.other.subdomain", "2001:db8::10"}, true}, // supported
}
for _, rt := range tests {
actual := ValidateAPIServerCertSANs(rt.sans, nil)
actual := ValidateCertSANs(rt.sans, nil)
if (len(actual) == 0) != rt.expected {
t.Errorf(
"failed ValidateAPIServerCertSANs:\n\texpected: %t\n\t actual: %t",
"failed ValidateCertSANs:\n\texpected: %t\n\t actual: %t",
rt.expected,
(len(actual) == 0),
)
@ -330,6 +379,22 @@ func TestValidateMasterConfiguration(t *testing.T) {
CertificatesDir: "/some/other/cert/dir",
Token: "abcdef.0123456789abcdef",
}, false},
{"valid master configuration with incorrect IPv4 pod subnet",
&kubeadm.MasterConfiguration{
API: kubeadm.API{
AdvertiseAddress: "1.2.3.4",
BindPort: 6443,
},
AuthorizationModes: []string{"Node", "RBAC"},
Networking: kubeadm.Networking{
ServiceSubnet: "10.96.0.1/12",
DNSDomain: "cluster.local",
PodSubnet: "10.0.1.15",
},
CertificatesDir: "/some/other/cert/dir",
Token: "abcdef.0123456789abcdef",
NodeName: nodename,
}, false},
{"valid master configuration with IPv4 service subnet",
&kubeadm.MasterConfiguration{
API: kubeadm.API{
@ -366,6 +431,7 @@ func TestValidateMasterConfiguration(t *testing.T) {
Networking: kubeadm.Networking{
ServiceSubnet: "10.96.0.1/12",
DNSDomain: "cluster.local",
PodSubnet: "10.0.1.15/16",
},
CertificatesDir: "/some/other/cert/dir",
Token: "abcdef.0123456789abcdef",
@ -547,12 +613,11 @@ func TestValidateIgnorePreflightErrors(t *testing.T) {
func TestValidateKubeletConfiguration(t *testing.T) {
successCase := &kubeadm.KubeletConfiguration{
BaseConfig: &kubeletconfigv1alpha1.KubeletConfiguration{
BaseConfig: &kubeletconfigv1beta1.KubeletConfiguration{
CgroupsPerQOS: utilpointer.BoolPtr(true),
EnforceNodeAllocatable: []string{"pods", "system-reserved", "kube-reserved"},
SystemCgroups: "",
CgroupRoot: "",
CAdvisorPort: utilpointer.Int32Ptr(0),
EventBurst: 10,
EventRecordQPS: utilpointer.Int32Ptr(5),
HealthzPort: utilpointer.Int32Ptr(10248),
@ -567,9 +632,10 @@ func TestValidateKubeletConfiguration(t *testing.T) {
OOMScoreAdj: utilpointer.Int32Ptr(-999),
PodsPerCore: 100,
Port: 65535,
ReadOnlyPort: utilpointer.Int32Ptr(0),
ReadOnlyPort: 0,
RegistryBurst: 10,
RegistryPullQPS: utilpointer.Int32Ptr(5),
HairpinMode: "promiscuous-bridge",
},
}
if allErrors := ValidateKubeletConfiguration(successCase, nil); len(allErrors) != 0 {
@ -577,12 +643,11 @@ func TestValidateKubeletConfiguration(t *testing.T) {
}
errorCase := &kubeadm.KubeletConfiguration{
BaseConfig: &kubeletconfigv1alpha1.KubeletConfiguration{
BaseConfig: &kubeletconfigv1beta1.KubeletConfiguration{
CgroupsPerQOS: utilpointer.BoolPtr(false),
EnforceNodeAllocatable: []string{"pods", "system-reserved", "kube-reserved", "illegal-key"},
SystemCgroups: "/",
CgroupRoot: "",
CAdvisorPort: utilpointer.Int32Ptr(-10),
EventBurst: -10,
EventRecordQPS: utilpointer.Int32Ptr(-10),
HealthzPort: utilpointer.Int32Ptr(-10),
@ -597,7 +662,7 @@ func TestValidateKubeletConfiguration(t *testing.T) {
OOMScoreAdj: utilpointer.Int32Ptr(-1001),
PodsPerCore: -10,
Port: 0,
ReadOnlyPort: utilpointer.Int32Ptr(-10),
ReadOnlyPort: -10,
RegistryBurst: -10,
RegistryPullQPS: utilpointer.Int32Ptr(-10),
},
@ -606,3 +671,414 @@ func TestValidateKubeletConfiguration(t *testing.T) {
t.Errorf("failed ValidateKubeletConfiguration: expect errors but got no error")
}
}
func TestValidateKubeProxyConfiguration(t *testing.T) {
successCases := []kubeadm.MasterConfiguration{
{
KubeProxy: kubeadm.KubeProxy{
Config: &kubeproxyconfigv1alpha1.KubeProxyConfiguration{
BindAddress: "192.168.59.103",
HealthzBindAddress: "0.0.0.0:10256",
MetricsBindAddress: "127.0.0.1:10249",
ClusterCIDR: "192.168.59.0/24",
UDPIdleTimeout: metav1.Duration{Duration: 1 * time.Second},
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
IPTables: kubeproxyconfigv1alpha1.KubeProxyIPTablesConfiguration{
MasqueradeAll: true,
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
},
IPVS: kubeproxyconfigv1alpha1.KubeProxyIPVSConfiguration{
SyncPeriod: metav1.Duration{Duration: 10 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 5 * time.Second},
},
Conntrack: kubeproxyconfigv1alpha1.KubeProxyConntrackConfiguration{
Max: utilpointer.Int32Ptr(2),
MaxPerCore: utilpointer.Int32Ptr(1),
Min: utilpointer.Int32Ptr(1),
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
},
},
},
},
}
for _, successCase := range successCases {
if errs := ValidateProxy(&successCase, nil); len(errs) != 0 {
t.Errorf("failed ValidateProxy: expect no errors but got %v", errs)
}
}
errorCases := []struct {
masterConfig kubeadm.MasterConfiguration
msg string
}{
{
masterConfig: kubeadm.MasterConfiguration{
KubeProxy: kubeadm.KubeProxy{
Config: &kubeproxyconfigv1alpha1.KubeProxyConfiguration{
// only BindAddress is invalid
BindAddress: "10.10.12.11:2000",
HealthzBindAddress: "0.0.0.0:10256",
MetricsBindAddress: "127.0.0.1:10249",
ClusterCIDR: "192.168.59.0/24",
UDPIdleTimeout: metav1.Duration{Duration: 1 * time.Second},
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
IPTables: kubeproxyconfigv1alpha1.KubeProxyIPTablesConfiguration{
MasqueradeAll: true,
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
},
IPVS: kubeproxyconfigv1alpha1.KubeProxyIPVSConfiguration{
SyncPeriod: metav1.Duration{Duration: 10 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 5 * time.Second},
},
Conntrack: kubeproxyconfigv1alpha1.KubeProxyConntrackConfiguration{
Max: utilpointer.Int32Ptr(2),
MaxPerCore: utilpointer.Int32Ptr(1),
Min: utilpointer.Int32Ptr(1),
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
},
},
},
},
msg: "not a valid textual representation of an IP address",
},
{
masterConfig: kubeadm.MasterConfiguration{
KubeProxy: kubeadm.KubeProxy{
Config: &kubeproxyconfigv1alpha1.KubeProxyConfiguration{
BindAddress: "10.10.12.11",
// only HealthzBindAddress is invalid
HealthzBindAddress: "0.0.0.0",
MetricsBindAddress: "127.0.0.1:10249",
ClusterCIDR: "192.168.59.0/24",
UDPIdleTimeout: metav1.Duration{Duration: 1 * time.Second},
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
IPTables: kubeproxyconfigv1alpha1.KubeProxyIPTablesConfiguration{
MasqueradeAll: true,
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
},
IPVS: kubeproxyconfigv1alpha1.KubeProxyIPVSConfiguration{
SyncPeriod: metav1.Duration{Duration: 10 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 5 * time.Second},
},
Conntrack: kubeproxyconfigv1alpha1.KubeProxyConntrackConfiguration{
Max: utilpointer.Int32Ptr(2),
MaxPerCore: utilpointer.Int32Ptr(1),
Min: utilpointer.Int32Ptr(1),
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
},
},
},
},
msg: "must be IP:port",
},
{
masterConfig: kubeadm.MasterConfiguration{
KubeProxy: kubeadm.KubeProxy{
Config: &kubeproxyconfigv1alpha1.KubeProxyConfiguration{
BindAddress: "10.10.12.11",
HealthzBindAddress: "0.0.0.0:12345",
// only MetricsBindAddress is invalid
MetricsBindAddress: "127.0.0.1",
ClusterCIDR: "192.168.59.0/24",
UDPIdleTimeout: metav1.Duration{Duration: 1 * time.Second},
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
IPTables: kubeproxyconfigv1alpha1.KubeProxyIPTablesConfiguration{
MasqueradeAll: true,
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
},
IPVS: kubeproxyconfigv1alpha1.KubeProxyIPVSConfiguration{
SyncPeriod: metav1.Duration{Duration: 10 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 5 * time.Second},
},
Conntrack: kubeproxyconfigv1alpha1.KubeProxyConntrackConfiguration{
Max: utilpointer.Int32Ptr(2),
MaxPerCore: utilpointer.Int32Ptr(1),
Min: utilpointer.Int32Ptr(1),
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
},
},
},
},
msg: "must be IP:port",
},
{
masterConfig: kubeadm.MasterConfiguration{
KubeProxy: kubeadm.KubeProxy{
Config: &kubeproxyconfigv1alpha1.KubeProxyConfiguration{
BindAddress: "10.10.12.11",
HealthzBindAddress: "0.0.0.0:12345",
MetricsBindAddress: "127.0.0.1:10249",
// only ClusterCIDR is invalid
ClusterCIDR: "192.168.59.0",
UDPIdleTimeout: metav1.Duration{Duration: 1 * time.Second},
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
IPTables: kubeproxyconfigv1alpha1.KubeProxyIPTablesConfiguration{
MasqueradeAll: true,
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
},
IPVS: kubeproxyconfigv1alpha1.KubeProxyIPVSConfiguration{
SyncPeriod: metav1.Duration{Duration: 10 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 5 * time.Second},
},
Conntrack: kubeproxyconfigv1alpha1.KubeProxyConntrackConfiguration{
Max: utilpointer.Int32Ptr(2),
MaxPerCore: utilpointer.Int32Ptr(1),
Min: utilpointer.Int32Ptr(1),
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
},
},
},
},
msg: "must be a valid CIDR block (e.g. 10.100.0.0/16)",
},
{
masterConfig: kubeadm.MasterConfiguration{
KubeProxy: kubeadm.KubeProxy{
Config: &kubeproxyconfigv1alpha1.KubeProxyConfiguration{
BindAddress: "10.10.12.11",
HealthzBindAddress: "0.0.0.0:12345",
MetricsBindAddress: "127.0.0.1:10249",
ClusterCIDR: "192.168.59.0/24",
// only UDPIdleTimeout is invalid
UDPIdleTimeout: metav1.Duration{Duration: -1 * time.Second},
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
IPTables: kubeproxyconfigv1alpha1.KubeProxyIPTablesConfiguration{
MasqueradeAll: true,
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
},
IPVS: kubeproxyconfigv1alpha1.KubeProxyIPVSConfiguration{
SyncPeriod: metav1.Duration{Duration: 10 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 5 * time.Second},
},
Conntrack: kubeproxyconfigv1alpha1.KubeProxyConntrackConfiguration{
Max: utilpointer.Int32Ptr(2),
MaxPerCore: utilpointer.Int32Ptr(1),
Min: utilpointer.Int32Ptr(1),
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
},
},
},
},
msg: "must be greater than 0",
},
{
masterConfig: kubeadm.MasterConfiguration{
KubeProxy: kubeadm.KubeProxy{
Config: &kubeproxyconfigv1alpha1.KubeProxyConfiguration{
BindAddress: "10.10.12.11",
HealthzBindAddress: "0.0.0.0:12345",
MetricsBindAddress: "127.0.0.1:10249",
ClusterCIDR: "192.168.59.0/24",
UDPIdleTimeout: metav1.Duration{Duration: 1 * time.Second},
// only ConfigSyncPeriod is invalid
ConfigSyncPeriod: metav1.Duration{Duration: -1 * time.Second},
IPTables: kubeproxyconfigv1alpha1.KubeProxyIPTablesConfiguration{
MasqueradeAll: true,
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
},
IPVS: kubeproxyconfigv1alpha1.KubeProxyIPVSConfiguration{
SyncPeriod: metav1.Duration{Duration: 10 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 5 * time.Second},
},
Conntrack: kubeproxyconfigv1alpha1.KubeProxyConntrackConfiguration{
Max: utilpointer.Int32Ptr(2),
MaxPerCore: utilpointer.Int32Ptr(1),
Min: utilpointer.Int32Ptr(1),
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
},
},
},
},
msg: "must be greater than 0",
},
}
for i, errorCase := range errorCases {
if errs := ValidateProxy(&errorCase.masterConfig, nil); len(errs) == 0 {
t.Errorf("%d failed ValidateProxy: expected error for %s, but got no error", i, errorCase.msg)
} else if !strings.Contains(errs[0].Error(), errorCase.msg) {
t.Errorf("%d failed ValidateProxy: unexpected error: %v, expected: %s", i, errs[0], errorCase.msg)
}
}
}
func TestValidateArgSelection(t *testing.T) {
var tests = []struct {
name string
c *kubeadm.NodeConfiguration
expected bool
}{
{
"invalid: DiscoveryToken and DiscoveryFile cannot both be set",
&kubeadm.NodeConfiguration{
DiscoveryFile: "https://url/file.conf",
DiscoveryToken: "abcdef.1234567890123456",
},
false,
},
{
"invalid: DiscoveryToken or DiscoveryFile must be set",
&kubeadm.NodeConfiguration{
DiscoveryFile: "",
DiscoveryToken: "",
},
false,
},
{
"invalid: DiscoveryTokenAPIServers not set",
&kubeadm.NodeConfiguration{
DiscoveryToken: "abcdef.1234567890123456",
},
false,
},
{
"invalid: DiscoveryTokenCACertHashes cannot be used with DiscoveryFile",
&kubeadm.NodeConfiguration{
DiscoveryFile: "https://url/file.conf",
DiscoveryTokenCACertHashes: []string{"sha256:7173b809ca12ec5dee4506cd86be934c4596dd234ee82c0662eac04a8c2c71dc"},
},
false,
},
{
"invalid: using token-based discovery without DiscoveryTokenCACertHashes and DiscoveryTokenUnsafeSkipCAVerification",
&kubeadm.NodeConfiguration{
DiscoveryToken: "abcdef.1234567890123456",
DiscoveryTokenUnsafeSkipCAVerification: false,
DiscoveryTokenAPIServers: []string{"192.168.122.100:6443"},
},
false,
},
{
"WARNING: kubeadm doesn't fully support multiple API Servers yet",
&kubeadm.NodeConfiguration{
DiscoveryToken: "abcdef.1234567890123456",
DiscoveryTokenUnsafeSkipCAVerification: true,
DiscoveryTokenAPIServers: []string{"192.168.122.100:6443", "192.168.122.88:6443"},
},
true,
},
{
"valid: DiscoveryFile with DiscoveryTokenAPIServers",
&kubeadm.NodeConfiguration{
DiscoveryFile: "https://url/file.conf",
DiscoveryTokenAPIServers: []string{"192.168.122.100:6443"},
},
true,
},
{
"valid: DiscoveryFile without DiscoveryTokenAPIServers",
&kubeadm.NodeConfiguration{
DiscoveryFile: "https://url/file.conf",
},
true,
},
{
"valid: using token-based discovery with DiscoveryTokenCACertHashes",
&kubeadm.NodeConfiguration{
DiscoveryToken: "abcdef.1234567890123456",
DiscoveryTokenAPIServers: []string{"192.168.122.100:6443"},
DiscoveryTokenCACertHashes: []string{"sha256:7173b809ca12ec5dee4506cd86be934c4596dd234ee82c0662eac04a8c2c71dc"},
DiscoveryTokenUnsafeSkipCAVerification: false,
},
true,
},
{
"valid: using token-based discovery with DiscoveryTokenCACertHashe but skip ca verification",
&kubeadm.NodeConfiguration{
DiscoveryToken: "abcdef.1234567890123456",
DiscoveryTokenAPIServers: []string{"192.168.122.100:6443"},
DiscoveryTokenCACertHashes: []string{"sha256:7173b809ca12ec5dee4506cd86be934c4596dd234ee82c0662eac04a8c2c71dc"},
DiscoveryTokenUnsafeSkipCAVerification: true,
},
true,
},
}
for _, rt := range tests {
err := ValidateArgSelection(rt.c, nil).ToAggregate()
if (err == nil) != rt.expected {
t.Errorf(
"%s test case failed: ValidateArgSelection:\n\texpected: %t\n\t actual: %t",
rt.name,
rt.expected,
(err == nil),
)
}
}
}
func TestValidateJoinDiscoveryTokenAPIServer(t *testing.T) {
var tests = []struct {
s *kubeadm.NodeConfiguration
expected bool
}{
{
&kubeadm.NodeConfiguration{
DiscoveryTokenAPIServers: []string{"192.168.122.100"},
},
false,
},
{
&kubeadm.NodeConfiguration{
DiscoveryTokenAPIServers: []string{"192.168.122.100:6443"},
},
true,
},
}
for _, rt := range tests {
actual := ValidateJoinDiscoveryTokenAPIServer(rt.s, nil)
if (len(actual) == 0) != rt.expected {
t.Errorf(
"failed ValidateJoinDiscoveryTokenAPIServer:\n\texpected: %t\n\t actual: %t",
rt.expected,
(len(actual) == 0),
)
}
}
}
func TestValidateDiscoveryFile(t *testing.T) {
tmpfile, err := ioutil.TempFile("/tmp", "test_discovery_file")
if err != nil {
t.Errorf("Error creating temporary file: %v", err)
}
defer os.Remove(tmpfile.Name())
var tests = []struct {
s string
expected bool
}{
{"foo", false},
{"/foo/bar/file_which_i_believe_not_existing.conf", false},
{tmpfile.Name(), true},
{"http://[::1]a", false},
{"http://url/file.conf", false},
{"https://u r l/file.conf", false},
{"https://url/file.conf", true},
}
for i, rt := range tests {
actual := ValidateDiscoveryFile(rt.s, nil)
if (len(actual) == 0) != rt.expected {
t.Errorf(
"%d: failed ValidateDiscoveryFile:\n\texpected: %t\n\t actual: %t",
i,
rt.expected,
(len(actual) == 0),
)
}
}
}

View File

@ -1,43 +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 kubeadm
// Role labels are applied to Nodes to mark their purpose. In particular, we
// usually want to distinguish the master, so that we can isolate privileged
// pods and operations.
//
// Originally we relied on not registering the master, on the fact that the
// master was Unschedulable, and on static manifests for master components.
// But we now do register masters in many environments, are generally moving
// away from static manifests (for better manageability), and working towards
// deprecating the unschedulable field (replacing it with taints & tolerations
// instead).
//
// Even with tainting, a label remains the easiest way of making a positive
// selection, so that pods can schedule only to master nodes for example, and
// thus installations will likely define a label for their master nodes.
//
// So that we can recognize master nodes in consequent places though (such as
// kubectl get nodes), we encourage installations to use the well-known labels.
// We define NodeLabelRole, which is the preferred form, but we will also recognize
// other forms that are known to be in widespread use (NodeLabelKubeadmAlphaRole).
const (
// NodeLabelKubeadmAlphaRole is a label that kubeadm applies to a Node as a hint that it has a particular purpose.
// Use of NodeLabelRole is preferred.
NodeLabelKubeadmAlphaRole = "kubeadm.alpha.kubernetes.io/role"
)

View File

@ -16,14 +16,14 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
// This file was autogenerated by deepcopy-gen. Do not edit it manually!
// Code generated by deepcopy-gen. DO NOT EDIT.
package kubeadm
import (
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
kubeletconfig_v1alpha1 "k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/v1alpha1"
v1beta1 "k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/v1beta1"
v1alpha1 "k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig/v1alpha1"
)
@ -43,6 +43,31 @@ func (in *API) DeepCopy() *API {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *AuditPolicyConfiguration) DeepCopyInto(out *AuditPolicyConfiguration) {
*out = *in
if in.LogMaxAge != nil {
in, out := &in.LogMaxAge, &out.LogMaxAge
if *in == nil {
*out = nil
} else {
*out = new(int32)
**out = **in
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AuditPolicyConfiguration.
func (in *AuditPolicyConfiguration) DeepCopy() *AuditPolicyConfiguration {
if in == nil {
return nil
}
out := new(AuditPolicyConfiguration)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Etcd) DeepCopyInto(out *Etcd) {
*out = *in
@ -67,6 +92,16 @@ func (in *Etcd) DeepCopyInto(out *Etcd) {
**out = **in
}
}
if in.ServerCertSANs != nil {
in, out := &in.ServerCertSANs, &out.ServerCertSANs
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.PeerCertSANs != nil {
in, out := &in.PeerCertSANs, &out.PeerCertSANs
*out = make([]string, len(*in))
copy(*out, *in)
}
return
}
@ -129,7 +164,7 @@ func (in *KubeletConfiguration) DeepCopyInto(out *KubeletConfiguration) {
if *in == nil {
*out = nil
} else {
*out = new(kubeletconfig_v1alpha1.KubeletConfiguration)
*out = new(v1beta1.KubeletConfiguration)
(*in).DeepCopyInto(*out)
}
}
@ -169,6 +204,16 @@ func (in *MasterConfiguration) DeepCopyInto(out *MasterConfiguration) {
**out = **in
}
}
if in.TokenUsages != nil {
in, out := &in.TokenUsages, &out.TokenUsages
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.TokenGroups != nil {
in, out := &in.TokenGroups, &out.TokenGroups
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.APIServerExtraArgs != nil {
in, out := &in.APIServerExtraArgs, &out.APIServerExtraArgs
*out = make(map[string]string, len(*in))
@ -210,6 +255,7 @@ func (in *MasterConfiguration) DeepCopyInto(out *MasterConfiguration) {
*out = make([]string, len(*in))
copy(*out, *in)
}
in.AuditPolicyConfiguration.DeepCopyInto(&out.AuditPolicyConfiguration)
if in.FeatureGates != nil {
in, out := &in.FeatureGates, &out.FeatureGates
*out = make(map[string]bool, len(*in))
@ -234,9 +280,8 @@ func (in *MasterConfiguration) DeepCopy() *MasterConfiguration {
func (in *MasterConfiguration) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
} else {
return nil
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
@ -293,9 +338,8 @@ func (in *NodeConfiguration) DeepCopy() *NodeConfiguration {
func (in *NodeConfiguration) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
} else {
return nil
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
@ -317,11 +361,6 @@ func (in *SelfHostedEtcd) DeepCopy() *SelfHostedEtcd {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TokenDiscovery) DeepCopyInto(out *TokenDiscovery) {
*out = *in
if in.Addresses != nil {
in, out := &in.Addresses, &out.Addresses
*out = make([]string, len(*in))
copy(*out, *in)
}
return
}

View File

@ -36,7 +36,6 @@ go_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/pkiutil:go_default_library",
"//cmd/kubeadm/app/phases/controlplane:go_default_library",
"//cmd/kubeadm/app/phases/etcd:go_default_library",
"//cmd/kubeadm/app/phases/kubeconfig:go_default_library",
@ -47,17 +46,15 @@ go_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/audit:go_default_library",
"//cmd/kubeadm/app/util/config:go_default_library",
"//cmd/kubeadm/app/util/dryrun:go_default_library",
"//cmd/kubeadm/app/util/kubeconfig:go_default_library",
"//cmd/kubeadm/app/util/pubkeypin:go_default_library",
"//cmd/kubeadm/app/util/token:go_default_library",
"//pkg/api/legacyscheme:go_default_library",
"//pkg/apis/core:go_default_library",
"//pkg/bootstrap/api:go_default_library",
"//pkg/kubectl/cmd/util:go_default_library",
"//pkg/kubectl/util/i18n:go_default_library",
"//pkg/printers:go_default_library",
"//pkg/util/initsystem:go_default_library",
"//pkg/util/node:go_default_library",
"//pkg/version:go_default_library",
@ -69,11 +66,12 @@ go_library(
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/fields:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/duration:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/version:go_default_library",
"//vendor/k8s.io/apiserver/pkg/util/flag:go_default_library",
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
"//vendor/k8s.io/client-go/tools/clientcmd:go_default_library",
"//vendor/k8s.io/client-go/tools/bootstrap/token/api:go_default_library",
"//vendor/k8s.io/client-go/util/cert:go_default_library",
"//vendor/k8s.io/utils/exec:go_default_library",
],
@ -85,11 +83,17 @@ go_test(
"reset_test.go",
"token_test.go",
],
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/cmd",
library = ":go_default_library",
embed = [":go_default_library"],
deps = [
"//cmd/kubeadm/app/apis/kubeadm/v1alpha1:go_default_library",
"//cmd/kubeadm/app/constants:go_default_library",
"//cmd/kubeadm/app/preflight: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",
"//vendor/k8s.io/utils/exec:go_default_library",
"//vendor/k8s.io/utils/exec/testing:go_default_library",
],

View File

@ -47,7 +47,7 @@ const defaultBoilerPlate = `
var (
completionLong = dedent.Dedent(`
Output shell completion code for the specified shell (bash or zsh).
The shell code must be evalutated to provide interactive
The shell code must be evaluated to provide interactive
completion of kubeadm commands. This can be done by sourcing it from
the .bash_profile.

View File

@ -65,7 +65,7 @@ func NewCmdConfig(out io.Writer) *cobra.Command {
return cmd
}
// NewCmdConfigUpload returs cobra.Command for "kubeadm config upload" command
// NewCmdConfigUpload returns cobra.Command for "kubeadm config upload" command
func NewCmdConfigUpload(out io.Writer, kubeConfigFile *string) *cobra.Command {
cmd := &cobra.Command{
Use: "upload",
@ -78,7 +78,7 @@ func NewCmdConfigUpload(out io.Writer, kubeConfigFile *string) *cobra.Command {
return cmd
}
// NewCmdConfigView returs cobra.Command for "kubeadm config view" command
// NewCmdConfigView returns cobra.Command for "kubeadm config view" command
func NewCmdConfigView(out io.Writer, kubeConfigFile *string) *cobra.Command {
return &cobra.Command{
Use: "view",
@ -98,7 +98,7 @@ func NewCmdConfigView(out io.Writer, kubeConfigFile *string) *cobra.Command {
}
}
// NewCmdConfigUploadFromFile verifies given kubernetes config file and returs cobra.Command for
// NewCmdConfigUploadFromFile verifies given kubernetes config file and returns cobra.Command for
// "kubeadm config upload from-file" command
func NewCmdConfigUploadFromFile(out io.Writer, kubeConfigFile *string) *cobra.Command {
var cfgPath string
@ -131,7 +131,7 @@ func NewCmdConfigUploadFromFile(out io.Writer, kubeConfigFile *string) *cobra.Co
return cmd
}
// NewCmdConfigUploadFromFlags returs cobra.Command for "kubeadm config upload from-flags" command
// NewCmdConfigUploadFromFlags returns cobra.Command for "kubeadm config upload from-flags" command
func NewCmdConfigUploadFromFlags(out io.Writer, kubeConfigFile *string) *cobra.Command {
cfg := &kubeadmapiext.MasterConfiguration{}
legacyscheme.Scheme.Default(cfg)

View File

@ -30,12 +30,14 @@ import (
"github.com/spf13/cobra"
flag "github.com/spf13/pflag"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/sets"
clientset "k8s.io/client-go/kubernetes"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
kubeadmapiext "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha1"
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation"
cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util"
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
"k8s.io/kubernetes/cmd/kubeadm/app/features"
"k8s.io/kubernetes/cmd/kubeadm/app/images"
@ -44,7 +46,6 @@ import (
clusterinfophase "k8s.io/kubernetes/cmd/kubeadm/app/phases/bootstraptoken/clusterinfo"
nodebootstraptokenphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/bootstraptoken/node"
certsphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/certs"
"k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/pkiutil"
controlplanephase "k8s.io/kubernetes/cmd/kubeadm/app/phases/controlplane"
etcdphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/etcd"
kubeconfigphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig"
@ -55,10 +56,10 @@ import (
"k8s.io/kubernetes/cmd/kubeadm/app/preflight"
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
"k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
auditutil "k8s.io/kubernetes/cmd/kubeadm/app/util/audit"
configutil "k8s.io/kubernetes/cmd/kubeadm/app/util/config"
dryrunutil "k8s.io/kubernetes/cmd/kubeadm/app/util/dryrun"
kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig"
"k8s.io/kubernetes/cmd/kubeadm/app/util/pubkeypin"
"k8s.io/kubernetes/pkg/api/legacyscheme"
utilsexec "k8s.io/utils/exec"
)
@ -80,7 +81,7 @@ var (
You can now join any number of machines by running the following on each node
as root:
kubeadm join --token {{.Token}} {{.MasterHostPort}} --discovery-token-ca-cert-hash {{.CAPubKeyPin}}
{{.joinCommand}}
`)))
@ -91,10 +92,12 @@ var (
This error is likely caused by:
- The kubelet is not running
- The kubelet is unhealthy due to a misconfiguration of the node in some way (required cgroups disabled)
- There is no internet connection, so the kubelet cannot pull the following control plane images:
- Either there is no internet connection, or imagePullPolicy is set to "Never",
so the kubelet cannot pull or find the following control plane images:
- {{ .APIServerImage }}
- {{ .ControllerManagerImage }}
- {{ .SchedulerImage }}
- {{ .EtcdImage }} (only if no external etcd endpoints are configured)
If you are on a systemd-powered system, you can try to troubleshoot the error with the following commands:
- 'systemctl status kubelet'
@ -112,7 +115,6 @@ func NewCmdInit(out io.Writer) *cobra.Command {
var skipTokenPrint bool
var dryRun bool
var featureGatesString string
var criSocket string
var ignorePreflightErrors []string
cmd := &cobra.Command{
@ -131,7 +133,7 @@ func NewCmdInit(out io.Writer) *cobra.Command {
ignorePreflightErrorsSet, err := validation.ValidateIgnorePreflightErrors(ignorePreflightErrors, skipPreFlight)
kubeadmutil.CheckErr(err)
i, err := NewInit(cfgPath, internalcfg, ignorePreflightErrorsSet, skipTokenPrint, dryRun, criSocket)
i, err := NewInit(cfgPath, internalcfg, ignorePreflightErrorsSet, skipTokenPrint, dryRun)
kubeadmutil.CheckErr(err)
kubeadmutil.CheckErr(i.Validate(cmd))
kubeadmutil.CheckErr(i.Run(out))
@ -139,7 +141,7 @@ func NewCmdInit(out io.Writer) *cobra.Command {
}
AddInitConfigFlags(cmd.PersistentFlags(), cfg, &featureGatesString)
AddInitOtherFlags(cmd.PersistentFlags(), &cfgPath, &skipPreFlight, &skipTokenPrint, &dryRun, &criSocket, &ignorePreflightErrors)
AddInitOtherFlags(cmd.PersistentFlags(), &cfgPath, &skipPreFlight, &skipTokenPrint, &dryRun, &ignorePreflightErrors)
return cmd
}
@ -190,12 +192,17 @@ func AddInitConfigFlags(flagSet *flag.FlagSet, cfg *kubeadmapiext.MasterConfigur
&cfg.TokenTTL.Duration, "token-ttl", cfg.TokenTTL.Duration,
"The duration before the bootstrap token is automatically deleted. If set to '0', the token will never expire.",
)
flagSet.StringVar(
&cfg.CRISocket, "cri-socket", cfg.CRISocket,
`Specify the CRI socket to connect to.`,
)
flagSet.StringVar(featureGatesString, "feature-gates", *featureGatesString, "A set of key=value pairs that describe feature gates for various features. "+
"Options are:\n"+strings.Join(features.KnownFeatures(&features.InitFeatureGates), "\n"))
}
// AddInitOtherFlags adds init flags that are not bound to a configuration file to the given flagset
func AddInitOtherFlags(flagSet *flag.FlagSet, cfgPath *string, skipPreFlight, skipTokenPrint, dryRun *bool, criSocket *string, ignorePreflightErrors *[]string) {
func AddInitOtherFlags(flagSet *flag.FlagSet, cfgPath *string, skipPreFlight, skipTokenPrint, dryRun *bool, ignorePreflightErrors *[]string) {
flagSet.StringVar(
cfgPath, "config", *cfgPath,
"Path to kubeadm config file. WARNING: Usage of a configuration file is experimental.",
@ -220,14 +227,10 @@ func AddInitOtherFlags(flagSet *flag.FlagSet, cfgPath *string, skipPreFlight, sk
dryRun, "dry-run", *dryRun,
"Don't apply any changes; just output what would be done.",
)
flagSet.StringVar(
criSocket, "cri-socket", "/var/run/dockershim.sock",
`Specify the CRI socket to connect to.`,
)
}
// NewInit validates given arguments and instantiates Init struct with provided information.
func NewInit(cfgPath string, cfg *kubeadmapi.MasterConfiguration, ignorePreflightErrors sets.String, skipTokenPrint, dryRun bool, criSocket string) (*Init, error) {
func NewInit(cfgPath string, cfg *kubeadmapi.MasterConfiguration, ignorePreflightErrors sets.String, skipTokenPrint, dryRun bool) (*Init, error) {
if cfgPath != "" {
b, err := ioutil.ReadFile(cfgPath)
@ -260,7 +263,7 @@ func NewInit(cfgPath string, cfg *kubeadmapi.MasterConfiguration, ignorePrefligh
fmt.Println("[preflight] Running pre-flight checks.")
if err := preflight.RunInitMasterChecks(utilsexec.New(), cfg, criSocket, ignorePreflightErrors); err != nil {
if err := preflight.RunInitMasterChecks(utilsexec.New(), cfg, ignorePreflightErrors); err != nil {
return nil, err
}
@ -314,6 +317,21 @@ func (i *Init) Run(out io.Writer) error {
fmt.Println("[externalca] The file 'ca.key' was not found, yet all other certificates are present. Using external CA mode - certificates or kubeconfig will not be generated.")
}
if features.Enabled(i.cfg.FeatureGates, features.Auditing) {
// Setup the AuditPolicy (either it was passed in and exists or it wasn't passed in and generate a default policy)
if i.cfg.AuditPolicyConfiguration.Path != "" {
// TODO(chuckha) ensure passed in audit policy is valid so users don't have to find the error in the api server log.
if _, err := os.Stat(i.cfg.AuditPolicyConfiguration.Path); err != nil {
return fmt.Errorf("error getting file info for audit policy file %q [%v]", i.cfg.AuditPolicyConfiguration.Path, err)
}
} else {
i.cfg.AuditPolicyConfiguration.Path = filepath.Join(kubeConfigDir, kubeadmconstants.AuditPolicyDir, kubeadmconstants.AuditPolicyFile)
if err := auditutil.CreateDefaultAuditLogPolicy(i.cfg.AuditPolicyConfiguration.Path); err != nil {
return fmt.Errorf("error creating default audit policy %q [%v]", i.cfg.AuditPolicyConfiguration.Path, err)
}
}
}
// Temporarily set cfg.CertificatesDir to the "real value" when writing controlplane manifests
// This is needed for writing the right kind of manifests
i.cfg.CertificatesDir = realCertsDir
@ -352,7 +370,7 @@ func (i *Init) Run(out io.Writer) error {
}
// waiter holds the apiclient.Waiter implementation of choice, responsible for querying the API server in various ways and waiting for conditions to be fulfilled
waiter := getWaiter(i.dryRun, client)
waiter := getWaiter(i, client)
if err := waitForAPIAndKubelet(waiter); err != nil {
ctx := map[string]string{
@ -360,6 +378,7 @@ func (i *Init) Run(out io.Writer) error {
"APIServerImage": images.GetCoreImage(kubeadmconstants.KubeAPIServer, i.cfg.GetControlPlaneImageRepository(), i.cfg.KubernetesVersion, i.cfg.UnifiedControlPlaneImage),
"ControllerManagerImage": images.GetCoreImage(kubeadmconstants.KubeControllerManager, i.cfg.GetControlPlaneImageRepository(), i.cfg.KubernetesVersion, i.cfg.UnifiedControlPlaneImage),
"SchedulerImage": images.GetCoreImage(kubeadmconstants.KubeScheduler, i.cfg.GetControlPlaneImageRepository(), i.cfg.KubernetesVersion, i.cfg.UnifiedControlPlaneImage),
"EtcdImage": images.GetCoreImage(kubeadmconstants.Etcd, i.cfg.ImageRepository, i.cfg.KubernetesVersion, i.cfg.Etcd.Image),
}
kubeletFailTempl.Execute(out, ctx)
@ -383,7 +402,7 @@ func (i *Init) Run(out io.Writer) error {
}
// PHASE 4: Mark the master with the right label/taint
if err := markmasterphase.MarkMaster(client, i.cfg.NodeName); err != nil {
if err := markmasterphase.MarkMaster(client, i.cfg.NodeName, !i.cfg.NoTaintMaster); err != nil {
return fmt.Errorf("error marking master: %v", err)
}
@ -394,7 +413,7 @@ func (i *Init) Run(out io.Writer) error {
// Create the default node bootstrap token
tokenDescription := "The default bootstrap token generated by 'kubeadm init'."
if err := nodebootstraptokenphase.UpdateOrCreateToken(client, i.cfg.Token, false, i.cfg.TokenTTL.Duration, kubeadmconstants.DefaultTokenUsages, []string{kubeadmconstants.NodeBootstrapTokenAuthGroup}, tokenDescription); err != nil {
if err := nodebootstraptokenphase.UpdateOrCreateToken(client, i.cfg.Token, false, i.cfg.TokenTTL.Duration, i.cfg.TokenUsages, i.cfg.TokenGroups, tokenDescription); err != nil {
return fmt.Errorf("error updating or creating token: %v", err)
}
// Create RBAC rules that makes the bootstrap tokens able to post CSRs
@ -443,26 +462,15 @@ func (i *Init) Run(out io.Writer) error {
return nil
}
// Load the CA certificate from so we can pin its public key
caCert, err := pkiutil.TryLoadCertFromDisk(i.cfg.CertificatesDir, kubeadmconstants.CACertAndKeyBaseName)
// Gets the join command
joinCommand, err := cmdutil.GetJoinCommand(kubeadmconstants.GetAdminKubeConfigPath(), i.cfg.Token, i.skipTokenPrint)
if err != nil {
return fmt.Errorf("error loading ca cert from disk: %v", err)
}
// Generate the Master host/port pair used by initDoneTempl
masterHostPort, err := kubeadmutil.GetMasterHostPort(i.cfg)
if err != nil {
return fmt.Errorf("error getting master host port: %v", err)
return fmt.Errorf("failed to get join command: %v", err)
}
ctx := map[string]string{
"KubeConfigPath": adminKubeConfigPath,
"Token": i.cfg.Token,
"CAPubKeyPin": pubkeypin.Hash(caCert),
"MasterHostPort": masterHostPort,
}
if i.skipTokenPrint {
ctx["Token"] = "<value withheld>"
"joinCommand": joinCommand,
}
return initDoneTempl.Execute(out, ctx)
@ -517,11 +525,18 @@ func printFilesIfDryRunning(dryRun bool, manifestDir string) error {
}
// getWaiter gets the right waiter implementation for the right occasion
func getWaiter(dryRun bool, client clientset.Interface) apiclient.Waiter {
if dryRun {
func getWaiter(i *Init, client clientset.Interface) apiclient.Waiter {
if i.dryRun {
return dryrunutil.NewWaiter()
}
return apiclient.NewKubeWaiter(client, 30*time.Minute, os.Stdout)
timeout := 30 * time.Minute
// No need for a large timeout if we don't expect downloads
if i.cfg.ImagePullPolicy == v1.PullNever {
timeout = 60 * time.Second
}
return apiclient.NewKubeWaiter(client, timeout, os.Stdout)
}
// waitForAPIAndKubelet waits primarily for the API server to come up. If that takes a long time, and the kubelet

View File

@ -106,12 +106,11 @@ func NewCmdJoin(out io.Writer) *cobra.Command {
var skipPreFlight bool
var cfgPath string
var criSocket string
var featureGatesString string
var ignorePreflightErrors []string
cmd := &cobra.Command{
Use: "join [flags]",
Use: "join",
Short: "Run this on any machine you wish to join an existing cluster",
Long: joinLongDescription,
Run: func(cmd *cobra.Command, args []string) {
@ -129,7 +128,7 @@ func NewCmdJoin(out io.Writer) *cobra.Command {
ignorePreflightErrorsSet, err := validation.ValidateIgnorePreflightErrors(ignorePreflightErrors, skipPreFlight)
kubeadmutil.CheckErr(err)
j, err := NewJoin(cfgPath, args, internalcfg, ignorePreflightErrorsSet, criSocket)
j, err := NewJoin(cfgPath, args, internalcfg, ignorePreflightErrorsSet)
kubeadmutil.CheckErr(err)
kubeadmutil.CheckErr(j.Validate(cmd))
kubeadmutil.CheckErr(j.Run(out))
@ -137,7 +136,7 @@ func NewCmdJoin(out io.Writer) *cobra.Command {
}
AddJoinConfigFlags(cmd.PersistentFlags(), cfg, &featureGatesString)
AddJoinOtherFlags(cmd.PersistentFlags(), &cfgPath, &skipPreFlight, &criSocket, &ignorePreflightErrors)
AddJoinOtherFlags(cmd.PersistentFlags(), &cfgPath, &skipPreFlight, &ignorePreflightErrors)
return cmd
}
@ -169,10 +168,14 @@ func AddJoinConfigFlags(flagSet *flag.FlagSet, cfg *kubeadmapiext.NodeConfigurat
featureGatesString, "feature-gates", *featureGatesString,
"A set of key=value pairs that describe feature gates for various features. "+
"Options are:\n"+strings.Join(features.KnownFeatures(&features.InitFeatureGates), "\n"))
flagSet.StringVar(
&cfg.CRISocket, "cri-socket", cfg.CRISocket,
`Specify the CRI socket to connect to.`,
)
}
// AddJoinOtherFlags adds join flags that are not bound to a configuration file to the given flagset
func AddJoinOtherFlags(flagSet *flag.FlagSet, cfgPath *string, skipPreFlight *bool, criSocket *string, ignorePreflightErrors *[]string) {
func AddJoinOtherFlags(flagSet *flag.FlagSet, cfgPath *string, skipPreFlight *bool, ignorePreflightErrors *[]string) {
flagSet.StringVar(
cfgPath, "config", *cfgPath,
"Path to kubeadm config file.")
@ -186,10 +189,6 @@ func AddJoinOtherFlags(flagSet *flag.FlagSet, cfgPath *string, skipPreFlight *bo
"Skip preflight checks which normally run before modifying the system.",
)
flagSet.MarkDeprecated("skip-preflight-checks", "it is now equivalent to --ignore-preflight-errors=all")
flagSet.StringVar(
criSocket, "cri-socket", "/var/run/dockershim.sock",
`Specify the CRI socket to connect to.`,
)
}
// Join defines struct used by kubeadm join command
@ -198,7 +197,7 @@ type Join struct {
}
// NewJoin instantiates Join struct with given arguments
func NewJoin(cfgPath string, args []string, cfg *kubeadmapi.NodeConfiguration, ignorePreflightErrors sets.String, criSocket string) (*Join, error) {
func NewJoin(cfgPath string, args []string, cfg *kubeadmapi.NodeConfiguration, ignorePreflightErrors sets.String) (*Join, error) {
if cfg.NodeName == "" {
cfg.NodeName = nodeutil.GetHostname("")
@ -217,7 +216,7 @@ func NewJoin(cfgPath string, args []string, cfg *kubeadmapi.NodeConfiguration, i
fmt.Println("[preflight] Running pre-flight checks.")
// Then continue with the others...
if err := preflight.RunJoinNodeChecks(utilsexec.New(), cfg, criSocket, ignorePreflightErrors); err != nil {
if err := preflight.RunJoinNodeChecks(utilsexec.New(), cfg, ignorePreflightErrors); err != nil {
return nil, err
}

View File

@ -35,7 +35,6 @@ go_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/pkiutil:go_default_library",
"//cmd/kubeadm/app/phases/controlplane:go_default_library",
"//cmd/kubeadm/app/phases/etcd:go_default_library",
"//cmd/kubeadm/app/phases/kubeconfig:go_default_library",
@ -47,15 +46,15 @@ go_library(
"//cmd/kubeadm/app/util/apiclient:go_default_library",
"//cmd/kubeadm/app/util/config:go_default_library",
"//cmd/kubeadm/app/util/kubeconfig:go_default_library",
"//cmd/kubeadm/app/util/pubkeypin:go_default_library",
"//pkg/api/legacyscheme:go_default_library",
"//pkg/bootstrap/api:go_default_library",
"//pkg/util/normalizer:go_default_library",
"//vendor/github.com/spf13/cobra:go_default_library",
"//vendor/github.com/spf13/pflag:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//vendor/k8s.io/apiserver/pkg/util/flag: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/utils/exec:go_default_library",
],
)
@ -69,8 +68,7 @@ go_test(
"etcd_test.go",
"kubeconfig_test.go",
],
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases",
library = ":go_default_library",
embed = [":go_default_library"],
deps = [
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
"//cmd/kubeadm/app/apis/kubeadm/install:go_default_library",

View File

@ -24,21 +24,18 @@ import (
"github.com/spf13/pflag"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/sets"
clientset "k8s.io/client-go/kubernetes"
bootstrapapi "k8s.io/client-go/tools/bootstrap/token/api"
kubeadmapiext "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha1"
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation"
cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util"
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
"k8s.io/kubernetes/cmd/kubeadm/app/phases/bootstraptoken/clusterinfo"
"k8s.io/kubernetes/cmd/kubeadm/app/phases/bootstraptoken/node"
"k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/pkiutil"
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
configutil "k8s.io/kubernetes/cmd/kubeadm/app/util/config"
kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig"
"k8s.io/kubernetes/cmd/kubeadm/app/util/pubkeypin"
"k8s.io/kubernetes/pkg/api/legacyscheme"
bootstrapapi "k8s.io/kubernetes/pkg/bootstrap/api"
"k8s.io/kubernetes/pkg/util/normalizer"
)
@ -120,7 +117,6 @@ func NewSubCmdBootstrapTokenAll(kubeConfigFile *string) *cobra.Command {
legacyscheme.Scheme.Default(cfg)
var cfgPath, description string
var usages, extraGroups []string
var skipTokenPrint bool
cmd := &cobra.Command{
@ -136,7 +132,7 @@ func NewSubCmdBootstrapTokenAll(kubeConfigFile *string) *cobra.Command {
kubeadmutil.CheckErr(err)
// Creates the bootstap token
err = createBootstrapToken(client, cfgPath, cfg, description, usages, extraGroups, skipTokenPrint)
err = createBootstrapToken(*kubeConfigFile, client, cfgPath, cfg, description, skipTokenPrint)
kubeadmutil.CheckErr(err)
// Create the cluster-info ConfigMap or update if it already exists
@ -162,7 +158,7 @@ func NewSubCmdBootstrapTokenAll(kubeConfigFile *string) *cobra.Command {
}
// Adds flags to the command
addBootstrapTokenFlags(cmd.Flags(), cfg, &cfgPath, &description, &usages, &extraGroups, &skipTokenPrint)
addBootstrapTokenFlags(cmd.Flags(), cfg, &cfgPath, &description, &skipTokenPrint)
return cmd
}
@ -179,7 +175,6 @@ func NewSubCmdBootstrapToken(kubeConfigFile *string) *cobra.Command {
legacyscheme.Scheme.Default(cfg)
var cfgPath, description string
var usages, extraGroups []string
var skipTokenPrint bool
cmd := &cobra.Command{
@ -193,13 +188,13 @@ func NewSubCmdBootstrapToken(kubeConfigFile *string) *cobra.Command {
client, err := kubeconfigutil.ClientSetFromFile(*kubeConfigFile)
kubeadmutil.CheckErr(err)
err = createBootstrapToken(client, cfgPath, cfg, description, usages, extraGroups, skipTokenPrint)
err = createBootstrapToken(*kubeConfigFile, client, cfgPath, cfg, description, skipTokenPrint)
kubeadmutil.CheckErr(err)
},
}
// Adds flags to the command
addBootstrapTokenFlags(cmd.Flags(), cfg, &cfgPath, &description, &usages, &extraGroups, &skipTokenPrint)
addBootstrapTokenFlags(cmd.Flags(), cfg, &cfgPath, &description, &skipTokenPrint)
return cmd
}
@ -282,29 +277,25 @@ func NewSubCmdNodeBootstrapTokenAutoApprove(kubeConfigFile *string) *cobra.Comma
return cmd
}
func addBootstrapTokenFlags(flagSet *pflag.FlagSet, cfg *kubeadmapiext.MasterConfiguration, cfgPath, description *string, usages, extraGroups *[]string, skipTokenPrint *bool) {
func addBootstrapTokenFlags(flagSet *pflag.FlagSet, cfg *kubeadmapiext.MasterConfiguration, cfgPath, description *string, skipTokenPrint *bool) {
flagSet.StringVar(
cfgPath, "config", *cfgPath,
"Path to kubeadm config file (WARNING: Usage of a configuration file is experimental)",
)
flagSet.StringVar(
&cfg.CertificatesDir, "cert-dir", cfg.CertificatesDir,
"The path where certificates are stored",
)
flagSet.StringVar(
&cfg.Token, "token", cfg.Token,
"The token to use for establishing bidirectional trust between nodes and masters",
)
flagSet.DurationVar(
&cfg.TokenTTL.Duration, "ttl", kubeadmconstants.DefaultTokenDuration,
&cfg.TokenTTL.Duration, "ttl", cfg.TokenTTL.Duration,
"The duration before the token is automatically deleted (e.g. 1s, 2m, 3h). If set to '0', the token will never expire",
)
flagSet.StringSliceVar(
usages, "usages", kubeadmconstants.DefaultTokenUsages,
&cfg.TokenUsages, "usages", cfg.TokenUsages,
fmt.Sprintf("Describes the ways in which this token can be used. You can pass --usages multiple times or provide a comma separated list of options. Valid options: [%s]", strings.Join(kubeadmconstants.DefaultTokenUsages, ",")),
)
flagSet.StringSliceVar(
extraGroups, "groups", []string{kubeadmconstants.NodeBootstrapTokenAuthGroup},
&cfg.TokenGroups, "groups", cfg.TokenGroups,
fmt.Sprintf("Extra groups that this token will authenticate as when used for authentication. Must match %q", bootstrapapi.BootstrapGroupPattern),
)
flagSet.StringVar(
@ -317,42 +308,27 @@ func addBootstrapTokenFlags(flagSet *pflag.FlagSet, cfg *kubeadmapiext.MasterCon
)
}
func createBootstrapToken(client clientset.Interface, cfgPath string, cfg *kubeadmapiext.MasterConfiguration, description string, usages, extraGroups []string, skipTokenPrint bool) error {
// adding groups only makes sense for authentication
usagesSet := sets.NewString(usages...)
usageAuthentication := strings.TrimPrefix(bootstrapapi.BootstrapTokenUsageAuthentication, bootstrapapi.BootstrapTokenUsagePrefix)
if len(extraGroups) > 0 && !usagesSet.Has(usageAuthentication) {
return fmt.Errorf("--groups cannot be specified unless --usages includes %q", usageAuthentication)
}
// validate any extra group names
for _, group := range extraGroups {
if err := bootstrapapi.ValidateBootstrapGroupName(group); err != nil {
return err
}
}
func createBootstrapToken(kubeConfigFile string, client clientset.Interface, cfgPath string, cfg *kubeadmapiext.MasterConfiguration, description string, skipTokenPrint bool) error {
// This call returns the ready-to-use configuration based on the configuration file that might or might not exist and the default cfg populated by flags
internalcfg, err := configutil.ConfigFileAndDefaultsToInternalConfig(cfgPath, cfg)
kubeadmutil.CheckErr(err)
// Load the CA certificate from so we can pin its public key
caCert, err := pkiutil.TryLoadCertFromDisk(internalcfg.CertificatesDir, kubeadmconstants.CACertAndKeyBaseName)
if err != nil {
return fmt.Errorf("error loading ca cert from disk: %v", err)
return err
}
// Creates or updates the token
if err := node.UpdateOrCreateToken(client, internalcfg.Token, false, internalcfg.TokenTTL.Duration, usages, extraGroups, description); err != nil {
if err := node.UpdateOrCreateToken(client, internalcfg.Token, false, internalcfg.TokenTTL.Duration, internalcfg.TokenUsages, internalcfg.TokenGroups, description); err != nil {
return err
}
fmt.Println("[bootstraptoken] Bootstrap token Created")
if skipTokenPrint {
internalcfg.Token = "{token}"
}
fmt.Println("[bootstraptoken] You can now join any number of machines by running:")
fmt.Printf("[bootstraptoken] kubeadm join {master} --token %s --discovery-token-ca-cert-hash %s \n", internalcfg.Token, pubkeypin.Hash(caCert))
joinCommand, err := cmdutil.GetJoinCommand(kubeConfigFile, internalcfg.Token, skipTokenPrint)
if err != nil {
return fmt.Errorf("failed to get join command: %v", err)
}
fmt.Println(joinCommand)
return nil
}

View File

@ -60,8 +60,8 @@ var (
apiServerCertLongDesc = fmt.Sprintf(normalizer.LongDesc(`
Generates the API server serving certificate and key and saves them into %s and %s files.
The certificate includes default subject alternative names and additional sans eventually provided by the user;
default sans are: <node-name>, <apiserver-advertise-address>, kubernetes, kubernetes.default, kubernetes.default.svc,
The certificate includes default subject alternative names and additional SANs provided by the user;
default SANs are: <node-name>, <apiserver-advertise-address>, kubernetes, kubernetes.default, kubernetes.default.svc,
kubernetes.default.svc.<service-dns-domain>, <internalAPIServerVirtualIP> (that is the .10 address in <service-cidr> address space).
If both files already exist, kubeadm skips the generation step and existing files will be used.
@ -74,6 +74,31 @@ var (
If both files already exist, kubeadm skips the generation step and existing files will be used.
`+cmdutil.AlphaDisclaimer), kubeadmconstants.APIServerKubeletClientCertName, kubeadmconstants.APIServerKubeletClientKeyName)
etcdServerCertLongDesc = fmt.Sprintf(normalizer.LongDesc(`
Generates the etcd serving certificate and key and saves them into %s and %s files.
The certificate includes default subject alternative names and additional SANs provided by the user;
default SANs are: localhost, 127.0.0.1.
If both files already exist, kubeadm skips the generation step and existing files will be used.
`+cmdutil.AlphaDisclaimer), kubeadmconstants.EtcdServerCertName, kubeadmconstants.EtcdServerKeyName)
etcdPeerCertLongDesc = fmt.Sprintf(normalizer.LongDesc(`
Generates the etcd peer certificate and key and saves them into %s and %s files.
The certificate includes default subject alternative names and additional SANs provided by the user;
default SANs are: <node-name>, <apiserver-advertise-address>.
If both files already exist, kubeadm skips the generation step and existing files will be used.
`+cmdutil.AlphaDisclaimer), kubeadmconstants.EtcdPeerCertName, kubeadmconstants.EtcdPeerKeyName)
apiServerEtcdServerCertLongDesc = fmt.Sprintf(normalizer.LongDesc(`
Generates the client certificate for the API server to connect to etcd securely and the respective key,
and saves them into %s and %s files.
If both files already exist, kubeadm skips the generation step and existing files will be used.
`+cmdutil.AlphaDisclaimer), kubeadmconstants.APIServerEtcdClientCertName, kubeadmconstants.APIServerEtcdClientKeyName)
saKeyLongDesc = fmt.Sprintf(normalizer.LongDesc(`
Generates the private key for signing service account tokens along with its public key, and saves them into
%s and %s files.
@ -114,7 +139,7 @@ func getCertsSubCommands(defaultKubernetesVersion string) []*cobra.Command {
// This is used for unit testing only...
// If we wouldn't set this to something, the code would dynamically look up the version from the internet
// By setting this explicitely for tests workarounds that
// By setting this explicitly for tests workarounds that
if defaultKubernetesVersion != "" {
cfg.KubernetesVersion = defaultKubernetesVersion
}
@ -157,6 +182,24 @@ func getCertsSubCommands(defaultKubernetesVersion string) []*cobra.Command {
long: apiServerKubeletCertLongDesc,
cmdFunc: certsphase.CreateAPIServerKubeletClientCertAndKeyFiles,
},
{
use: "etcd-server",
short: "Generates etcd serving certificate and key",
long: etcdServerCertLongDesc,
cmdFunc: certsphase.CreateEtcdServerCertAndKeyFiles,
},
{
use: "etcd-peer",
short: "Generates etcd peer certificate and key",
long: etcdPeerCertLongDesc,
cmdFunc: certsphase.CreateEtcdPeerCertAndKeyFiles,
},
{
use: "apiserver-etcd-client",
short: "Generates client certificate for the API server to connect to etcd securely",
long: apiServerEtcdServerCertLongDesc,
cmdFunc: certsphase.CreateAPIServerEtcdClientCertAndKeyFiles,
},
{
use: "sa",
short: "Generates a private key for signing service account tokens along with its public key",
@ -206,7 +249,7 @@ func getCertsSubCommands(defaultKubernetesVersion string) []*cobra.Command {
// runCmdFunc creates a cobra.Command Run function, by composing the call to the given cmdFunc with necessary additional steps (e.g preparation of input parameters)
func runCmdFunc(cmdFunc func(cfg *kubeadmapi.MasterConfiguration) error, cfgPath *string, cfg *kubeadmapiext.MasterConfiguration) func(cmd *cobra.Command, args []string) {
// the following statement build a clousure that wraps a call to a cmdFunc, binding
// the following statement build a closure that wraps a call to a cmdFunc, binding
// the function itself with the specific parameters of each sub command.
// Please note that specific parameter should be passed as value, while other parameters - passed as reference -
// are shared between sub commands and gets access to current value e.g. flags value.

View File

@ -34,7 +34,7 @@ import (
)
// phaseTestK8sVersion is a fake kubernetes version to use when testing
const phaseTestK8sVersion = "v1.8.0"
const phaseTestK8sVersion = "v1.9.0"
func TestCertsSubCommandsHasFlags(t *testing.T) {

View File

@ -22,6 +22,7 @@ import (
"github.com/spf13/cobra"
utilflag "k8s.io/apiserver/pkg/util/flag"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
kubeadmapiext "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha1"
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation"
@ -82,7 +83,7 @@ func getControlPlaneSubCommands(outDir, defaultKubernetesVersion string) []*cobr
// This is used for unit testing only...
// If we wouldn't set this to something, the code would dynamically look up the version from the internet
// By setting this explicitely for tests workarounds that
// By setting this explicitly for tests workarounds that
if defaultKubernetesVersion != "" {
cfg.KubernetesVersion = defaultKubernetesVersion
}
@ -142,15 +143,21 @@ func getControlPlaneSubCommands(outDir, defaultKubernetesVersion string) []*cobr
cmd.Flags().StringVar(&cfg.KubernetesVersion, "kubernetes-version", cfg.KubernetesVersion, `Choose a specific Kubernetes version for the control plane`)
if properties.use == "all" || properties.use == "apiserver" {
cmd.Flags().StringVar(&cfg.API.AdvertiseAddress, "apiserver-advertise-address", cfg.API.AdvertiseAddress, "The IP address or DNS name the API server is accessible on")
cmd.Flags().StringVar(&cfg.API.AdvertiseAddress, "apiserver-advertise-address", cfg.API.AdvertiseAddress, "The IP address of the API server is accessible on")
cmd.Flags().Int32Var(&cfg.API.BindPort, "apiserver-bind-port", cfg.API.BindPort, "The port the API server is accessible on")
cmd.Flags().StringVar(&cfg.Networking.ServiceSubnet, "service-cidr", cfg.Networking.ServiceSubnet, "The range of IP address used for service VIPs")
cmd.Flags().StringVar(&featureGatesString, "feature-gates", featureGatesString, "A set of key=value pairs that describe feature gates for various features. "+
"Options are:\n"+strings.Join(features.KnownFeatures(&features.InitFeatureGates), "\n"))
cmd.Flags().Var(utilflag.NewMapStringString(&cfg.APIServerExtraArgs), "apiserver-extra-args", "A set of extra flags to pass to the API Server or override default ones in form of <flagname>=<value>")
}
if properties.use == "all" || properties.use == "controller-manager" {
cmd.Flags().StringVar(&cfg.Networking.PodSubnet, "pod-network-cidr", cfg.Networking.PodSubnet, "The range of IP addresses used for the Pod network")
cmd.Flags().Var(utilflag.NewMapStringString(&cfg.ControllerManagerExtraArgs), "controller-manager-extra-args", "A set of extra flags to pass to the Controller Manager or override default ones in form of <flagname>=<value>")
}
if properties.use == "all" || properties.use == "scheduler" {
cmd.Flags().Var(utilflag.NewMapStringString(&cfg.SchedulerExtraArgs), "scheduler-extra-args", "A set of extra flags to pass to the Scheduler or override default ones in form of <flagname>=<value>")
}
cmd.Flags().StringVar(&cfgPath, "config", cfgPath, "Path to kubeadm config file (WARNING: Usage of a configuration file is experimental)")
@ -164,7 +171,7 @@ func getControlPlaneSubCommands(outDir, defaultKubernetesVersion string) []*cobr
// runCmdControlPlane creates a cobra.Command Run function, by composing the call to the given cmdFunc with necessary additional steps (e.g preparation of input parameters)
func runCmdControlPlane(cmdFunc func(outDir string, cfg *kubeadmapi.MasterConfiguration) error, outDir, cfgPath *string, featureGatesString *string, cfg *kubeadmapiext.MasterConfiguration) func(cmd *cobra.Command, args []string) {
// the following statement build a clousure that wraps a call to a cmdFunc, binding
// the following statement build a closure that wraps a call to a cmdFunc, binding
// the function itself with the specific parameters of each sub command.
// Please note that specific parameter should be passed as value, while other parameters - passed as reference -
// are shared between sub commands and gets access to current value e.g. flags value.

View File

@ -93,7 +93,7 @@ func TestControlPlaneCreateFilesWithFlags(t *testing.T) {
{
command: "all",
additionalFlags: []string{
"--kubernetes-version=v1.8.0",
"--kubernetes-version=v1.9.0",
"--apiserver-advertise-address=1.2.3.4",
"--apiserver-bind-port=6443",
"--service-cidr=1.2.3.4/16",
@ -108,7 +108,7 @@ func TestControlPlaneCreateFilesWithFlags(t *testing.T) {
{
command: "apiserver",
additionalFlags: []string{
"--kubernetes-version=v1.8.0",
"--kubernetes-version=v1.9.0",
"--apiserver-advertise-address=1.2.3.4",
"--apiserver-bind-port=6443",
"--service-cidr=1.2.3.4/16",
@ -118,7 +118,7 @@ func TestControlPlaneCreateFilesWithFlags(t *testing.T) {
{
command: "controller-manager",
additionalFlags: []string{
"--kubernetes-version=v1.8.0",
"--kubernetes-version=v1.9.0",
"--pod-network-cidr=1.2.3.4/16",
},
expectedFiles: []string{"kube-controller-manager.yaml"},
@ -126,7 +126,7 @@ func TestControlPlaneCreateFilesWithFlags(t *testing.T) {
{
command: "scheduler",
additionalFlags: []string{
"--kubernetes-version=v1.8.0",
"--kubernetes-version=v1.9.0",
},
expectedFiles: []string{"kube-scheduler.yaml"},
},

View File

@ -65,7 +65,7 @@ func getEtcdSubCommands(outDir, defaultKubernetesVersion string) []*cobra.Comman
// This is used for unit testing only...
// If we wouldn't set this to something, the code would dynamically look up the version from the internet
// By setting this explicitely for tests workarounds that
// By setting this explicitly for tests workarounds that
if defaultKubernetesVersion != "" {
cfg.KubernetesVersion = defaultKubernetesVersion
}

View File

@ -94,7 +94,7 @@ func getKubeConfigSubCommands(out io.Writer, outDir, defaultKubernetesVersion st
// This is used for unit testing only...
// If we wouldn't set this to something, the code would dynamically look up the version from the internet
// By setting this explicitely for tests workarounds that
// By setting this explicitly for tests workarounds that
if defaultKubernetesVersion != "" {
cfg.KubernetesVersion = defaultKubernetesVersion
}

View File

@ -170,10 +170,10 @@ func TestKubeConfigSubCommandsThatCreateFilesWithFlags(t *testing.T) {
outputdir := tmpdir
// Retrives ca cert for assertions
// Retrieves ca cert for assertions
caCert, _, err := pkiutil.TryLoadCertAndKeyFromDisk(pkidir, kubeadmconstants.CACertAndKeyBaseName)
if err != nil {
t.Fatalf("couldn't retrive ca cert: %v", err)
t.Fatalf("couldn't retrieve ca cert: %v", err)
}
// Get subcommands working in the temporary directory
@ -272,10 +272,10 @@ func TestKubeConfigSubCommandsThatCreateFilesWithConfigFile(t *testing.T) {
// Adds a pki folder with a ca certs to the temp folder
pkidir := testutil.SetupPkiDirWithCertificateAuthorithy(t, tmpdir)
// Retrives ca cert for assertions
// Retrieves ca cert for assertions
caCert, _, err := pkiutil.TryLoadCertAndKeyFromDisk(pkidir, kubeadmconstants.CACertAndKeyBaseName)
if err != nil {
t.Fatalf("couldn't retrive ca cert: %v", err)
t.Fatalf("couldn't retrieve ca cert: %v", err)
}
// Adds a master configuration file
@ -327,10 +327,10 @@ func TestKubeConfigSubCommandsThatWritesToOut(t *testing.T) {
outputdir := tmpdir
// Retrives ca cert for assertions
// Retrieves ca cert for assertions
caCert, _, err := pkiutil.TryLoadCertAndKeyFromDisk(pkidir, kubeadmconstants.CACertAndKeyBaseName)
if err != nil {
t.Fatalf("couldn't retrive ca cert: %v", err)
t.Fatalf("couldn't retrieve ca cert: %v", err)
}
commonFlags := []string{

View File

@ -75,7 +75,7 @@ func NewCmdMarkMaster() *cobra.Command {
client, err := kubeconfigutil.ClientSetFromFile(kubeConfigFile)
kubeadmutil.CheckErr(err)
err = markmasterphase.MarkMaster(client, internalcfg.NodeName)
err = markmasterphase.MarkMaster(client, internalcfg.NodeName, !internalcfg.NoTaintMaster)
kubeadmutil.CheckErr(err)
},
}

View File

@ -70,8 +70,7 @@ func NewCmdPreFlightMaster() *cobra.Command {
Example: masterPreflightExample,
Run: func(cmd *cobra.Command, args []string) {
cfg := &kubeadmapi.MasterConfiguration{}
criSocket := ""
err := preflight.RunInitMasterChecks(utilsexec.New(), cfg, criSocket, sets.NewString())
err := preflight.RunInitMasterChecks(utilsexec.New(), cfg, sets.NewString())
kubeadmutil.CheckErr(err)
},
}
@ -88,8 +87,7 @@ func NewCmdPreFlightNode() *cobra.Command {
Example: nodePreflightExample,
Run: func(cmd *cobra.Command, args []string) {
cfg := &kubeadmapi.NodeConfiguration{}
criSocket := ""
err := preflight.RunJoinNodeChecks(utilsexec.New(), cfg, criSocket, sets.NewString())
err := preflight.RunJoinNodeChecks(utilsexec.New(), cfg, sets.NewString())
kubeadmutil.CheckErr(err)
},
}

View File

@ -29,7 +29,7 @@ import (
// runCmdPhase creates a cobra.Command Run function, by composing the call to the given cmdFunc with necessary additional steps (e.g preparation of input parameters)
func runCmdPhase(cmdFunc func(outDir string, cfg *kubeadmapi.MasterConfiguration) error, outDir, cfgPath *string, cfg *kubeadmapiext.MasterConfiguration) func(cmd *cobra.Command, args []string) {
// the following statement build a clousure that wraps a call to a cmdFunc, binding
// the following statement build a closure that wraps a call to a cmdFunc, binding
// the function itself with the specific parameters of each sub command.
// Please note that specific parameter should be passed as value, while other parameters - passed as reference -
// are shared between sub commands and gets access to current value e.g. flags value.

View File

@ -184,7 +184,7 @@ func resetWithCrictl(execer utilsexec.Interface, dockerCheck preflight.Checker,
if criSocketPath != "" {
fmt.Printf("[reset] Cleaning up running containers using crictl with socket %s\n", criSocketPath)
listcmd := fmt.Sprintf(crictlSandboxesParamsFormat, crictlPath, criSocketPath)
output, err := execer.Command("sh", "-c", listcmd).CombinedOutput()
output, err := execer.Command(listcmd).CombinedOutput()
if err != nil {
fmt.Println("[reset] Failed to list running pods using crictl. Trying using docker instead.")
resetWithDocker(execer, dockerCheck)
@ -193,13 +193,13 @@ func resetWithCrictl(execer utilsexec.Interface, dockerCheck preflight.Checker,
sandboxes := strings.Split(string(output), " ")
for _, s := range sandboxes {
stopcmd := fmt.Sprintf(crictlStopParamsFormat, crictlPath, criSocketPath, s)
if err := execer.Command("sh", "-c", stopcmd).Run(); err != nil {
if err := execer.Command(stopcmd).Run(); err != nil {
fmt.Println("[reset] Failed to stop the running containers using crictl. Trying using docker instead.")
resetWithDocker(execer, dockerCheck)
return
}
removecmd := fmt.Sprintf(crictlRemoveParamsFormat, crictlPath, criSocketPath, s)
if err := execer.Command("sh", "-c", removecmd).Run(); err != nil {
if err := execer.Command(removecmd).Run(); err != nil {
fmt.Println("[reset] Failed to remove the running containers using crictl. Trying using docker instead.")
resetWithDocker(execer, dockerCheck)
return
@ -252,6 +252,7 @@ func resetConfigDir(configPathDir, pkiPathDir string) {
filesToClean := []string{
filepath.Join(configPathDir, kubeadmconstants.AdminKubeConfigFileName),
filepath.Join(configPathDir, kubeadmconstants.KubeletKubeConfigFileName),
filepath.Join(configPathDir, kubeadmconstants.KubeletBootstrapKubeConfigFileName),
filepath.Join(configPathDir, kubeadmconstants.ControllerManagerKubeConfigFileName),
filepath.Join(configPathDir, kubeadmconstants.SchedulerKubeConfigFileName),
}

View File

@ -235,7 +235,7 @@ func TestResetWithDocker(t *testing.T) {
func TestResetWithCrictl(t *testing.T) {
fcmd := fakeexec.FakeCmd{
CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
// 2: socket path provided, not runnning with crictl (1x CombinedOutput, 2x Run)
// 2: socket path provided, not running with crictl (1x CombinedOutput, 2x Run)
func() ([]byte, error) { return []byte("1"), nil },
// 3: socket path provided, crictl fails, reset with docker (1x CombinedOuput fail, 1x Run)
func() ([]byte, error) { return nil, errors.New("crictl list err") },
@ -243,7 +243,7 @@ func TestResetWithCrictl(t *testing.T) {
RunScript: []fakeexec.FakeRunAction{
// 1: socket path not provided, running with docker
func() ([]byte, []byte, error) { return nil, nil, nil },
// 2: socket path provided, now runnning with crictl (1x CombinedOutput, 2x Run)
// 2: socket path provided, now running with crictl (1x CombinedOutput, 2x Run)
func() ([]byte, []byte, error) { return nil, nil, nil },
func() ([]byte, []byte, error) { return nil, nil, nil },
// 3: socket path provided, crictl fails, reset with docker (1x CombinedOuput, 1x Run)
@ -273,15 +273,15 @@ func TestResetWithCrictl(t *testing.T) {
t.Errorf("expected a call to docker, got %v", fcmd.RunLog[0])
}
// 2: socket path provided, now runnning with crictl (1x CombinedOutput, 2x Run)
// 2: socket path provided, now running with crictl (1x CombinedOutput, 2x Run)
resetWithCrictl(&fexec, newFakeDockerChecker(nil, nil), "/test.sock", "crictl")
if fcmd.RunCalls != 3 {
t.Errorf("expected 3 calls to Run, got %d", fcmd.RunCalls)
}
if !strings.Contains(fcmd.RunLog[1][2], "crictl") {
if !strings.Contains(fcmd.RunLog[1][0], "crictl") {
t.Errorf("expected a call to crictl, got %v", fcmd.RunLog[0])
}
if !strings.Contains(fcmd.RunLog[2][2], "crictl") {
if !strings.Contains(fcmd.RunLog[2][0], "crictl") {
t.Errorf("expected a call to crictl, got %v", fcmd.RunLog[0])
}
@ -330,7 +330,7 @@ func TestReset(t *testing.T) {
if fcmd.RunCalls != 2 {
t.Errorf("expected 2 call to Run, got %d", fcmd.RunCalls)
}
if !strings.Contains(fcmd.RunLog[0][2], "crictl") {
if !strings.Contains(fcmd.RunLog[0][0], "crictl") {
t.Errorf("expected a call to crictl, got %v", fcmd.RunLog[0])
}

View File

@ -17,15 +17,12 @@ limitations under the License.
package cmd
import (
"bytes"
"crypto/x509"
"fmt"
"io"
"os"
"sort"
"strings"
"text/tabwriter"
"text/template"
"time"
"github.com/renstrom/dedent"
@ -34,28 +31,24 @@ import (
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/duration"
clientset "k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
clientcertutil "k8s.io/client-go/util/cert"
bootstrapapi "k8s.io/client-go/tools/bootstrap/token/api"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
kubeadmapiext "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha1"
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation"
cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util"
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
tokenphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/bootstraptoken/node"
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
"k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
configutil "k8s.io/kubernetes/cmd/kubeadm/app/util/config"
kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig"
"k8s.io/kubernetes/cmd/kubeadm/app/util/pubkeypin"
tokenutil "k8s.io/kubernetes/cmd/kubeadm/app/util/token"
"k8s.io/kubernetes/pkg/api/legacyscheme"
api "k8s.io/kubernetes/pkg/apis/core"
bootstrapapi "k8s.io/kubernetes/pkg/bootstrap/api"
"k8s.io/kubernetes/pkg/printers"
)
var joinCommandTemplate = template.Must(template.New("join").Parse(`` +
`kubeadm join --token {{.Token}} {{.MasterHostPort}}{{range $h := .CAPubKeyPins}} --discovery-token-ca-cert-hash {{$h}}{{end}}`,
))
// NewCmdToken returns cobra.Command for token management
func NewCmdToken(out io.Writer, errW io.Writer) *cobra.Command {
var kubeConfigFile string
@ -95,13 +88,20 @@ func NewCmdToken(out io.Writer, errW io.Writer) *cobra.Command {
tokenCmd.PersistentFlags().BoolVar(&dryRun,
"dry-run", dryRun, "Whether to enable dry-run mode or not")
var usages []string
var extraGroups []string
var tokenDuration time.Duration
var description string
cfg := &kubeadmapiext.MasterConfiguration{
// KubernetesVersion is not used by bootstrap-token, but we set this explicitly to avoid
// the lookup of the version from the internet when executing ConfigFileAndDefaultsToInternalConfig
KubernetesVersion: "v1.9.0",
}
// Default values for the cobra help text
legacyscheme.Scheme.Default(cfg)
var cfgPath, description string
var printJoinCommand bool
createCmd := &cobra.Command{
Use: "create [token]",
Use: "create [token]",
DisableFlagsInUseLine: true,
Short: "Create bootstrap tokens on the server.",
Long: dedent.Dedent(`
This command will create a bootstrap token for you.
@ -112,23 +112,28 @@ func NewCmdToken(out io.Writer, errW io.Writer) *cobra.Command {
If no [token] is given, kubeadm will generate a random token instead.
`),
Run: func(tokenCmd *cobra.Command, args []string) {
token := ""
if len(args) != 0 {
token = args[0]
cfg.Token = args[0]
}
err := validation.ValidateMixedArguments(tokenCmd.Flags())
kubeadmutil.CheckErr(err)
client, err := getClientset(kubeConfigFile, dryRun)
kubeadmutil.CheckErr(err)
err = RunCreateToken(out, client, token, tokenDuration, usages, extraGroups, description, printJoinCommand, kubeConfigFile)
err = RunCreateToken(out, client, cfgPath, cfg, description, printJoinCommand, kubeConfigFile)
kubeadmutil.CheckErr(err)
},
}
createCmd.Flags().DurationVar(&tokenDuration,
"ttl", kubeadmconstants.DefaultTokenDuration, "The duration before the token is automatically deleted (e.g. 1s, 2m, 3h). If set to '0', the token will never expire.")
createCmd.Flags().StringSliceVar(&usages,
"usages", kubeadmconstants.DefaultTokenUsages, fmt.Sprintf("Describes the ways in which this token can be used. You can pass --usages multiple times or provide a comma separated list of options. Valid options: [%s].", strings.Join(kubeadmconstants.DefaultTokenUsages, ",")))
createCmd.Flags().StringSliceVar(&extraGroups,
"groups", []string{kubeadmconstants.NodeBootstrapTokenAuthGroup},
createCmd.Flags().StringVar(&cfgPath,
"config", cfgPath, "Path to kubeadm config file (WARNING: Usage of a configuration file is experimental)")
createCmd.Flags().DurationVar(&cfg.TokenTTL.Duration,
"ttl", cfg.TokenTTL.Duration, "The duration before the token is automatically deleted (e.g. 1s, 2m, 3h). If set to '0', the token will never expire.")
createCmd.Flags().StringSliceVar(&cfg.TokenUsages,
"usages", cfg.TokenUsages, fmt.Sprintf("Describes the ways in which this token can be used. You can pass --usages multiple times or provide a comma separated list of options. Valid options: [%s].", strings.Join(kubeadmconstants.DefaultTokenUsages, ",")))
createCmd.Flags().StringSliceVar(&cfg.TokenGroups,
"groups", cfg.TokenGroups,
fmt.Sprintf("Extra groups that this token will authenticate as when used for authentication. Must match %q.", bootstrapapi.BootstrapGroupPattern))
createCmd.Flags().StringVar(&description,
"description", "", "A human friendly description of how this token is used.")
@ -155,7 +160,8 @@ func NewCmdToken(out io.Writer, errW io.Writer) *cobra.Command {
tokenCmd.AddCommand(listCmd)
deleteCmd := &cobra.Command{
Use: "delete [token-value]",
Use: "delete [token-value]",
DisableFlagsInUseLine: true,
Short: "Delete bootstrap tokens on the server.",
Long: dedent.Dedent(`
This command will delete a given bootstrap token for you.
@ -203,40 +209,14 @@ func NewCmdTokenGenerate(out io.Writer) *cobra.Command {
}
// RunCreateToken generates a new bootstrap token and stores it as a secret on the server.
func RunCreateToken(out io.Writer, client clientset.Interface, token string, tokenDuration time.Duration, usages []string, extraGroups []string, description string, printJoinCommand bool, kubeConfigFile string) error {
if len(token) == 0 {
var err error
token, err = tokenutil.GenerateToken()
if err != nil {
return err
}
} else {
_, _, err := tokenutil.ParseToken(token)
if err != nil {
return err
}
}
// adding groups only makes sense for authentication
usagesSet := sets.NewString(usages...)
usageAuthentication := strings.TrimPrefix(bootstrapapi.BootstrapTokenUsageAuthentication, bootstrapapi.BootstrapTokenUsagePrefix)
if len(extraGroups) > 0 && !usagesSet.Has(usageAuthentication) {
return fmt.Errorf("--groups cannot be specified unless --usages includes %q", usageAuthentication)
}
// validate any extra group names
for _, group := range extraGroups {
if err := bootstrapapi.ValidateBootstrapGroupName(group); err != nil {
return err
}
}
// validate usages
if err := bootstrapapi.ValidateUsages(usages); err != nil {
func RunCreateToken(out io.Writer, client clientset.Interface, cfgPath string, cfg *kubeadmapiext.MasterConfiguration, description string, printJoinCommand bool, kubeConfigFile string) error {
// This call returns the ready-to-use configuration based on the configuration file that might or might not exist and the default cfg populated by flags
internalcfg, err := configutil.ConfigFileAndDefaultsToInternalConfig(cfgPath, cfg)
if err != nil {
return err
}
err := tokenphase.CreateNewToken(client, token, tokenDuration, usages, extraGroups, description)
err = tokenphase.CreateNewToken(client, internalcfg.Token, internalcfg.TokenTTL.Duration, internalcfg.TokenUsages, internalcfg.TokenGroups, description)
if err != nil {
return err
}
@ -244,13 +224,13 @@ func RunCreateToken(out io.Writer, client clientset.Interface, token string, tok
// if --print-join-command was specified, print the full `kubeadm join` command
// otherwise, just print the token
if printJoinCommand {
joinCommand, err := getJoinCommand(token, kubeConfigFile)
joinCommand, err := cmdutil.GetJoinCommand(kubeConfigFile, internalcfg.Token, false)
if err != nil {
return fmt.Errorf("failed to get join command: %v", err)
}
fmt.Fprintln(out, joinCommand)
} else {
fmt.Fprintln(out, token)
fmt.Fprintln(out, internalcfg.Token)
}
return nil
@ -317,7 +297,7 @@ func RunListTokens(out io.Writer, errW io.Writer, client clientset.Interface) er
fmt.Fprintf(errW, "can't parse expiration time of bootstrap token %s\n", secret.Name)
continue
}
ttl = printers.ShortHumanDuration(expireTime.Sub(time.Now()))
ttl = duration.ShortHumanDuration(expireTime.Sub(time.Now()))
expires = expireTime.Format(time.RFC3339)
}
@ -390,55 +370,5 @@ func getClientset(file string, dryRun bool) (clientset.Interface, error) {
}
return apiclient.NewDryRunClient(dryRunGetter, os.Stdout), nil
}
client, err := kubeconfigutil.ClientSetFromFile(file)
return client, err
}
func getJoinCommand(token string, kubeConfigFile string) (string, error) {
// load the kubeconfig file to get the CA certificate and endpoint
config, err := clientcmd.LoadFromFile(kubeConfigFile)
if err != nil {
return "", fmt.Errorf("failed to load kubeconfig: %v", err)
}
// load the default cluster config
clusterConfig := kubeconfigutil.GetClusterFromKubeConfig(config)
if clusterConfig == nil {
return "", fmt.Errorf("failed to get default cluster config")
}
// load CA certificates from the kubeconfig (either from PEM data or by file path)
var caCerts []*x509.Certificate
if clusterConfig.CertificateAuthorityData != nil {
caCerts, err = clientcertutil.ParseCertsPEM(clusterConfig.CertificateAuthorityData)
if err != nil {
return "", fmt.Errorf("failed to parse CA certificate from kubeconfig: %v", err)
}
} else if clusterConfig.CertificateAuthority != "" {
caCerts, err = clientcertutil.CertsFromFile(clusterConfig.CertificateAuthority)
if err != nil {
return "", fmt.Errorf("failed to load CA certificate referenced by kubeconfig: %v", err)
}
} else {
return "", fmt.Errorf("no CA certificates found in kubeconfig")
}
// hash all the CA certs and include their public key pins as trusted values
publicKeyPins := make([]string, 0, len(caCerts))
for _, caCert := range caCerts {
publicKeyPins = append(publicKeyPins, pubkeypin.Hash(caCert))
}
ctx := map[string]interface{}{
"Token": token,
"CAPubKeyPins": publicKeyPins,
"MasterHostPort": strings.Replace(clusterConfig.Server, "https://", "", -1),
}
var out bytes.Buffer
err = joinCommandTemplate.Execute(&out, ctx)
if err != nil {
return "", fmt.Errorf("failed to render join command template: %v", err)
}
return out.String(), nil
return kubeconfigutil.ClientSetFromFile(file)
}

View File

@ -20,6 +20,14 @@ import (
"bytes"
"regexp"
"testing"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/kubernetes/fake"
core "k8s.io/client-go/testing"
kubeadmapiext "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha1"
)
const (
@ -44,3 +52,93 @@ func TestRunGenerateToken(t *testing.T) {
t.Errorf("RunGenerateToken's output did not match expected regex; wanted: [%s], got: [%s]", TokenExpectedRegex, output)
}
}
func TestRunCreateToken(t *testing.T) {
var buf bytes.Buffer
fakeClient := &fake.Clientset{}
fakeClient.AddReactor("get", "secrets", func(action core.Action) (handled bool, ret runtime.Object, err error) {
return true, nil, errors.NewNotFound(v1.Resource("secrets"), "foo")
})
testCases := []struct {
name string
token string
usages []string
extraGroups []string
expectedError bool
}{
{
name: "valid: empty token",
token: "",
usages: []string{"signing", "authentication"},
extraGroups: []string{"system:bootstrappers:foo"},
expectedError: false,
},
{
name: "valid: non-empty token",
token: "abcdef.1234567890123456",
usages: []string{"signing", "authentication"},
extraGroups: []string{"system:bootstrappers:foo"},
expectedError: false,
},
{
name: "valid: no extraGroups",
token: "abcdef.1234567890123456",
usages: []string{"signing", "authentication"},
extraGroups: []string{},
expectedError: false,
},
{
name: "invalid: incorrect token",
token: "123456.AABBCCDDEEFFGGHH",
usages: []string{"signing", "authentication"},
extraGroups: []string{},
expectedError: true,
},
{
name: "invalid: incorrect extraGroups",
token: "abcdef.1234567890123456",
usages: []string{"signing", "authentication"},
extraGroups: []string{"foo"},
expectedError: true,
},
{
name: "invalid: specifying --groups when --usages doesn't include authentication",
token: "abcdef.1234567890123456",
usages: []string{"signing"},
extraGroups: []string{"foo"},
expectedError: true,
},
{
name: "invalid: partially incorrect usages",
token: "abcdef.1234567890123456",
usages: []string{"foo", "authentication"},
extraGroups: []string{"system:bootstrappers:foo"},
expectedError: true,
},
{
name: "invalid: all incorrect usages",
token: "abcdef.1234567890123456",
usages: []string{"foo", "bar"},
extraGroups: []string{"system:bootstrappers:foo"},
expectedError: true,
},
}
for _, tc := range testCases {
cfg := &kubeadmapiext.MasterConfiguration{
// KubernetesVersion is not used by bootstrap-token, but we set this explicitly to avoid
// the lookup of the version from the internet when executing ConfigFileAndDefaultsToInternalConfig
KubernetesVersion: "v1.9.0",
Token: tc.token,
TokenTTL: &metav1.Duration{Duration: 0},
TokenUsages: tc.usages,
TokenGroups: tc.extraGroups,
}
err := RunCreateToken(&buf, fakeClient, "", cfg, "", false, "")
if (err != nil) != tc.expectedError {
t.Errorf("Test case %s: RunCreateToken expected error: %v, saw: %v", tc.name, tc.expectedError, (err != nil))
}
}
}

View File

@ -42,8 +42,7 @@ go_test(
"common_test.go",
"plan_test.go",
],
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/cmd/upgrade",
library = ":go_default_library",
embed = [":go_default_library"],
deps = [
"//cmd/kubeadm/app/apis/kubeadm/v1alpha1:go_default_library",
"//cmd/kubeadm/app/phases/upgrade:go_default_library",

View File

@ -69,7 +69,8 @@ func NewCmdApply(parentFlags *cmdUpgradeFlags) *cobra.Command {
}
cmd := &cobra.Command{
Use: "apply [version]",
Use: "apply [version]",
DisableFlagsInUseLine: true,
Short: "Upgrade your Kubernetes cluster to the specified version.",
Run: func(cmd *cobra.Command, args []string) {
var err error
@ -80,11 +81,26 @@ func NewCmdApply(parentFlags *cmdUpgradeFlags) *cobra.Command {
err = runPreflightChecks(flags.parent.ignorePreflightErrorsSet)
kubeadmutil.CheckErr(err)
err = cmdutil.ValidateExactArgNumber(args, []string{"version"})
kubeadmutil.CheckErr(err)
// If the version is specified in config file, pick up that value.
if flags.parent.cfgPath != "" {
cfg, err := upgrade.FetchConfigurationFromFile(flags.parent.cfgPath)
kubeadmutil.CheckErr(err)
// It's safe to use args[0] here as the slice has been validated above
flags.newK8sVersionStr = args[0]
if cfg.KubernetesVersion != "" {
flags.newK8sVersionStr = cfg.KubernetesVersion
}
}
// If the new version is already specified in config file, version arg is optional.
if flags.newK8sVersionStr == "" {
err = cmdutil.ValidateExactArgNumber(args, []string{"version"})
kubeadmutil.CheckErr(err)
}
// If option was specified in both args and config file, args will overwrite the config file.
if len(args) == 1 {
flags.newK8sVersionStr = args[0]
}
// Default the flags dynamically, based on each others' value
err = SetImplicitFlags(flags)

View File

@ -41,6 +41,10 @@ func TestPrintConfiguration(t *testing.T) {
api:
advertiseAddress: ""
bindPort: 0
controlPlaneEndpoint: ""
auditPolicy:
logDir: ""
path: ""
certificatesDir: ""
cloudProvider: ""
etcd:
@ -59,6 +63,7 @@ func TestPrintConfiguration(t *testing.T) {
podSubnet: ""
serviceSubnet: ""
nodeName: ""
privilegedPods: false
token: ""
unifiedControlPlaneImage: ""
`),
@ -74,6 +79,10 @@ func TestPrintConfiguration(t *testing.T) {
api:
advertiseAddress: ""
bindPort: 0
controlPlaneEndpoint: ""
auditPolicy:
logDir: ""
path: ""
certificatesDir: ""
cloudProvider: ""
etcd:
@ -92,6 +101,7 @@ func TestPrintConfiguration(t *testing.T) {
podSubnet: ""
serviceSubnet: 10.96.0.1/12
nodeName: ""
privilegedPods: false
token: ""
unifiedControlPlaneImage: ""
`),
@ -112,6 +122,10 @@ func TestPrintConfiguration(t *testing.T) {
api:
advertiseAddress: ""
bindPort: 0
controlPlaneEndpoint: ""
auditPolicy:
logDir: ""
path: ""
certificatesDir: ""
cloudProvider: ""
etcd:
@ -135,6 +149,7 @@ func TestPrintConfiguration(t *testing.T) {
podSubnet: ""
serviceSubnet: ""
nodeName: ""
privilegedPods: false
token: ""
unifiedControlPlaneImage: ""
`),

View File

@ -132,8 +132,8 @@ _____________________________________________________________________
After: upgrade.ClusterState{
KubeVersion: "v1.9.0",
KubeadmVersion: "v1.9.0",
DNSVersion: "1.14.7",
EtcdVersion: "3.1.10",
DNSVersion: "1.14.8",
EtcdVersion: "3.1.11",
},
},
},
@ -148,8 +148,8 @@ API Server v1.8.3 v1.9.0
Controller Manager v1.8.3 v1.9.0
Scheduler v1.8.3 v1.9.0
Kube Proxy v1.8.3 v1.9.0
Kube DNS 1.14.5 1.14.7
Etcd 3.0.17 3.1.10
Kube DNS 1.14.5 1.14.8
Etcd 3.0.17 3.1.11
You can now apply the upgrade by executing the following command:
@ -193,8 +193,8 @@ _____________________________________________________________________
After: upgrade.ClusterState{
KubeVersion: "v1.9.0",
KubeadmVersion: "v1.9.0",
DNSVersion: "1.14.7",
EtcdVersion: "3.1.10",
DNSVersion: "1.14.8",
EtcdVersion: "3.1.11",
},
},
},
@ -229,8 +229,8 @@ API Server v1.8.3 v1.9.0
Controller Manager v1.8.3 v1.9.0
Scheduler v1.8.3 v1.9.0
Kube Proxy v1.8.3 v1.9.0
Kube DNS 1.14.5 1.14.7
Etcd 3.0.17 3.1.10
Kube DNS 1.14.5 1.14.8
Etcd 3.0.17 3.1.11
You can now apply the upgrade by executing the following command:
@ -258,8 +258,8 @@ _____________________________________________________________________
After: upgrade.ClusterState{
KubeVersion: "v1.9.0-beta.1",
KubeadmVersion: "v1.9.0-beta.1",
DNSVersion: "1.14.7",
EtcdVersion: "3.1.10",
DNSVersion: "1.14.8",
EtcdVersion: "3.1.11",
},
},
},
@ -274,8 +274,8 @@ API Server v1.8.5 v1.9.0-beta.1
Controller Manager v1.8.5 v1.9.0-beta.1
Scheduler v1.8.5 v1.9.0-beta.1
Kube Proxy v1.8.5 v1.9.0-beta.1
Kube DNS 1.14.5 1.14.7
Etcd 3.0.17 3.1.10
Kube DNS 1.14.5 1.14.8
Etcd 3.0.17 3.1.11
You can now apply the upgrade by executing the following command:
@ -303,8 +303,8 @@ _____________________________________________________________________
After: upgrade.ClusterState{
KubeVersion: "v1.9.0-rc.1",
KubeadmVersion: "v1.9.0-rc.1",
DNSVersion: "1.14.7",
EtcdVersion: "3.1.10",
DNSVersion: "1.14.8",
EtcdVersion: "3.1.11",
},
},
},
@ -319,8 +319,8 @@ API Server v1.8.5 v1.9.0-rc.1
Controller Manager v1.8.5 v1.9.0-rc.1
Scheduler v1.8.5 v1.9.0-rc.1
Kube Proxy v1.8.5 v1.9.0-rc.1
Kube DNS 1.14.5 1.14.7
Etcd 3.0.17 3.1.10
Kube DNS 1.14.5 1.14.8
Etcd 3.0.17 3.1.11
You can now apply the upgrade by executing the following command:

View File

@ -5,20 +5,24 @@ go_library(
srcs = [
"cmdutil.go",
"documentation.go",
"join.go",
],
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util",
visibility = ["//visibility:public"],
deps = [
"//cmd/kubeadm/app/util/kubeconfig:go_default_library",
"//cmd/kubeadm/app/util/pubkeypin:go_default_library",
"//pkg/util/normalizer:go_default_library",
"//vendor/github.com/spf13/cobra:go_default_library",
"//vendor/k8s.io/client-go/tools/clientcmd:go_default_library",
"//vendor/k8s.io/client-go/util/cert:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = ["cmdutil_test.go"],
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util",
library = ":go_default_library",
embed = [":go_default_library"],
)
filegroup(

View File

@ -0,0 +1,89 @@
/*
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 util
import (
"bytes"
"crypto/x509"
"fmt"
"html/template"
"strings"
"k8s.io/client-go/tools/clientcmd"
clientcertutil "k8s.io/client-go/util/cert"
kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig"
"k8s.io/kubernetes/cmd/kubeadm/app/util/pubkeypin"
)
var joinCommandTemplate = template.Must(template.New("join").Parse(`` +
`kubeadm join {{.MasterHostPort}} --token {{.Token}}{{range $h := .CAPubKeyPins}} --discovery-token-ca-cert-hash {{$h}}{{end}}`,
))
// GetJoinCommand returns the kubeadm join command for a given token and
// and kubernetes cluster (the current cluster in the kubeconfig file)
func GetJoinCommand(kubeConfigFile string, token string, skipTokenPrint bool) (string, error) {
// load the kubeconfig file to get the CA certificate and endpoint
config, err := clientcmd.LoadFromFile(kubeConfigFile)
if err != nil {
return "", fmt.Errorf("failed to load kubeconfig: %v", err)
}
// load the default cluster config
clusterConfig := kubeconfigutil.GetClusterFromKubeConfig(config)
if clusterConfig == nil {
return "", fmt.Errorf("failed to get default cluster config")
}
// load CA certificates from the kubeconfig (either from PEM data or by file path)
var caCerts []*x509.Certificate
if clusterConfig.CertificateAuthorityData != nil {
caCerts, err = clientcertutil.ParseCertsPEM(clusterConfig.CertificateAuthorityData)
if err != nil {
return "", fmt.Errorf("failed to parse CA certificate from kubeconfig: %v", err)
}
} else if clusterConfig.CertificateAuthority != "" {
caCerts, err = clientcertutil.CertsFromFile(clusterConfig.CertificateAuthority)
if err != nil {
return "", fmt.Errorf("failed to load CA certificate referenced by kubeconfig: %v", err)
}
} else {
return "", fmt.Errorf("no CA certificates found in kubeconfig")
}
// hash all the CA certs and include their public key pins as trusted values
publicKeyPins := make([]string, 0, len(caCerts))
for _, caCert := range caCerts {
publicKeyPins = append(publicKeyPins, pubkeypin.Hash(caCert))
}
ctx := map[string]interface{}{
"Token": token,
"CAPubKeyPins": publicKeyPins,
"MasterHostPort": strings.Replace(clusterConfig.Server, "https://", "", -1),
}
if skipTokenPrint {
ctx["Token"] = template.HTML("<value withheld>")
}
var out bytes.Buffer
err = joinCommandTemplate.Execute(&out, ctx)
if err != nil {
return "", fmt.Errorf("failed to render join command template: %v", err)
}
return out.String(), nil
}

View File

@ -14,6 +14,7 @@ go_library(
"//pkg/registry/core/service/ipallocator:go_default_library",
"//pkg/util/version:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/client-go/tools/bootstrap/token/api:go_default_library",
],
)
@ -33,7 +34,6 @@ filegroup(
go_test(
name = "go_default_test",
srcs = ["constants_test.go"],
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/constants",
library = ":go_default_library",
embed = [":go_default_library"],
deps = ["//pkg/util/version:go_default_library"],
)

View File

@ -25,6 +25,7 @@ import (
"time"
"k8s.io/api/core/v1"
bootstrapapi "k8s.io/client-go/tools/bootstrap/token/api"
"k8s.io/kubernetes/pkg/registry/core/service/ipallocator"
"k8s.io/kubernetes/pkg/util/version"
)
@ -64,6 +65,33 @@ const (
// APIServerKubeletClientCertCommonName defines kubelet client certificate common name (CN)
APIServerKubeletClientCertCommonName = "kube-apiserver-kubelet-client"
// EtcdServerCertAndKeyBaseName defines etcd's server certificate and key base name
EtcdServerCertAndKeyBaseName = "etcd/server"
// EtcdServerCertName defines etcd's server certificate name
EtcdServerCertName = "etcd/server.crt"
// EtcdServerKeyName defines etcd's server key name
EtcdServerKeyName = "etcd/server.key"
// EtcdServerCertCommonName defines etcd's server certificate common name (CN)
EtcdServerCertCommonName = "kube-etcd"
// EtcdPeerCertAndKeyBaseName defines etcd's peer certificate and key base name
EtcdPeerCertAndKeyBaseName = "etcd/peer"
// EtcdPeerCertName defines etcd's peer certificate name
EtcdPeerCertName = "etcd/peer.crt"
// EtcdPeerKeyName defines etcd's peer key name
EtcdPeerKeyName = "etcd/peer.key"
// EtcdPeerCertCommonName defines etcd's peer certificate common name (CN)
EtcdPeerCertCommonName = "kube-etcd-peer"
// APIServerEtcdClientCertAndKeyBaseName defines etcd client certificate and key base name
APIServerEtcdClientCertAndKeyBaseName = "apiserver-etcd-client"
// APIServerEtcdClientCertName defines etcd client certificate name
APIServerEtcdClientCertName = "apiserver-etcd-client.crt"
// APIServerEtcdClientKeyName defines etcd client key name
APIServerEtcdClientKeyName = "apiserver-etcd-client.key"
// APIServerEtcdClientCertCommonName defines etcd client certificate common name (CN)
APIServerEtcdClientCertCommonName = "kube-apiserver-etcd-client"
// ServiceAccountKeyBaseName defines SA key base name
ServiceAccountKeyBaseName = "sa"
// ServiceAccountPublicKeyName defines SA public key base name
@ -164,10 +192,10 @@ const (
KubeletBaseConfigurationFile = "kubelet"
// MinExternalEtcdVersion indicates minimum external etcd version which kubeadm supports
MinExternalEtcdVersion = "3.0.14"
MinExternalEtcdVersion = "3.1.11"
// DefaultEtcdVersion indicates the default etcd version that kubeadm uses
DefaultEtcdVersion = "3.1.10"
DefaultEtcdVersion = "3.2.14"
// Etcd defines variable used internally when referring to etcd component
Etcd = "etcd"
@ -199,6 +227,22 @@ const (
CoreDNS = "coredns"
// KubeDNS defines a variable used internally when referring to the kube-dns addon for a cluster
KubeDNS = "kube-dns"
// CRICtlPackage defines the go package that installs crictl
CRICtlPackage = "github.com/kubernetes-incubator/cri-tools/cmd/crictl"
// KubeAuditPolicyVolumeName is the name of the volume that will contain the audit policy
KubeAuditPolicyVolumeName = "audit"
// AuditPolicyDir is the directory that will contain the audit policy
AuditPolicyDir = "audit"
// AuditPolicyFile is the name of the audit policy file itself
AuditPolicyFile = "audit.yaml"
// AuditPolicyLogFile is the name of the file audit logs get written to
AuditPolicyLogFile = "audit.log"
// KubeAuditPolicyLogVolumeName is the name of the volume that will contain the audit logs
KubeAuditPolicyLogVolumeName = "audit-log"
// StaticPodAuditPolicyLogDir is the name of the directory in the static pod that will have the audit logs
StaticPodAuditPolicyLogDir = "/var/log/kubernetes/audit"
)
var (
@ -220,25 +264,25 @@ var (
AuthorizationWebhookConfigPath = filepath.Join(KubernetesDir, "webhook_authz.conf")
// DefaultTokenUsages specifies the default functions a token will get
DefaultTokenUsages = []string{"signing", "authentication"}
DefaultTokenUsages = bootstrapapi.KnownTokenUsages
// DefaultTokenGroups specifies the default groups that this token will authenticate as when used for authentication
DefaultTokenGroups = []string{NodeBootstrapTokenAuthGroup}
// MasterComponents defines the master component names
MasterComponents = []string{KubeAPIServer, KubeControllerManager, KubeScheduler}
// MinimumControlPlaneVersion specifies the minimum control plane version kubeadm can deploy
MinimumControlPlaneVersion = version.MustParseSemantic("v1.8.0")
MinimumControlPlaneVersion = version.MustParseSemantic("v1.9.0")
// MinimumKubeletVersion specifies the minimum version of kubelet which kubeadm supports
MinimumKubeletVersion = version.MustParseSemantic("v1.8.0")
// MinimumKubeProxyComponentConfigVersion specifies the minimum version for the kubeProxyComponent
MinimumKubeProxyComponentConfigVersion = version.MustParseSemantic("v1.9.0-alpha.3")
MinimumKubeletVersion = version.MustParseSemantic("v1.9.0")
// SupportedEtcdVersion lists officially supported etcd versions with corresponding kubernetes releases
SupportedEtcdVersion = map[uint8]string{
8: "3.0.17",
9: "3.1.10",
10: "3.1.10",
9: "3.1.11",
10: "3.2.14",
11: "3.2.14",
}
)
@ -310,3 +354,8 @@ func GetDNSIP(svcSubnet string) (net.IP, error) {
return dnsIP, nil
}
// GetStaticPodAuditPolicyFile returns the path to the audit policy file within a static pod
func GetStaticPodAuditPolicyFile() string {
return filepath.Join(KubernetesDir, AuditPolicyDir, AuditPolicyFile)
}

View File

@ -121,44 +121,47 @@ func TestEtcdSupportedVersion(t *testing.T) {
expectedError error
}{
{
kubernetesVersion: "1.8.0",
expectedVersion: version.MustParseSemantic("3.0.17"),
expectedError: nil,
},
{
kubernetesVersion: "1.80.0",
kubernetesVersion: "1.99.0",
expectedVersion: nil,
expectedError: fmt.Errorf("Unsupported or unknown kubernetes version"),
},
{
kubernetesVersion: "1.9.0",
expectedVersion: version.MustParseSemantic("3.1.10"),
expectedVersion: version.MustParseSemantic("3.1.11"),
expectedError: nil,
},
{
kubernetesVersion: "1.9.2",
expectedVersion: version.MustParseSemantic("3.1.11"),
expectedError: nil,
},
{
kubernetesVersion: "1.10.0",
expectedVersion: version.MustParseSemantic("3.1.10"),
expectedVersion: version.MustParseSemantic("3.2.14"),
expectedError: nil,
},
{
kubernetesVersion: "1.8.6",
expectedVersion: version.MustParseSemantic("3.0.17"),
kubernetesVersion: "1.10.1",
expectedVersion: version.MustParseSemantic("3.2.14"),
expectedError: nil,
},
}
for _, rt := range tests {
actualVersion, actualError := EtcdSupportedVersion(rt.kubernetesVersion)
if actualError != nil {
if actualError.Error() != rt.expectedError.Error() {
if rt.expectedError == nil {
t.Errorf("failed EtcdSupportedVersion:\n\texpected no error, but got: %v", actualError)
} else if actualError.Error() != rt.expectedError.Error() {
t.Errorf(
"failed EtcdSupportedVersion:\n\texpected error: %v\n\t actual error: %v",
rt.expectedError,
actualError,
)
}
} else {
if strings.Compare(actualVersion.String(), rt.expectedVersion.String()) != 0 {
if rt.expectedError != nil {
t.Errorf("failed EtcdSupportedVersion:\n\texpected error: %v, but got no error", rt.expectedError)
} else if strings.Compare(actualVersion.String(), rt.expectedVersion.String()) != 0 {
t.Errorf(
"failed EtcdSupportedVersion:\n\texpected version: %s\n\t actual version: %s",
rt.expectedVersion.String(),

View File

@ -23,8 +23,7 @@ go_library(
go_test(
name = "go_default_test",
srcs = ["discovery_test.go"],
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/discovery",
library = ":go_default_library",
embed = [":go_default_library"],
deps = ["//cmd/kubeadm/app/apis/kubeadm:go_default_library"],
)

View File

@ -12,11 +12,11 @@ go_library(
deps = [
"//cmd/kubeadm/app/constants:go_default_library",
"//cmd/kubeadm/app/util/kubeconfig:go_default_library",
"//pkg/bootstrap/api: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/util/wait: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",
],

View File

@ -23,11 +23,11 @@ import (
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/wait"
bootstrapapi "k8s.io/client-go/tools/bootstrap/token/api"
"k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig"
bootstrapapi "k8s.io/kubernetes/pkg/bootstrap/api"
)
// RetrieveValidatedClusterInfo connects to the API Server and makes sure it can talk
@ -75,7 +75,7 @@ func ValidateClusterInfo(clusterinfo *clientcmdapi.Config) (*clientcmdapi.Cluste
clusterinfoCM, err = client.CoreV1().ConfigMaps(metav1.NamespacePublic).Get(bootstrapapi.ConfigMapClusterInfo, metav1.GetOptions{})
if err != nil {
if apierrors.IsForbidden(err) {
// If the request is unauthorized, the cluster admin has not granted access to the cluster info configmap for unauthenicated users
// If the request is unauthorized, the cluster admin has not granted access to the cluster info configmap for unauthenticated users
// In that case, trust the cluster admin and do not refresh the cluster-info credentials
fmt.Printf("[discovery] Could not access the %s ConfigMap for refreshing the cluster-info information, but the TLS cert is valid so proceeding...\n", bootstrapapi.ConfigMapClusterInfo)
return true, nil

View File

@ -11,6 +11,7 @@ go_library(
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/discovery/https",
deps = [
"//cmd/kubeadm/app/discovery/file:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/net:go_default_library",
"//vendor/k8s.io/client-go/tools/clientcmd:go_default_library",
"//vendor/k8s.io/client-go/tools/clientcmd/api:go_default_library",
],

View File

@ -20,6 +20,7 @@ import (
"io/ioutil"
"net/http"
netutil "k8s.io/apimachinery/pkg/util/net"
"k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
"k8s.io/kubernetes/cmd/kubeadm/app/discovery/file"
@ -29,7 +30,8 @@ import (
// securely to the API Server using the provided CA cert and
// optionally refreshes the cluster-info information from the cluster-info ConfigMap
func RetrieveValidatedClusterInfo(httpsURL string) (*clientcmdapi.Cluster, error) {
response, err := http.Get(httpsURL)
client := &http.Client{Transport: netutil.SetOldTransportDefaults(&http.Transport{})}
response, err := client.Get(httpsURL)
if err != nil {
return nil, err
}

View File

@ -15,11 +15,11 @@ go_library(
"//cmd/kubeadm/app/util/kubeconfig:go_default_library",
"//cmd/kubeadm/app/util/pubkeypin:go_default_library",
"//cmd/kubeadm/app/util/token:go_default_library",
"//pkg/bootstrap/api:go_default_library",
"//pkg/controller/bootstrap: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/util/wait: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",
],
@ -41,8 +41,7 @@ filegroup(
go_test(
name = "go_default_test",
srcs = ["token_test.go"],
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/discovery/token",
library = ":go_default_library",
embed = [":go_default_library"],
deps = [
"//cmd/kubeadm/app/util/kubeconfig:go_default_library",
"//vendor/k8s.io/client-go/tools/clientcmd/api:go_default_library",

View File

@ -26,13 +26,13 @@ import (
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/wait"
bootstrapapi "k8s.io/client-go/tools/bootstrap/token/api"
"k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig"
"k8s.io/kubernetes/cmd/kubeadm/app/util/pubkeypin"
tokenutil "k8s.io/kubernetes/cmd/kubeadm/app/util/token"
bootstrapapi "k8s.io/kubernetes/pkg/bootstrap/api"
"k8s.io/kubernetes/pkg/controller/bootstrap"
)
@ -88,7 +88,7 @@ func RetrieveValidatedClusterInfo(discoveryToken string, tokenAPIServers, rootCA
}
detachedJWSToken, ok := insecureClusterInfo.Data[bootstrapapi.JWSSignatureKeyPrefix+tokenID]
if !ok || len(detachedJWSToken) == 0 {
return nil, fmt.Errorf("there is no JWS signed token in the %s ConfigMap. This token id %q is invalid for this cluster, can't connect", bootstrapapi.ConfigMapClusterInfo, tokenID)
return nil, fmt.Errorf("token id %q is invalid for this cluster or it has expired. Use \"kubeadm token create\" on the master node to creating a new valid token", tokenID)
}
if !bootstrap.DetachedTokenIsValid(detachedJWSToken, insecureKubeconfigString, tokenID, tokenSecret) {
return nil, fmt.Errorf("failed to verify JWS signature of received cluster info object, can't trust this API Server")

View File

@ -32,7 +32,6 @@ filegroup(
go_test(
name = "go_default_test",
srcs = ["features_test.go"],
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/features",
library = ":go_default_library",
embed = [":go_default_library"],
deps = ["//vendor/k8s.io/apiserver/pkg/util/feature:go_default_library"],
)

View File

@ -41,6 +41,9 @@ const (
// DynamicKubeletConfig is alpha in v1.9
DynamicKubeletConfig = "DynamicKubeletConfig"
// Auditing is beta in 1.8
Auditing = "Auditing"
)
var v190 = version.MustParseSemantic("v1.9.0-alpha.1")
@ -53,6 +56,7 @@ var InitFeatureGates = FeatureList{
HighAvailability: {FeatureSpec: utilfeature.FeatureSpec{Default: false, PreRelease: utilfeature.Alpha}, MinimumVersion: v190, HiddenInHelpText: true},
CoreDNS: {FeatureSpec: utilfeature.FeatureSpec{Default: false, PreRelease: utilfeature.Alpha}, MinimumVersion: v190},
DynamicKubeletConfig: {FeatureSpec: utilfeature.FeatureSpec{Default: false, PreRelease: utilfeature.Alpha}, MinimumVersion: v190},
Auditing: {FeatureSpec: utilfeature.FeatureSpec{Default: false, PreRelease: utilfeature.Alpha}},
}
// Feature represents a feature being gated

View File

@ -46,7 +46,7 @@ func TestKnownFeatures(t *testing.T) {
if r[1] != f2 {
t.Errorf("KnownFeatures returned %s values, expected %s", r[1], f2)
}
// check the second value is feature3; prerelease should not shown fo GA features; default should be present
// check the second value is feature3; prerelease should not be shown for GA features; default should be present
f3 := "feature3=true|false (default=false)"
if r[2] != f3 {
t.Errorf("KnownFeatures returned %s values, expected %s", r[2], f3)
@ -168,16 +168,16 @@ func TestResolveFeatureGateDependencies(t *testing.T) {
expectedFeatures: map[string]bool{},
},
{ // others flags
inputFeatures: map[string]bool{"SupportIPVSProxyMode": true},
expectedFeatures: map[string]bool{"SupportIPVSProxyMode": true},
inputFeatures: map[string]bool{CoreDNS: true},
expectedFeatures: map[string]bool{CoreDNS: true},
},
{ // just StoreCertsInSecrets flags
inputFeatures: map[string]bool{"StoreCertsInSecrets": true},
expectedFeatures: map[string]bool{"StoreCertsInSecrets": true, "SelfHosting": true},
inputFeatures: map[string]bool{StoreCertsInSecrets: true},
expectedFeatures: map[string]bool{StoreCertsInSecrets: true, SelfHosting: true},
},
{ // just HighAvailability flags
inputFeatures: map[string]bool{"HighAvailability": true},
expectedFeatures: map[string]bool{"HighAvailability": true, "StoreCertsInSecrets": true, "SelfHosting": true},
inputFeatures: map[string]bool{HighAvailability: true},
expectedFeatures: map[string]bool{HighAvailability: true, StoreCertsInSecrets: true, SelfHosting: true},
},
}

View File

@ -19,8 +19,7 @@ go_library(
go_test(
name = "go_default_test",
srcs = ["images_test.go"],
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/images",
library = ":go_default_library",
embed = [":go_default_library"],
deps = ["//cmd/kubeadm/app/constants:go_default_library"],
)

View File

@ -27,7 +27,7 @@ import (
const (
testversion = "v10.1.2-alpha.1.100+0123456789abcdef+SOMETHING"
expected = "v10.1.2-alpha.1.100_0123456789abcdef_SOMETHING"
gcrPrefix = "gcr.io/google_containers"
gcrPrefix = "k8s.gcr.io"
)
func TestGetCoreImage(t *testing.T) {

View File

@ -12,8 +12,7 @@ go_test(
"dns_test.go",
"versions_test.go",
],
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/dns",
library = ":go_default_library",
embed = [":go_default_library"],
deps = [
"//cmd/kubeadm/app/constants:go_default_library",
"//cmd/kubeadm/app/util:go_default_library",
@ -42,7 +41,7 @@ go_library(
"//cmd/kubeadm/app/util/apiclient:go_default_library",
"//pkg/api/legacyscheme:go_default_library",
"//pkg/util/version:go_default_library",
"//vendor/k8s.io/api/apps/v1beta2: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",

View File

@ -20,7 +20,7 @@ import (
"fmt"
"runtime"
apps "k8s.io/api/apps/v1beta2"
apps "k8s.io/api/apps/v1"
"k8s.io/api/core/v1"
rbac "k8s.io/api/rbac/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
@ -75,7 +75,7 @@ func kubeDNSAddon(cfg *kubeadmapi.MasterConfiguration, client clientset.Interfac
// Get the YAML manifest conditionally based on the k8s version
kubeDNSDeploymentBytes := GetKubeDNSManifest(k8sVersion)
dnsDeploymentBytes, err := kubeadmutil.ParseTemplate(kubeDNSDeploymentBytes,
struct{ ImageRepository, Arch, Version, DNSBindAddr, DNSProbeAddr, DNSDomain, DNSProbeType, MasterTaintKey string }{
struct{ ImageRepository, Arch, Version, DNSBindAddr, DNSProbeAddr, DNSDomain, MasterTaintKey string }{
ImageRepository: cfg.ImageRepository,
Arch: runtime.GOARCH,
// Get the kube-dns version conditionally based on the k8s version
@ -83,7 +83,6 @@ func kubeDNSAddon(cfg *kubeadmapi.MasterConfiguration, client clientset.Interfac
DNSBindAddr: dnsBindAddr,
DNSProbeAddr: dnsProbeAddr,
DNSDomain: cfg.Networking.DNSDomain,
DNSProbeType: GetKubeDNSProbeType(k8sVersion),
MasterTaintKey: kubeadmconstants.LabelNodeRoleMaster,
})
if err != nil {
@ -203,7 +202,7 @@ func createCoreDNSAddon(deploymentBytes, serviceBytes, configBytes []byte, clien
coreDNSServiceAccount := &v1.ServiceAccount{}
if err := kuberuntime.DecodeInto(legacyscheme.Codecs.UniversalDecoder(), []byte(CoreDNSServiceAccount), coreDNSServiceAccount); err != nil {
return fmt.Errorf("unable to decode CoreDNS configmap %v", err)
return fmt.Errorf("unable to decode CoreDNS serviceaccount %v", err)
}
// Create the ConfigMap for CoreDNS or update it in case it already exists

View File

@ -92,14 +92,13 @@ func TestCompileManifests(t *testing.T) {
}{
{
manifest: v180AndAboveKubeDNSDeployment,
data: struct{ ImageRepository, Arch, Version, DNSBindAddr, DNSProbeAddr, DNSDomain, DNSProbeType, MasterTaintKey string }{
data: struct{ ImageRepository, Arch, Version, DNSBindAddr, DNSProbeAddr, DNSDomain, MasterTaintKey string }{
ImageRepository: "foo",
Arch: "foo",
Version: "foo",
DNSBindAddr: "foo",
DNSProbeAddr: "foo",
DNSDomain: "foo",
DNSProbeType: "foo",
MasterTaintKey: "foo",
},
expected: true,

View File

@ -19,7 +19,7 @@ package dns
const (
// v180AndAboveKubeDNSDeployment is the kube-dns Deployment manifest for the kube-dns manifest for v1.7+
v180AndAboveKubeDNSDeployment = `
apiVersion: apps/v1beta2
apiVersion: apps/v1
kind: Deployment
metadata:
name: kube-dns
@ -156,8 +156,8 @@ spec:
args:
- --v=2
- --logtostderr
- --probe=kubedns,{{ .DNSProbeAddr }}:10053,kubernetes.default.svc.{{ .DNSDomain }},5,{{ .DNSProbeType }}
- --probe=dnsmasq,{{ .DNSProbeAddr }}:53,kubernetes.default.svc.{{ .DNSDomain }},5,{{ .DNSProbeType }}
- --probe=kubedns,{{ .DNSProbeAddr }}:10053,kubernetes.default.svc.{{ .DNSDomain }},5,SRV
- --probe=dnsmasq,{{ .DNSProbeAddr }}:53,kubernetes.default.svc.{{ .DNSDomain }},5,SRV
ports:
- containerPort: 10054
name: metrics
@ -216,7 +216,7 @@ spec:
// CoreDNSDeployment is the CoreDNS Deployment manifest
CoreDNSDeployment = `
apiVersion: apps/v1beta2
apiVersion: apps/v1
kind: Deployment
metadata:
name: coredns
@ -224,7 +224,11 @@ metadata:
labels:
k8s-app: kube-dns
spec:
replicas: 1
replicas: 2
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
selector:
matchLabels:
k8s-app: kube-dns
@ -239,6 +243,18 @@ spec:
operator: Exists
- key: {{ .MasterTaintKey }}
effect: NoSchedule
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: k8s-app
operator: In
values:
- coredns
topologyKey: kubernetes.io/hostname
containers:
- name: coredns
image: coredns/coredns:{{ .Version }}
@ -260,9 +276,6 @@ spec:
- containerPort: 53
name: dns-tcp
protocol: TCP
- containerPort: 9153
name: metrics
protocol: TCP
livenessProbe:
httpGet:
path: /health
@ -293,12 +306,13 @@ data:
Corefile: |
.:53 {
errors
log
health
kubernetes {{ .DNSDomain }} {{ .ServiceCIDR }} {
pods insecure
upstream /etc/resolv.conf
fallthrough in-addr.arpa ip6.arpa
}
prometheus
prometheus :9153
proxy . /etc/resolv.conf
cache 30
}

View File

@ -22,48 +22,26 @@ import (
)
const (
kubeDNSv180AndAboveVersion = "1.14.5"
kubeDNSv190AndAboveVersion = "1.14.7"
kubeDNSProbeSRV = "SRV"
kubeDNSProbeA = "A"
coreDNSVersion = "1.0.1"
kubeDNSv190AndAboveVersion = "1.14.8"
coreDNSVersion = "1.0.4"
)
// GetDNSVersion returns the right kube-dns version for a specific k8s version
func GetDNSVersion(kubeVersion *version.Version, dns string) string {
// v1.8.0+ uses kube-dns 1.14.5
// v1.9.0+ uses kube-dns 1.14.7
// v1.9.0+ uses CoreDNS 1.0.1
// v1.9.0+ uses kube-dns 1.14.8
// v1.9.0+ uses CoreDNS 1.0.4 if feature gate "CoreDNS" is enabled.
// In the future when the version is bumped at HEAD; add conditional logic to return the right versions
// Also, the version might be bumped for different k8s releases on the same branch
switch dns {
case kubeadmconstants.KubeDNS:
// return the kube-dns version
if kubeVersion.Major() == 1 && kubeVersion.Minor() >= 9 {
return kubeDNSv190AndAboveVersion
}
return kubeDNSv180AndAboveVersion
case kubeadmconstants.CoreDNS:
// return the CoreDNS version
return coreDNSVersion
default:
return kubeDNSv180AndAboveVersion
return kubeDNSv190AndAboveVersion
}
}
// GetKubeDNSProbeType returns the right kube-dns probe for a specific k8s version
func GetKubeDNSProbeType(kubeVersion *version.Version) string {
// v1.8.0+ uses type A, just return that here
// In the future when the kube-dns version is bumped at HEAD; add conditional logic to return the right versions
// Also, the version might be bumped for different k8s releases on the same branch
if kubeVersion.Major() == 1 && kubeVersion.Minor() >= 9 {
return kubeDNSProbeSRV
}
return kubeDNSProbeA
}
// GetKubeDNSManifest returns the right kube-dns YAML manifest for a specific k8s version
func GetKubeDNSManifest(kubeVersion *version.Version) string {
// v1.8.0+ has only one known YAML manifest spec, just return that here

View File

@ -25,45 +25,38 @@ import (
func TestGetKubeDNSVersion(t *testing.T) {
var tests = []struct {
k8sVersion, expected string
k8sVersion string
dns string
expected string
}{
{
k8sVersion: "v1.7.0",
expected: "1.14.5",
k8sVersion: "v1.9.0",
dns: kubeadmconstants.KubeDNS,
expected: kubeDNSv190AndAboveVersion,
},
{
k8sVersion: "v1.7.1",
expected: "1.14.5",
},
{
k8sVersion: "v1.7.2",
expected: "1.14.5",
},
{
k8sVersion: "v1.7.3",
expected: "1.14.5",
},
{
k8sVersion: "v1.8.0-alpha.2",
expected: "1.14.5",
},
{
k8sVersion: "v1.8.0",
expected: "1.14.5",
k8sVersion: "v1.10.0",
dns: kubeadmconstants.KubeDNS,
expected: kubeDNSv190AndAboveVersion,
},
{
k8sVersion: "v1.9.0",
expected: "1.14.7",
dns: kubeadmconstants.CoreDNS,
expected: coreDNSVersion,
},
{
k8sVersion: "v1.10.0",
dns: kubeadmconstants.CoreDNS,
expected: coreDNSVersion,
},
}
for _, rt := range tests {
k8sVersion, err := version.ParseSemantic(rt.k8sVersion)
if err != nil {
t.Fatalf("couldn't parse kubernetes version %q: %v", rt.k8sVersion, err)
}
actualDNSVersion := GetDNSVersion(k8sVersion, kubeadmconstants.KubeDNS)
actualDNSVersion := GetDNSVersion(k8sVersion, rt.dns)
if actualDNSVersion != rt.expected {
t.Errorf(
"failed GetDNSVersion:\n\texpected: %s\n\t actual: %s",
@ -73,54 +66,3 @@ func TestGetKubeDNSVersion(t *testing.T) {
}
}
}
func TestGetKubeDNSProbeType(t *testing.T) {
var tests = []struct {
k8sVersion, expected string
}{
{
k8sVersion: "v1.7.0",
expected: "A",
},
{
k8sVersion: "v1.7.1",
expected: "A",
},
{
k8sVersion: "v1.7.2",
expected: "A",
},
{
k8sVersion: "v1.7.3",
expected: "A",
},
{
k8sVersion: "v1.8.0-alpha.2",
expected: "A",
},
{
k8sVersion: "v1.8.0",
expected: "A",
},
{
k8sVersion: "v1.9.0",
expected: "SRV",
},
}
for _, rt := range tests {
k8sVersion, err := version.ParseSemantic(rt.k8sVersion)
if err != nil {
t.Fatalf("couldn't parse kubernetes version %q: %v", rt.k8sVersion, err)
}
actualDNSProbeType := GetKubeDNSProbeType(k8sVersion)
if actualDNSProbeType != rt.expected {
t.Errorf(
"failed GetKubeDNSProbeType:\n\texpected: %s\n\t actual: %s",
rt.expected,
actualDNSProbeType,
)
}
}
}

View File

@ -9,8 +9,7 @@ load(
go_test(
name = "go_default_test",
srcs = ["proxy_test.go"],
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/proxy",
library = ":go_default_library",
embed = [":go_default_library"],
deps = [
"//cmd/kubeadm/app/apis/kubeadm/v1alpha1:go_default_library",
"//cmd/kubeadm/app/util:go_default_library",
@ -41,9 +40,8 @@ go_library(
"//pkg/api/legacyscheme:go_default_library",
"//pkg/proxy/apis/kubeproxyconfig/scheme:go_default_library",
"//pkg/proxy/apis/kubeproxyconfig/v1alpha1:go_default_library",
"//pkg/util/version:go_default_library",
"//plugin/pkg/scheduler/algorithm:go_default_library",
"//vendor/k8s.io/api/apps/v1beta2:go_default_library",
"//pkg/scheduler/algorithm: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",

View File

@ -17,37 +17,6 @@ limitations under the License.
package proxy
const (
// KubeProxyConfigMap18 is the proxy ConfigMap manifest for Kubernetes version 1.8
KubeProxyConfigMap18 = `
kind: ConfigMap
apiVersion: v1
metadata:
name: kube-proxy
namespace: kube-system
labels:
app: kube-proxy
data:
kubeconfig.conf: |
apiVersion: v1
kind: Config
clusters:
- cluster:
certificate-authority: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
server: {{ .MasterEndpoint }}
name: default
contexts:
- context:
cluster: default
namespace: default
user: default
name: default
current-context: default
users:
- name: default
user:
tokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
`
// KubeProxyConfigMap19 is the proxy ConfigMap manifest for Kubernetes 1.9 and above
KubeProxyConfigMap19 = `
kind: ConfigMap
@ -79,70 +48,11 @@ data:
tokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
config.conf: |-
{{ .ProxyConfig}}
`
// KubeProxyDaemonSet18 is the proxy DaemonSet manifest for Kubernetes version 1.8
KubeProxyDaemonSet18 = `
apiVersion: apps/v1beta2
kind: DaemonSet
metadata:
labels:
k8s-app: kube-proxy
name: kube-proxy
namespace: kube-system
spec:
selector:
matchLabels:
k8s-app: kube-proxy
updateStrategy:
type: RollingUpdate
template:
metadata:
labels:
k8s-app: kube-proxy
spec:
containers:
- name: kube-proxy
image: {{ if .ImageOverride }}{{ .ImageOverride }}{{ else }}{{ .ImageRepository }}/kube-proxy-{{ .Arch }}:{{ .Version }}{{ end }}
imagePullPolicy: IfNotPresent
command:
- /usr/local/bin/kube-proxy
- --kubeconfig=/var/lib/kube-proxy/kubeconfig.conf
{{ .ClusterCIDR }}
securityContext:
privileged: true
volumeMounts:
- mountPath: /var/lib/kube-proxy
name: kube-proxy
- mountPath: /run/xtables.lock
name: xtables-lock
readOnly: false
- mountPath: /lib/modules
name: lib-modules
readOnly: true
hostNetwork: true
serviceAccountName: kube-proxy
tolerations:
- key: {{ .MasterTaintKey }}
effect: NoSchedule
- key: {{ .CloudTaintKey }}
value: "true"
effect: NoSchedule
volumes:
- name: kube-proxy
configMap:
name: kube-proxy
- name: xtables-lock
hostPath:
path: /run/xtables.lock
type: FileOrCreate
- name: lib-modules
hostPath:
path: /lib/modules
`
// KubeProxyDaemonSet19 is the proxy DaemonSet manifest for Kubernetes 1.9 and above
KubeProxyDaemonSet19 = `
apiVersion: apps/v1beta2
apiVersion: apps/v1
kind: DaemonSet
metadata:
labels:

View File

@ -17,10 +17,11 @@ limitations under the License.
package proxy
import (
"bytes"
"fmt"
"runtime"
apps "k8s.io/api/apps/v1beta2"
apps "k8s.io/api/apps/v1"
"k8s.io/api/core/v1"
rbac "k8s.io/api/rbac/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -33,8 +34,7 @@ import (
"k8s.io/kubernetes/pkg/api/legacyscheme"
kubeproxyconfigscheme "k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig/scheme"
kubeproxyconfigv1alpha1 "k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig/v1alpha1"
"k8s.io/kubernetes/pkg/util/version"
"k8s.io/kubernetes/plugin/pkg/scheduler/algorithm"
"k8s.io/kubernetes/pkg/scheduler/algorithm"
)
const (
@ -58,63 +58,35 @@ func EnsureProxyAddon(cfg *kubeadmapi.MasterConfiguration, client clientset.Inte
return err
}
proxyBytes, err := kubeadmutil.MarshalToYamlForCodecsWithShift(cfg.KubeProxy.Config, kubeproxyconfigv1alpha1.SchemeGroupVersion,
proxyBytes, err := kubeadmutil.MarshalToYamlForCodecs(cfg.KubeProxy.Config, kubeproxyconfigv1alpha1.SchemeGroupVersion,
kubeproxyconfigscheme.Codecs)
if err != nil {
return fmt.Errorf("error when marshaling: %v", err)
}
// Parse the given kubernetes version
k8sVersion, err := version.ParseSemantic(cfg.KubernetesVersion)
if err != nil {
return fmt.Errorf("couldn't parse kubernetes version %q: %v", cfg.KubernetesVersion, err)
}
var prefixBytes bytes.Buffer
apiclient.PrintBytesWithLinePrefix(&prefixBytes, proxyBytes, " ")
var proxyConfigMapBytes, proxyDaemonSetBytes []byte
if k8sVersion.AtLeast(kubeadmconstants.MinimumKubeProxyComponentConfigVersion) {
proxyConfigMapBytes, err = kubeadmutil.ParseTemplate(KubeProxyConfigMap19,
struct {
MasterEndpoint string
ProxyConfig string
}{
MasterEndpoint: masterEndpoint,
ProxyConfig: proxyBytes,
})
if err != nil {
return fmt.Errorf("error when parsing kube-proxy configmap template: %v", err)
}
proxyDaemonSetBytes, err = kubeadmutil.ParseTemplate(KubeProxyDaemonSet19, struct{ ImageRepository, Arch, Version, ImageOverride, ClusterCIDR, MasterTaintKey, CloudTaintKey string }{
ImageRepository: cfg.GetControlPlaneImageRepository(),
Arch: runtime.GOARCH,
Version: kubeadmutil.KubernetesVersionToImageTag(cfg.KubernetesVersion),
ImageOverride: cfg.UnifiedControlPlaneImage,
MasterTaintKey: kubeadmconstants.LabelNodeRoleMaster,
CloudTaintKey: algorithm.TaintExternalCloudProvider,
proxyConfigMapBytes, err = kubeadmutil.ParseTemplate(KubeProxyConfigMap19,
struct {
MasterEndpoint string
ProxyConfig string
}{
MasterEndpoint: masterEndpoint,
ProxyConfig: prefixBytes.String(),
})
if err != nil {
return fmt.Errorf("error when parsing kube-proxy daemonset template: %v", err)
}
} else {
proxyConfigMapBytes, err = kubeadmutil.ParseTemplate(KubeProxyConfigMap18,
struct {
MasterEndpoint string
}{
MasterEndpoint: masterEndpoint,
})
if err != nil {
return fmt.Errorf("error when parsing kube-proxy configmap template: %v", err)
}
proxyDaemonSetBytes, err = kubeadmutil.ParseTemplate(KubeProxyDaemonSet18, struct{ ImageRepository, Arch, Version, ImageOverride, ClusterCIDR, MasterTaintKey, CloudTaintKey string }{
ImageRepository: cfg.GetControlPlaneImageRepository(),
Arch: runtime.GOARCH,
Version: kubeadmutil.KubernetesVersionToImageTag(cfg.KubernetesVersion),
ImageOverride: cfg.UnifiedControlPlaneImage,
ClusterCIDR: getClusterCIDR(cfg.Networking.PodSubnet),
MasterTaintKey: kubeadmconstants.LabelNodeRoleMaster,
CloudTaintKey: algorithm.TaintExternalCloudProvider,
})
if err != nil {
return fmt.Errorf("error when parsing kube-proxy daemonset template: %v", err)
}
if err != nil {
return fmt.Errorf("error when parsing kube-proxy configmap template: %v", err)
}
proxyDaemonSetBytes, err = kubeadmutil.ParseTemplate(KubeProxyDaemonSet19, struct{ ImageRepository, Arch, Version, ImageOverride, MasterTaintKey, CloudTaintKey string }{
ImageRepository: cfg.GetControlPlaneImageRepository(),
Arch: runtime.GOARCH,
Version: kubeadmutil.KubernetesVersionToImageTag(cfg.KubernetesVersion),
ImageOverride: cfg.UnifiedControlPlaneImage,
MasterTaintKey: kubeadmconstants.LabelNodeRoleMaster,
CloudTaintKey: algorithm.TaintExternalCloudProvider,
})
if err != nil {
return fmt.Errorf("error when parsing kube-proxy daemonset template: %v", err)
}
if err := createKubeProxyAddon(proxyConfigMapBytes, proxyDaemonSetBytes, client); err != nil {
return err
@ -182,10 +154,3 @@ func createClusterRoleBindings(client clientset.Interface) error {
},
})
}
func getClusterCIDR(podsubnet string) string {
if len(podsubnet) == 0 {
return ""
}
return "- --cluster-cidr=" + podsubnet
}

View File

@ -90,38 +90,12 @@ func TestCreateServiceAccount(t *testing.T) {
}
}
func TestGetClusterCIDR(t *testing.T) {
emptyClusterCIDR := getClusterCIDR("")
if emptyClusterCIDR != "" {
t.Errorf("Invalid format: %s", emptyClusterCIDR)
}
clusterCIDR := getClusterCIDR("10.244.0.0/16")
if clusterCIDR != "- --cluster-cidr=10.244.0.0/16" {
t.Errorf("Invalid format: %s", clusterCIDR)
}
clusterIPv6CIDR := getClusterCIDR("2001:db8::/64")
if clusterIPv6CIDR != "- --cluster-cidr=2001:db8::/64" {
t.Errorf("Invalid format: %s", clusterIPv6CIDR)
}
}
func TestCompileManifests(t *testing.T) {
var tests = []struct {
manifest string
data interface{}
expected bool
}{
{
manifest: KubeProxyConfigMap18,
data: struct {
MasterEndpoint, ProxyConfig string
}{
MasterEndpoint: "foo",
},
expected: true,
},
{
manifest: KubeProxyConfigMap19,
data: struct {
@ -132,19 +106,6 @@ func TestCompileManifests(t *testing.T) {
},
expected: true,
},
{
manifest: KubeProxyDaemonSet18,
data: struct{ ImageRepository, Arch, Version, ImageOverride, ClusterCIDR, MasterTaintKey, CloudTaintKey string }{
ImageRepository: "foo",
Arch: "foo",
Version: "foo",
ImageOverride: "foo",
ClusterCIDR: "foo",
MasterTaintKey: "foo",
CloudTaintKey: "foo",
},
expected: true,
},
{
manifest: KubeProxyDaemonSet19,
data: struct{ ImageRepository, Arch, Version, ImageOverride, MasterTaintKey, CloudTaintKey string }{
@ -240,7 +201,7 @@ func TestEnsureProxyAddon(t *testing.T) {
UnifiedControlPlaneImage: "someImage",
}
// Simulate an error if neccessary
// Simulate an error if necessary
switch tc.simError {
case ServiceAccountError:
client.PrependReactor("create", "serviceaccounts", func(action core.Action) (bool, runtime.Object, error) {

View File

@ -9,8 +9,7 @@ load(
go_test(
name = "go_default_test",
srcs = ["clusterinfo_test.go"],
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/phases/bootstraptoken/clusterinfo",
library = ":go_default_library",
embed = [":go_default_library"],
deps = [
"//pkg/apis/core:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
@ -27,12 +26,12 @@ go_library(
deps = [
"//cmd/kubeadm/app/util/apiclient:go_default_library",
"//pkg/apis/rbac/v1:go_default_library",
"//pkg/bootstrap/api: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",
],

View File

@ -24,11 +24,11 @@ import (
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"
"k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
rbachelper "k8s.io/kubernetes/pkg/apis/rbac/v1"
bootstrapapi "k8s.io/kubernetes/pkg/bootstrap/api"
)
const (

View File

@ -9,8 +9,7 @@ load(
go_test(
name = "go_default_test",
srcs = ["token_test.go"],
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/phases/bootstraptoken/node",
library = ":go_default_library",
embed = [":go_default_library"],
deps = ["//cmd/kubeadm/app/apis/kubeadm:go_default_library"],
)
@ -25,12 +24,13 @@ go_library(
"//cmd/kubeadm/app/constants:go_default_library",
"//cmd/kubeadm/app/util/apiclient:go_default_library",
"//cmd/kubeadm/app/util/token:go_default_library",
"//pkg/bootstrap/api: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/client-go/kubernetes:go_default_library",
"//vendor/k8s.io/client-go/tools/bootstrap/token/api:go_default_library",
"//vendor/k8s.io/client-go/tools/bootstrap/token/util:go_default_library",
],
)

View File

@ -25,8 +25,9 @@ import (
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
clientset "k8s.io/client-go/kubernetes"
bootstrapapi "k8s.io/client-go/tools/bootstrap/token/api"
bootstraputil "k8s.io/client-go/tools/bootstrap/token/util"
tokenutil "k8s.io/kubernetes/cmd/kubeadm/app/util/token"
bootstrapapi "k8s.io/kubernetes/pkg/bootstrap/api"
)
const tokenCreateRetries = 5
@ -115,7 +116,7 @@ func encodeTokenSecretData(tokenID, tokenSecret string, duration time.Duration,
}
// validate usages
if err := bootstrapapi.ValidateUsages(usages); err != nil {
if err := bootstraputil.ValidateUsages(usages); err != nil {
return nil, err
}
for _, usage := range usages {

View File

@ -9,8 +9,7 @@ load(
go_test(
name = "go_default_test",
srcs = ["certs_test.go"],
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/phases/certs",
library = ":go_default_library",
embed = [":go_default_library"],
deps = [
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
"//cmd/kubeadm/app/constants:go_default_library",
@ -31,8 +30,6 @@ go_library(
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
"//cmd/kubeadm/app/constants:go_default_library",
"//cmd/kubeadm/app/phases/certs/pkiutil: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",
],
)

View File

@ -20,16 +20,13 @@ import (
"crypto/rsa"
"crypto/x509"
"fmt"
"net"
"os"
"path/filepath"
"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"
"k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/pkiutil"
"k8s.io/kubernetes/pkg/registry/core/service/ipallocator"
)
// CreatePKIAssets will create and write to disk all PKI assets necessary to establish the control plane.
@ -40,6 +37,9 @@ func CreatePKIAssets(cfg *kubeadmapi.MasterConfiguration) error {
CreateCACertAndKeyfiles,
CreateAPIServerCertAndKeyFiles,
CreateAPIServerKubeletClientCertAndKeyFiles,
CreateEtcdServerCertAndKeyFiles,
CreateEtcdPeerCertAndKeyFiles,
CreateAPIServerEtcdClientCertAndKeyFiles,
CreateServiceAccountKeyAndPublicKeyFiles,
CreateFrontProxyCACertAndKeyFiles,
CreateFrontProxyClientCertAndKeyFiles,
@ -79,7 +79,7 @@ func CreateCACertAndKeyfiles(cfg *kubeadmapi.MasterConfiguration) error {
// It assumes the cluster CA certificate and key files should exists into the CertificatesDir
func CreateAPIServerCertAndKeyFiles(cfg *kubeadmapi.MasterConfiguration) error {
caCert, caKey, err := loadCertificateAuthorithy(cfg.CertificatesDir, kubeadmconstants.CACertAndKeyBaseName)
caCert, caKey, err := loadCertificateAuthority(cfg.CertificatesDir, kubeadmconstants.CACertAndKeyBaseName)
if err != nil {
return err
}
@ -103,12 +103,12 @@ func CreateAPIServerCertAndKeyFiles(cfg *kubeadmapi.MasterConfiguration) error {
// It assumes the cluster CA certificate and key files should exists into the CertificatesDir
func CreateAPIServerKubeletClientCertAndKeyFiles(cfg *kubeadmapi.MasterConfiguration) error {
caCert, caKey, err := loadCertificateAuthorithy(cfg.CertificatesDir, kubeadmconstants.CACertAndKeyBaseName)
caCert, caKey, err := loadCertificateAuthority(cfg.CertificatesDir, kubeadmconstants.CACertAndKeyBaseName)
if err != nil {
return err
}
apiClientCert, apiClientKey, err := NewAPIServerKubeletClientCertAndKey(caCert, caKey)
apiKubeletClientCert, apiKubeletClientKey, err := NewAPIServerKubeletClientCertAndKey(caCert, caKey)
if err != nil {
return err
}
@ -117,8 +117,80 @@ func CreateAPIServerKubeletClientCertAndKeyFiles(cfg *kubeadmapi.MasterConfigura
cfg.CertificatesDir,
kubeadmconstants.APIServerKubeletClientCertAndKeyBaseName,
caCert,
apiClientCert,
apiClientKey,
apiKubeletClientCert,
apiKubeletClientKey,
)
}
// 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 cluster CA certificate and key file exist in the CertificatesDir
func CreateEtcdServerCertAndKeyFiles(cfg *kubeadmapi.MasterConfiguration) error {
caCert, caKey, err := loadCertificateAuthority(cfg.CertificatesDir, kubeadmconstants.CACertAndKeyBaseName)
if err != nil {
return err
}
etcdServerCert, etcdServerKey, err := NewEtcdServerCertAndKey(cfg, caCert, caKey)
if err != nil {
return err
}
return writeCertificateFilesIfNotExist(
cfg.CertificatesDir,
kubeadmconstants.EtcdServerCertAndKeyBaseName,
caCert,
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 cluster CA certificate and key file exist in the CertificatesDir
func CreateEtcdPeerCertAndKeyFiles(cfg *kubeadmapi.MasterConfiguration) error {
caCert, caKey, err := loadCertificateAuthority(cfg.CertificatesDir, kubeadmconstants.CACertAndKeyBaseName)
if err != nil {
return err
}
etcdPeerCert, etcdPeerKey, err := NewEtcdPeerCertAndKey(cfg, caCert, caKey)
if err != nil {
return err
}
return writeCertificateFilesIfNotExist(
cfg.CertificatesDir,
kubeadmconstants.EtcdPeerCertAndKeyBaseName,
caCert,
etcdPeerCert,
etcdPeerKey,
)
}
// 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 cluster CA certificate and key file exist in the CertificatesDir
func CreateAPIServerEtcdClientCertAndKeyFiles(cfg *kubeadmapi.MasterConfiguration) error {
caCert, caKey, err := loadCertificateAuthority(cfg.CertificatesDir, kubeadmconstants.CACertAndKeyBaseName)
if err != nil {
return err
}
apiEtcdClientCert, apiEtcdClientKey, err := NewAPIServerEtcdClientCertAndKey(caCert, caKey)
if err != nil {
return err
}
return writeCertificateFilesIfNotExist(
cfg.CertificatesDir,
kubeadmconstants.APIServerEtcdClientCertAndKeyBaseName,
caCert,
apiEtcdClientCert,
apiEtcdClientKey,
)
}
@ -140,7 +212,7 @@ 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 separte CA, so that front proxy identities cannot hit the API and normal client certs cannot be used
// 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 {
@ -163,7 +235,7 @@ func CreateFrontProxyCACertAndKeyFiles(cfg *kubeadmapi.MasterConfiguration) erro
// It assumes the front proxy CAA certificate and key files should exists into the CertificatesDir
func CreateFrontProxyClientCertAndKeyFiles(cfg *kubeadmapi.MasterConfiguration) error {
frontProxyCACert, frontProxyCAKey, err := loadCertificateAuthorithy(cfg.CertificatesDir, kubeadmconstants.FrontProxyCACertAndKeyBaseName)
frontProxyCACert, frontProxyCAKey, err := loadCertificateAuthority(cfg.CertificatesDir, kubeadmconstants.FrontProxyCACertAndKeyBaseName)
if err != nil {
return err
}
@ -196,7 +268,7 @@ func NewCACertAndKey() (*x509.Certificate, *rsa.PrivateKey, error) {
// NewAPIServerCertAndKey generate CA 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 := getAltNames(cfg)
altNames, err := pkiutil.GetAPIServerAltNames(cfg)
if err != nil {
return nil, nil, fmt.Errorf("failure while composing altnames for API server: %v", err)
}
@ -230,6 +302,64 @@ func NewAPIServerKubeletClientCertAndKey(caCert *x509.Certificate, caKey *rsa.Pr
return apiClientCert, apiClientKey, nil
}
// NewEtcdServerCertAndKey generate CA 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: kubeadmconstants.EtcdServerCertCommonName,
AltNames: *altNames,
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
}
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 CA 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: kubeadmconstants.EtcdPeerCertCommonName,
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
}
// NewAPIServerEtcdClientCertAndKey generate CA 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) {
@ -268,28 +398,28 @@ func NewFrontProxyClientCertAndKey(frontProxyCACert *x509.Certificate, frontProx
return frontProxyClientCert, frontProxyClientKey, nil
}
// loadCertificateAuthorithy loads certificate authorithy
func loadCertificateAuthorithy(pkiDir string, baseName string) (*x509.Certificate, *rsa.PrivateKey, error) {
// Checks if certificate authorithy exists in the PKI directory
// loadCertificateAuthority loads certificate authority
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 authorithy from %s", baseName, pkiDir)
return nil, nil, fmt.Errorf("couldn't load %s certificate authority from %s", baseName, pkiDir)
}
// Try to load certificate authorithy .crt and .key from the PKI directory
// 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 authorithy: %v", baseName, err)
return nil, nil, fmt.Errorf("failure loading %s certificate authority: %v", baseName, err)
}
// Make sure the loaded CA cert actually is a CA
if !caCert.IsCA {
return nil, nil, fmt.Errorf("%s certificate is not a certificate authorithy", baseName)
return nil, nil, fmt.Errorf("%s certificate is not a certificate authority", baseName)
}
return caCert, caKey, nil
}
// writeCertificateAuthorithyFilesIfNotExist write a new certificate Authorithy to the given path.
// 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,
// otherwise this function returns an error.
@ -309,7 +439,7 @@ func writeCertificateAuthorithyFilesIfNotExist(pkiDir string, baseName string, c
return fmt.Errorf("certificate %s is not a CA", baseName)
}
// kubeadm doesn't validate the existing certificate Authorithy more than this;
// kubeadm doesn't validate the existing certificate Authority more than this;
// Basically, if we find a certificate file with the same path; and it is a CA
// 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)
@ -346,7 +476,7 @@ func writeCertificateFilesIfNotExist(pkiDir string, baseName string, signingCert
// 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 authorithy, kubeadm thinks those files are equal and
// the expected certificate authority, kubeadm thinks those files are equal and
// doesn't bother writing a new file
fmt.Printf("[certificates] Using the existing %s certificate and key.\n", baseName)
} else {
@ -478,7 +608,7 @@ 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 authorithy for %s: %v", l.uxName, err)
return fmt.Errorf("failure loading certificate authority for %s: %v", l.uxName, err)
}
// Try to load key and signed certificate
@ -503,50 +633,3 @@ func validatePrivatePublicKey(l certKeyLocation) error {
}
return nil
}
// getAltNames builds an AltNames object for to be used when generating apiserver certificate
func getAltNames(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.NodeName,
"kubernetes",
"kubernetes.default",
"kubernetes.default.svc",
fmt.Sprintf("kubernetes.default.svc.%s", cfg.Networking.DNSDomain),
},
IPs: []net.IP{
internalAPIServerVirtualIP,
advertiseAddress,
},
}
// adds additional SAN
for _, altname := range cfg.APIServerCertSANs {
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)
}
}
return altNames, nil
}

View File

@ -258,51 +258,6 @@ func TestWriteKeyFilesIfNotExist(t *testing.T) {
}
}
func TestGetAltNames(t *testing.T) {
hostname := "valid-hostname"
advertiseIP := "1.2.3.4"
cfg := &kubeadmapi.MasterConfiguration{
API: kubeadmapi.API{AdvertiseAddress: advertiseIP},
Networking: kubeadmapi.Networking{ServiceSubnet: "10.96.0.0/12", DNSDomain: "cluster.local"},
NodeName: hostname,
}
altNames, err := getAltNames(cfg)
if err != nil {
t.Fatalf("failed calling getAltNames: %v", err)
}
expectedDNSNames := []string{hostname, "kubernetes", "kubernetes.default", "kubernetes.default.svc", "kubernetes.default.svc.cluster.local"}
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{"10.96.0.1", advertiseIP}
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 TestNewCACertAndKey(t *testing.T) {
caCert, _, err := NewCACertAndKey()
if err != nil {
@ -320,7 +275,7 @@ func TestNewAPIServerCertAndKey(t *testing.T) {
cfg := &kubeadmapi.MasterConfiguration{
API: kubeadmapi.API{AdvertiseAddress: addr},
Networking: kubeadmapi.Networking{ServiceSubnet: "10.96.0.0/12", DNSDomain: "cluster.local"},
NodeName: "valid-hostname",
NodeName: hostname,
}
caCert, caKey, err := NewCACertAndKey()
if err != nil {
@ -345,14 +300,93 @@ func TestNewAPIServerKubeletClientCertAndKey(t *testing.T) {
t.Fatalf("failed creation of ca cert and key: %v", err)
}
apiClientCert, _, err := NewAPIServerKubeletClientCertAndKey(caCert, caKey)
apiKubeletClientCert, _, err := NewAPIServerKubeletClientCertAndKey(caCert, caKey)
if err != nil {
t.Fatalf("failed creation of cert and key: %v", err)
}
certstestutil.AssertCertificateIsSignedByCa(t, apiClientCert, caCert)
certstestutil.AssertCertificateHasClientAuthUsage(t, apiClientCert)
certstestutil.AssertCertificateHasOrganizations(t, apiClientCert, kubeadmconstants.MastersGroup)
certstestutil.AssertCertificateIsSignedByCa(t, apiKubeletClientCert, caCert)
certstestutil.AssertCertificateHasClientAuthUsage(t, apiKubeletClientCert)
certstestutil.AssertCertificateHasOrganizations(t, apiKubeletClientCert, kubeadmconstants.MastersGroup)
}
func TestNewEtcdServerCertAndKey(t *testing.T) {
proxy := "user-etcd-proxy"
proxyIP := "10.10.10.100"
cfg := &kubeadmapi.MasterConfiguration{
Etcd: kubeadmapi.Etcd{
ServerCertSANs: []string{
proxy,
proxyIP,
},
},
}
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},
NodeName: hostname,
Etcd: kubeadmapi.Etcd{
PeerCertSANs: []string{
proxy,
proxyIP,
},
},
}
caCert, caKey, err := NewCACertAndKey()
if err != nil {
t.Fatalf("failed creation of ca cert and key: %v", err)
}
etcdPeerCert, _, err := NewEtcdPeerCertAndKey(cfg, caCert, caKey)
if err != nil {
t.Fatalf("failed creation of cert and key: %v", err)
}
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))
}
}
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) {
@ -549,6 +583,9 @@ func TestCreateCertificateFilesMethods(t *testing.T) {
kubeadmconstants.CACertName, kubeadmconstants.CAKeyName,
kubeadmconstants.APIServerCertName, kubeadmconstants.APIServerKeyName,
kubeadmconstants.APIServerKubeletClientCertName, kubeadmconstants.APIServerKubeletClientKeyName,
kubeadmconstants.EtcdServerCertName, kubeadmconstants.EtcdServerKeyName,
kubeadmconstants.EtcdPeerCertName, kubeadmconstants.EtcdPeerKeyName,
kubeadmconstants.APIServerEtcdClientCertName, kubeadmconstants.APIServerEtcdClientKeyName,
kubeadmconstants.ServiceAccountPrivateKeyName, kubeadmconstants.ServiceAccountPublicKeyName,
kubeadmconstants.FrontProxyCACertName, kubeadmconstants.FrontProxyCAKeyName,
kubeadmconstants.FrontProxyClientCertName, kubeadmconstants.FrontProxyClientKeyName,
@ -568,6 +605,21 @@ func TestCreateCertificateFilesMethods(t *testing.T) {
createFunc: CreateAPIServerKubeletClientCertAndKeyFiles,
expectedFiles: []string{kubeadmconstants.APIServerKubeletClientCertName, kubeadmconstants.APIServerKubeletClientKeyName},
},
{
setupFunc: CreateCACertAndKeyfiles,
createFunc: CreateEtcdServerCertAndKeyFiles,
expectedFiles: []string{kubeadmconstants.EtcdServerCertName, kubeadmconstants.EtcdServerKeyName},
},
{
setupFunc: CreateCACertAndKeyfiles,
createFunc: CreateEtcdPeerCertAndKeyFiles,
expectedFiles: []string{kubeadmconstants.EtcdPeerCertName, kubeadmconstants.EtcdPeerKeyName},
},
{
setupFunc: CreateCACertAndKeyfiles,
createFunc: CreateAPIServerEtcdClientCertAndKeyFiles,
expectedFiles: []string{kubeadmconstants.APIServerEtcdClientCertName, kubeadmconstants.APIServerEtcdClientKeyName},
},
{
createFunc: CreateServiceAccountKeyAndPublicKeyFiles,
expectedFiles: []string{kubeadmconstants.ServiceAccountPrivateKeyName, kubeadmconstants.ServiceAccountPublicKeyName},

View File

@ -23,7 +23,9 @@ package certs
INPUTS:
From MasterConfiguration
.API.AdvertiseAddress is an optional parameter that can be passed for an extra addition to the SAN IPs
.APIServerCertSANs is needed for knowing which DNS names and IPs the API Server serving cert should be valid for
.APIServerCertSANs is an optional parameter for adding DNS names and IPs to the API Server serving cert SAN
.Etcd.ServerCertSANs is an optional parameter for adding DNS names and IPs to the etcd serving cert SAN
.Etcd.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
.CertificatesDir is required for knowing where all certificates should be stored
@ -36,6 +38,12 @@ package certs
- apiserver.key
- apiserver-kubelet-client.crt
- apiserver-kubelet-client.key
- apiserver-etcd-client.crt
- apiserver-etcd-client.key
- etcd/server.crt
- etcd/server.key
- etcd/peer.crt
- etcd/peer.key
- sa.pub
- sa.key
- front-proxy-ca.crt

View File

@ -9,16 +9,24 @@ load(
go_test(
name = "go_default_test",
srcs = ["pki_helpers_test.go"],
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/pkiutil",
library = ":go_default_library",
deps = ["//vendor/k8s.io/client-go/util/cert:go_default_library"],
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 = ["//vendor/k8s.io/client-go/util/cert:go_default_library"],
deps = [
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
"//cmd/kubeadm/app/constants: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(

View File

@ -20,11 +20,16 @@ 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"
"k8s.io/kubernetes/pkg/registry/core/service/ipallocator"
)
// NewCertificateAuthority creates new certificate and private key for the certificate authority
@ -125,7 +130,7 @@ func WritePublicKey(pkiPath, name string, key *rsa.PublicKey) error {
return nil
}
// CertOrKeyExist retuns a boolean whether the cert or the key exists
// CertOrKeyExist returns a boolean whether the cert or the key exists
func CertOrKeyExist(pkiPath, name string) bool {
certificatePath, privateKeyPath := pathsForCertAndKey(pkiPath, name)
@ -246,3 +251,106 @@ func pathForKey(pkiPath, name string) string {
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.NodeName,
"kubernetes",
"kubernetes.default",
"kubernetes.default.svc",
fmt.Sprintf("kubernetes.default.svc.%s", cfg.Networking.DNSDomain),
},
IPs: []net.IP{
internalAPIServerVirtualIP,
advertiseAddress,
},
}
// add api server dns advertise address
if len(cfg.API.ControlPlaneEndpoint) > 0 {
altNames.DNSNames = append(altNames.DNSNames, cfg.API.ControlPlaneEndpoint)
}
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{"localhost"},
IPs: []net.IP{net.IPv4(127, 0, 0, 1)},
}
appendSANsToAltNames(altNames, cfg.Etcd.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.NodeName},
IPs: []net.IP{advertiseAddress},
}
appendSANsToAltNames(altNames, cfg.Etcd.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,
)
}
}
}

View File

@ -21,10 +21,12 @@ import (
"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) {
@ -432,3 +434,154 @@ func TestPathForPublicKey(t *testing.T) {
t.Errorf("unexpected certificate path: %s", pubPath)
}
}
func TestGetAPIServerAltNames(t *testing.T) {
hostname := "valid-hostname"
advertiseIP := "1.2.3.4"
controlPlaneEndpoint := "api.k8s.io"
cfg := &kubeadmapi.MasterConfiguration{
API: kubeadmapi.API{AdvertiseAddress: advertiseIP, ControlPlaneEndpoint: controlPlaneEndpoint},
Networking: kubeadmapi.Networking{ServiceSubnet: "10.96.0.0/12", DNSDomain: "cluster.local"},
NodeName: hostname,
APIServerCertSANs: []string{"10.1.245.94", "10.1.245.95", "1.2.3.L", "invalid,commas,in,DNS"},
}
altNames, err := GetAPIServerAltNames(cfg)
if err != nil {
t.Fatalf("failed calling GetAPIServerAltNames: %v", err)
}
expectedDNSNames := []string{hostname, "kubernetes", "kubernetes.default", "kubernetes.default.svc", "kubernetes.default.svc.cluster.local", controlPlaneEndpoint}
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{"10.96.0.1", advertiseIP, "10.1.245.94", "10.1.245.95"}
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 TestGetEtcdAltNames(t *testing.T) {
proxy := "user-etcd-proxy"
proxyIP := "10.10.10.100"
cfg := &kubeadmapi.MasterConfiguration{
Etcd: kubeadmapi.Etcd{
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", 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},
NodeName: hostname,
Etcd: kubeadmapi.Etcd{
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)
}
}
}

View File

@ -12,8 +12,7 @@ go_test(
"manifests_test.go",
"volumes_test.go",
],
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/phases/controlplane",
library = ":go_default_library",
embed = [":go_default_library"],
deps = [
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
"//cmd/kubeadm/app/constants:go_default_library",
@ -21,6 +20,7 @@ go_test(
"//cmd/kubeadm/app/phases/certs:go_default_library",
"//cmd/kubeadm/test:go_default_library",
"//pkg/master/reconcilers:go_default_library",
"//pkg/util/pointer:go_default_library",
"//pkg/util/version:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
],
@ -44,6 +44,7 @@ go_library(
"//cmd/kubeadm/app/util/staticpod:go_default_library",
"//pkg/kubeapiserver/authorizer/modes:go_default_library",
"//pkg/master/reconcilers: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",

View File

@ -21,6 +21,7 @@ import (
"net"
"os"
"path/filepath"
"strconv"
"strings"
"k8s.io/api/core/v1"
@ -35,6 +36,7 @@ import (
staticpodutil "k8s.io/kubernetes/cmd/kubeadm/app/util/staticpod"
authzmodes "k8s.io/kubernetes/pkg/kubeapiserver/authorizer/modes"
"k8s.io/kubernetes/pkg/master/reconcilers"
utilpointer "k8s.io/kubernetes/pkg/util/pointer"
"k8s.io/kubernetes/pkg/util/version"
)
@ -42,9 +44,8 @@ import (
const (
DefaultCloudConfigPath = "/etc/kubernetes/cloud-config"
defaultV18AdmissionControl = "Initializers,NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeLabel,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,ResourceQuota"
deprecatedV19AdmissionControl = "Initializers,NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeLabel,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,ResourceQuota"
defaultV19AdmissionControl = "Initializers,NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,ResourceQuota"
deprecatedV19AdmissionControl = "NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeLabel,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota"
defaultV19AdmissionControl = "NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota"
)
// CreateInitStaticPodManifestFiles will write all static pod manifest files needed to bring up the control plane.
@ -68,7 +69,7 @@ func CreateSchedulerStaticPodManifestFile(manifestDir string, cfg *kubeadmapi.Ma
}
// GetStaticPodSpecs returns all staticPodSpecs actualized to the context of the current MasterConfiguration
// NB. this methods holds the information about how kubeadm creates static pod mainfests.
// 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 {
// Get the required hostpath mounts
mounts := getHostPathVolumesForTheControlPlane(cfg)
@ -76,34 +77,49 @@ func GetStaticPodSpecs(cfg *kubeadmapi.MasterConfiguration, k8sVersion *version.
// Prepare static pod specs
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),
Command: getAPIServerCommand(cfg, k8sVersion),
VolumeMounts: staticpodutil.VolumeMountMapToSlice(mounts.GetVolumeMounts(kubeadmconstants.KubeAPIServer)),
LivenessProbe: staticpodutil.ComponentProbe(cfg, kubeadmconstants.KubeAPIServer, int(cfg.API.BindPort), "/healthz", v1.URISchemeHTTPS),
Resources: staticpodutil.ComponentResources("250m"),
Env: getProxyEnvVars(),
Name: kubeadmconstants.KubeAPIServer,
Image: images.GetCoreImage(kubeadmconstants.KubeAPIServer, cfg.GetControlPlaneImageRepository(), cfg.KubernetesVersion, cfg.UnifiedControlPlaneImage),
ImagePullPolicy: cfg.ImagePullPolicy,
Command: getAPIServerCommand(cfg, k8sVersion),
VolumeMounts: staticpodutil.VolumeMountMapToSlice(mounts.GetVolumeMounts(kubeadmconstants.KubeAPIServer)),
LivenessProbe: staticpodutil.ComponentProbe(cfg, kubeadmconstants.KubeAPIServer, int(cfg.API.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),
Command: getControllerManagerCommand(cfg, k8sVersion),
VolumeMounts: staticpodutil.VolumeMountMapToSlice(mounts.GetVolumeMounts(kubeadmconstants.KubeControllerManager)),
LivenessProbe: staticpodutil.ComponentProbe(cfg, kubeadmconstants.KubeControllerManager, 10252, "/healthz", v1.URISchemeHTTP),
Resources: staticpodutil.ComponentResources("200m"),
Env: getProxyEnvVars(),
Name: kubeadmconstants.KubeControllerManager,
Image: images.GetCoreImage(kubeadmconstants.KubeControllerManager, cfg.GetControlPlaneImageRepository(), cfg.KubernetesVersion, cfg.UnifiedControlPlaneImage),
ImagePullPolicy: cfg.ImagePullPolicy,
Command: getControllerManagerCommand(cfg, k8sVersion),
VolumeMounts: staticpodutil.VolumeMountMapToSlice(mounts.GetVolumeMounts(kubeadmconstants.KubeControllerManager)),
LivenessProbe: staticpodutil.ComponentProbe(cfg, kubeadmconstants.KubeControllerManager, 10252, "/healthz", v1.URISchemeHTTP),
Resources: staticpodutil.ComponentResources("200m"),
Env: getProxyEnvVars(),
}, mounts.GetVolumes(kubeadmconstants.KubeControllerManager)),
kubeadmconstants.KubeScheduler: staticpodutil.ComponentPod(v1.Container{
Name: kubeadmconstants.KubeScheduler,
Image: images.GetCoreImage(kubeadmconstants.KubeScheduler, cfg.GetControlPlaneImageRepository(), cfg.KubernetesVersion, cfg.UnifiedControlPlaneImage),
Command: getSchedulerCommand(cfg),
VolumeMounts: staticpodutil.VolumeMountMapToSlice(mounts.GetVolumeMounts(kubeadmconstants.KubeScheduler)),
LivenessProbe: staticpodutil.ComponentProbe(cfg, kubeadmconstants.KubeScheduler, 10251, "/healthz", v1.URISchemeHTTP),
Resources: staticpodutil.ComponentResources("100m"),
Env: getProxyEnvVars(),
Name: kubeadmconstants.KubeScheduler,
Image: images.GetCoreImage(kubeadmconstants.KubeScheduler, cfg.GetControlPlaneImageRepository(), cfg.KubernetesVersion, cfg.UnifiedControlPlaneImage),
ImagePullPolicy: cfg.ImagePullPolicy,
Command: getSchedulerCommand(cfg),
VolumeMounts: staticpodutil.VolumeMountMapToSlice(mounts.GetVolumeMounts(kubeadmconstants.KubeScheduler)),
LivenessProbe: staticpodutil.ComponentProbe(cfg, kubeadmconstants.KubeScheduler, 10251, "/healthz", v1.URISchemeHTTP),
Resources: staticpodutil.ComponentResources("100m"),
Env: getProxyEnvVars(),
}, mounts.GetVolumes(kubeadmconstants.KubeScheduler)),
}
// Some cloud providers need extra privileges for example to load node information from a config drive
// TODO: when we fully to external cloud providers and the api server and controller manager do not need
// to call out to cloud provider code, we can remove the support for the PrivilegedPods
if cfg.PrivilegedPods {
staticPodSpecs[kubeadmconstants.KubeAPIServer].Spec.Containers[0].SecurityContext = &v1.SecurityContext{
Privileged: utilpointer.BoolPtr(true),
}
staticPodSpecs[kubeadmconstants.KubeControllerManager].Spec.Containers[0].SecurityContext = &v1.SecurityContext{
Privileged: utilpointer.BoolPtr(true),
}
}
return staticPodSpecs
}
@ -167,10 +183,6 @@ func getAPIServerCommand(cfg *kubeadmapi.MasterConfiguration, k8sVersion *versio
command := []string{"kube-apiserver"}
if k8sVersion.Minor() == 8 {
defaultArguments["admission-control"] = defaultV18AdmissionControl
}
if cfg.CloudProvider == "aws" || cfg.CloudProvider == "gce" {
defaultArguments["admission-control"] = deprecatedV19AdmissionControl
}
@ -178,21 +190,37 @@ func getAPIServerCommand(cfg *kubeadmapi.MasterConfiguration, k8sVersion *versio
command = append(command, kubeadmutil.BuildArgumentListFromMap(defaultArguments, cfg.APIServerExtraArgs)...)
command = append(command, getAuthzParameters(cfg.AuthorizationModes)...)
// Check if the user decided to use an external etcd cluster
// If the user set endpoints for an external etcd cluster
if len(cfg.Etcd.Endpoints) > 0 {
command = append(command, fmt.Sprintf("--etcd-servers=%s", strings.Join(cfg.Etcd.Endpoints, ",")))
} else {
command = append(command, "--etcd-servers=http://127.0.0.1:2379")
}
// Is etcd secured?
if cfg.Etcd.CAFile != "" {
command = append(command, fmt.Sprintf("--etcd-cafile=%s", cfg.Etcd.CAFile))
}
if cfg.Etcd.CertFile != "" && cfg.Etcd.KeyFile != "" {
etcdClientFileArg := fmt.Sprintf("--etcd-certfile=%s", cfg.Etcd.CertFile)
etcdKeyFileArg := fmt.Sprintf("--etcd-keyfile=%s", cfg.Etcd.KeyFile)
command = append(command, etcdClientFileArg, etcdKeyFileArg)
// Use any user supplied etcd certificates
if cfg.Etcd.CAFile != "" {
command = append(command, fmt.Sprintf("--etcd-cafile=%s", cfg.Etcd.CAFile))
}
if cfg.Etcd.CertFile != "" && cfg.Etcd.KeyFile != "" {
etcdClientFileArg := fmt.Sprintf("--etcd-certfile=%s", cfg.Etcd.CertFile)
etcdKeyFileArg := fmt.Sprintf("--etcd-keyfile=%s", cfg.Etcd.KeyFile)
command = append(command, etcdClientFileArg, etcdKeyFileArg)
}
} else {
// Default to etcd static pod on localhost
etcdEndpointsArg := "--etcd-servers=https://127.0.0.1:2379"
etcdCAFileArg := fmt.Sprintf("--etcd-cafile=%s", filepath.Join(cfg.CertificatesDir, kubeadmconstants.CACertName))
etcdClientFileArg := fmt.Sprintf("--etcd-certfile=%s", filepath.Join(cfg.CertificatesDir, kubeadmconstants.APIServerEtcdClientCertName))
etcdKeyFileArg := fmt.Sprintf("--etcd-keyfile=%s", filepath.Join(cfg.CertificatesDir, kubeadmconstants.APIServerEtcdClientKeyName))
command = append(command, etcdEndpointsArg, etcdCAFileArg, etcdClientFileArg, etcdKeyFileArg)
// Warn for unused user supplied variables
if cfg.Etcd.CAFile != "" {
fmt.Printf("[controlplane] WARNING: Configuration for %s CAFile, %s, is unused without providing Endpoints for external %s\n", kubeadmconstants.Etcd, cfg.Etcd.CAFile, kubeadmconstants.Etcd)
}
if cfg.Etcd.CertFile != "" {
fmt.Printf("[controlplane] WARNING: Configuration for %s CertFile, %s, is unused without providing Endpoints for external %s\n", kubeadmconstants.Etcd, cfg.Etcd.CertFile, kubeadmconstants.Etcd)
}
if cfg.Etcd.KeyFile != "" {
fmt.Printf("[controlplane] WARNING: Configuration for %s KeyFile, %s, is unused without providing Endpoints for external %s\n", kubeadmconstants.Etcd, cfg.Etcd.KeyFile, kubeadmconstants.Etcd)
}
}
if cfg.CloudProvider != "" {
@ -212,9 +240,66 @@ func getAPIServerCommand(cfg *kubeadmapi.MasterConfiguration, k8sVersion *versio
command = append(command, "--feature-gates=DynamicKubeletConfig=true")
}
if features.Enabled(cfg.FeatureGates, features.Auditing) {
command = append(command, "--audit-policy-file="+kubeadmconstants.GetStaticPodAuditPolicyFile())
command = append(command, "--audit-log-path="+filepath.Join(kubeadmconstants.StaticPodAuditPolicyLogDir, kubeadmconstants.AuditPolicyLogFile))
if cfg.AuditPolicyConfiguration.LogMaxAge == nil {
command = append(command, fmt.Sprintf("--audit-log-maxage=%d", kubeadmapiext.DefaultAuditPolicyLogMaxAge))
} else {
command = append(command, fmt.Sprintf("--audit-log-maxage=%d", *cfg.AuditPolicyConfiguration.LogMaxAge))
}
}
return command
}
// calcNodeCidrSize determines the size of the subnets used on each node, based
// on the pod subnet provided. For IPv4, we assume that the pod subnet will
// be /16 and use /24. If the pod subnet cannot be parsed, the IPv4 value will
// be used (/24).
//
// For IPv6, the algorithm will do two three. First, the node CIDR will be set
// to a multiple of 8, using the available bits for easier readability by user.
// Second, the number of nodes will be 512 to 64K to attempt to maximize the
// number of nodes (see NOTE below). Third, pod networks of /113 and larger will
// be rejected, as the amount of bits available is too small.
//
// A special case is when the pod network size is /112, where /120 will be used,
// only allowing 256 nodes and 256 pods.
//
// If the pod network size is /113 or larger, the node CIDR will be set to the same
// size and this will be rejected later in validation.
//
// NOTE: Currently, the pod network must be /66 or larger. It is not reflected here,
// but a smaller value will fail later validation.
//
// NOTE: Currently, the design allows a maximum of 64K nodes. This algorithm splits
// the available bits to maximize the number used for nodes, but still have the node
// CIDR be a multiple of eight.
//
func calcNodeCidrSize(podSubnet string) string {
maskSize := "24"
if ip, podCidr, err := net.ParseCIDR(podSubnet); err == nil {
if ip.To4() == nil {
var nodeCidrSize int
podNetSize, totalBits := podCidr.Mask.Size()
switch {
case podNetSize == 112:
// Special case, allows 256 nodes, 256 pods/node
nodeCidrSize = 120
case podNetSize < 112:
// Use multiple of 8 for node CIDR, with 512 to 64K nodes
nodeCidrSize = totalBits - ((totalBits-podNetSize-1)/8-1)*8
default:
// Not enough bits, will fail later, when validate
nodeCidrSize = podNetSize
}
maskSize = strconv.Itoa(nodeCidrSize)
}
}
return maskSize
}
// getControllerManagerCommand builds the right controller manager command from the given config object and version
func getControllerManagerCommand(cfg *kubeadmapi.MasterConfiguration, k8sVersion *version.Version) []string {
defaultArguments := map[string]string{
@ -251,12 +336,7 @@ func getControllerManagerCommand(cfg *kubeadmapi.MasterConfiguration, k8sVersion
// Let the controller-manager allocate Node CIDRs for the Pod network.
// Each node will get a subspace of the address CIDR provided with --pod-network-cidr.
if cfg.Networking.PodSubnet != "" {
maskSize := "24"
if ip, _, err := net.ParseCIDR(cfg.Networking.PodSubnet); err == nil {
if ip.To4() == nil {
maskSize = "64"
}
}
maskSize := calcNodeCidrSize(cfg.Networking.PodSubnet)
command = append(command, "--allocate-node-cidrs=true", "--cluster-cidr="+cfg.Networking.PodSubnet,
"--node-cidr-mask-size="+maskSize)
}

View File

@ -32,6 +32,7 @@ import (
"k8s.io/kubernetes/pkg/util/version"
testutil "k8s.io/kubernetes/cmd/kubeadm/test"
utilpointer "k8s.io/kubernetes/pkg/util/pointer"
)
const (
@ -43,7 +44,7 @@ func TestGetStaticPodSpecs(t *testing.T) {
// Creates a Master Configuration
cfg := &kubeadmapi.MasterConfiguration{
KubernetesVersion: "v1.8.0",
KubernetesVersion: "v1.9.0",
}
// Executes GetStaticPodSpecs
@ -74,7 +75,7 @@ func TestGetStaticPodSpecs(t *testing.T) {
// Assert each specs refers to the right pod
if spec.Spec.Containers[0].Name != assertion.staticPodName {
t.Errorf("getKubeConfigSpecs spec for %s contains pod %s, expectes %s", assertion.staticPodName, spec.Spec.Containers[0].Name, assertion.staticPodName)
t.Errorf("getKubeConfigSpecs spec for %s contains pod %s, expects %s", assertion.staticPodName, spec.Spec.Containers[0].Name, assertion.staticPodName)
}
} else {
@ -115,7 +116,7 @@ func TestCreateStaticPodFilesAndWrappers(t *testing.T) {
// Creates a Master Configuration
cfg := &kubeadmapi.MasterConfiguration{
KubernetesVersion: "v1.8.0",
KubernetesVersion: "v1.9.0",
}
// Execute createStaticPodFunction
@ -135,6 +136,58 @@ func TestCreateStaticPodFilesAndWrappers(t *testing.T) {
}
}
func TestCreatePrivilegedContainerForOpenStack(t *testing.T) {
// Creates a Master Configuration with OpenStack cloud provider
var staticPodNames = []string{
kubeadmconstants.KubeAPIServer,
kubeadmconstants.KubeControllerManager,
}
var assertions = []struct {
cloudProvider string
privilegedPods bool
expectedPrivilege bool
}{
{
cloudProvider: "",
expectedPrivilege: false,
},
{
cloudProvider: "aws",
expectedPrivilege: false,
},
{
cloudProvider: "openstack",
privilegedPods: true,
expectedPrivilege: true,
},
}
for _, assertion := range assertions {
cfg := &kubeadmapi.MasterConfiguration{
KubernetesVersion: "v1.9.0",
CloudProvider: assertion.cloudProvider,
PrivilegedPods: assertion.privilegedPods,
}
k8sVersion, _ := version.ParseSemantic(cfg.KubernetesVersion)
specs := GetStaticPodSpecs(cfg, k8sVersion)
for _, podname := range staticPodNames {
spec, _ := specs[podname]
sc := spec.Spec.Containers[0].SecurityContext
if assertion.expectedPrivilege == true {
if sc == nil || sc.Privileged == nil || *sc.Privileged == false {
t.Errorf("GetStaticPodSpecs did not enable privileged containers in %s pod for provider %s", podname, assertion.cloudProvider)
}
} else {
if sc != nil && sc.Privileged != nil && *sc.Privileged == true {
t.Errorf("GetStaticPodSpecs enabled privileged containers in %s pod for provider %s", podname, assertion.cloudProvider)
}
}
}
}
}
func TestGetAPIServerCommand(t *testing.T) {
var tests = []struct {
cfg *kubeadmapi.MasterConfiguration
@ -145,12 +198,12 @@ func TestGetAPIServerCommand(t *testing.T) {
API: kubeadmapi.API{BindPort: 123, AdvertiseAddress: "1.2.3.4"},
Networking: kubeadmapi.Networking{ServiceSubnet: "bar"},
CertificatesDir: testCertsDir,
KubernetesVersion: "v1.8.0",
KubernetesVersion: "v1.9.0",
},
expected: []string{
"kube-apiserver",
"--insecure-port=0",
"--admission-control=Initializers,NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeLabel,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,ResourceQuota",
"--admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota",
"--service-cluster-ip-range=bar",
"--service-account-key-file=" + testCertsDir + "/sa.pub",
"--client-ca-file=" + testCertsDir + "/ca.crt",
@ -171,7 +224,10 @@ func TestGetAPIServerCommand(t *testing.T) {
"--requestheader-allowed-names=front-proxy-client",
"--authorization-mode=Node,RBAC",
"--advertise-address=1.2.3.4",
"--etcd-servers=http://127.0.0.1:2379",
"--etcd-servers=https://127.0.0.1:2379",
"--etcd-cafile=" + testCertsDir + "/ca.crt",
"--etcd-certfile=" + testCertsDir + "/apiserver-etcd-client.crt",
"--etcd-keyfile=" + testCertsDir + "/apiserver-etcd-client.key",
},
},
{
@ -179,12 +235,12 @@ func TestGetAPIServerCommand(t *testing.T) {
API: kubeadmapi.API{BindPort: 123, AdvertiseAddress: "1.2.3.4"},
Networking: kubeadmapi.Networking{ServiceSubnet: "bar"},
CertificatesDir: testCertsDir,
KubernetesVersion: "v1.8.0-beta.0",
KubernetesVersion: "v1.9.0-beta.0",
},
expected: []string{
"kube-apiserver",
"--insecure-port=0",
"--admission-control=Initializers,NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeLabel,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,ResourceQuota",
"--admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota",
"--service-cluster-ip-range=bar",
"--service-account-key-file=" + testCertsDir + "/sa.pub",
"--client-ca-file=" + testCertsDir + "/ca.crt",
@ -205,7 +261,10 @@ func TestGetAPIServerCommand(t *testing.T) {
"--requestheader-allowed-names=front-proxy-client",
"--authorization-mode=Node,RBAC",
"--advertise-address=1.2.3.4",
"--etcd-servers=http://127.0.0.1:2379",
"--etcd-servers=https://127.0.0.1:2379",
"--etcd-cafile=" + testCertsDir + "/ca.crt",
"--etcd-certfile=" + testCertsDir + "/apiserver-etcd-client.crt",
"--etcd-keyfile=" + testCertsDir + "/apiserver-etcd-client.key",
},
},
{
@ -213,12 +272,12 @@ func TestGetAPIServerCommand(t *testing.T) {
API: kubeadmapi.API{BindPort: 123, AdvertiseAddress: "4.3.2.1"},
Networking: kubeadmapi.Networking{ServiceSubnet: "bar"},
CertificatesDir: testCertsDir,
KubernetesVersion: "v1.8.1",
KubernetesVersion: "v1.9.1",
},
expected: []string{
"kube-apiserver",
"--insecure-port=0",
"--admission-control=Initializers,NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeLabel,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,ResourceQuota",
"--admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota",
"--service-cluster-ip-range=bar",
"--service-account-key-file=" + testCertsDir + "/sa.pub",
"--client-ca-file=" + testCertsDir + "/ca.crt",
@ -239,7 +298,10 @@ func TestGetAPIServerCommand(t *testing.T) {
"--requestheader-allowed-names=front-proxy-client",
"--authorization-mode=Node,RBAC",
"--advertise-address=4.3.2.1",
"--etcd-servers=http://127.0.0.1:2379",
"--etcd-servers=https://127.0.0.1:2379",
"--etcd-cafile=" + testCertsDir + "/ca.crt",
"--etcd-certfile=" + testCertsDir + "/apiserver-etcd-client.crt",
"--etcd-keyfile=" + testCertsDir + "/apiserver-etcd-client.key",
},
},
{
@ -248,12 +310,12 @@ func TestGetAPIServerCommand(t *testing.T) {
Networking: kubeadmapi.Networking{ServiceSubnet: "bar"},
Etcd: kubeadmapi.Etcd{CertFile: "fiz", KeyFile: "faz"},
CertificatesDir: testCertsDir,
KubernetesVersion: "v1.8.0",
KubernetesVersion: "v1.9.0",
},
expected: []string{
"kube-apiserver",
"--insecure-port=0",
"--admission-control=Initializers,NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeLabel,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,ResourceQuota",
"--admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota",
"--service-cluster-ip-range=bar",
"--service-account-key-file=" + testCertsDir + "/sa.pub",
"--client-ca-file=" + testCertsDir + "/ca.crt",
@ -274,9 +336,10 @@ func TestGetAPIServerCommand(t *testing.T) {
"--requestheader-allowed-names=front-proxy-client",
"--authorization-mode=Node,RBAC",
"--advertise-address=4.3.2.1",
"--etcd-servers=http://127.0.0.1:2379",
"--etcd-certfile=fiz",
"--etcd-keyfile=faz",
"--etcd-servers=https://127.0.0.1:2379",
"--etcd-cafile=" + testCertsDir + "/ca.crt",
"--etcd-certfile=" + testCertsDir + "/apiserver-etcd-client.crt",
"--etcd-keyfile=" + testCertsDir + "/apiserver-etcd-client.key",
},
},
{
@ -285,12 +348,17 @@ func TestGetAPIServerCommand(t *testing.T) {
Networking: kubeadmapi.Networking{ServiceSubnet: "bar"},
Etcd: kubeadmapi.Etcd{CertFile: "fiz", KeyFile: "faz"},
CertificatesDir: testCertsDir,
KubernetesVersion: "v1.8.3",
KubernetesVersion: "v1.9.3",
AuditPolicyConfiguration: kubeadmapi.AuditPolicyConfiguration{
Path: "/foo/bar",
LogDir: "/foo/baz",
LogMaxAge: utilpointer.Int32Ptr(10),
}, // ignored without the feature gate
},
expected: []string{
"kube-apiserver",
"--insecure-port=0",
"--admission-control=Initializers,NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeLabel,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,ResourceQuota",
"--admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota",
"--service-cluster-ip-range=bar",
"--service-account-key-file=" + testCertsDir + "/sa.pub",
"--client-ca-file=" + testCertsDir + "/ca.crt",
@ -311,9 +379,10 @@ func TestGetAPIServerCommand(t *testing.T) {
"--requestheader-allowed-names=front-proxy-client",
"--authorization-mode=Node,RBAC",
"--advertise-address=4.3.2.1",
"--etcd-servers=http://127.0.0.1:2379",
"--etcd-certfile=fiz",
"--etcd-keyfile=faz",
"--etcd-servers=https://127.0.0.1:2379",
"--etcd-cafile=" + testCertsDir + "/ca.crt",
"--etcd-certfile=" + testCertsDir + "/apiserver-etcd-client.crt",
"--etcd-keyfile=" + testCertsDir + "/apiserver-etcd-client.key",
},
},
{
@ -322,12 +391,12 @@ func TestGetAPIServerCommand(t *testing.T) {
Networking: kubeadmapi.Networking{ServiceSubnet: "bar"},
Etcd: kubeadmapi.Etcd{CertFile: "fiz", KeyFile: "faz"},
CertificatesDir: testCertsDir,
KubernetesVersion: "v1.8.0",
KubernetesVersion: "v1.9.0",
},
expected: []string{
"kube-apiserver",
"--insecure-port=0",
"--admission-control=Initializers,NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeLabel,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,ResourceQuota",
"--admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota",
"--service-cluster-ip-range=bar",
"--service-account-key-file=" + testCertsDir + "/sa.pub",
"--client-ca-file=" + testCertsDir + "/ca.crt",
@ -348,9 +417,10 @@ func TestGetAPIServerCommand(t *testing.T) {
"--requestheader-allowed-names=front-proxy-client",
"--authorization-mode=Node,RBAC",
"--advertise-address=2001:db8::1",
"--etcd-servers=http://127.0.0.1:2379",
"--etcd-certfile=fiz",
"--etcd-keyfile=faz",
"--etcd-servers=https://127.0.0.1:2379",
"--etcd-cafile=" + testCertsDir + "/ca.crt",
"--etcd-certfile=" + testCertsDir + "/apiserver-etcd-client.crt",
"--etcd-keyfile=" + testCertsDir + "/apiserver-etcd-client.key",
},
},
{
@ -364,7 +434,7 @@ func TestGetAPIServerCommand(t *testing.T) {
expected: []string{
"kube-apiserver",
"--insecure-port=0",
"--admission-control=Initializers,NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,ResourceQuota",
"--admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota",
"--service-cluster-ip-range=bar",
"--service-account-key-file=" + testCertsDir + "/sa.pub",
"--client-ca-file=" + testCertsDir + "/ca.crt",
@ -385,9 +455,10 @@ func TestGetAPIServerCommand(t *testing.T) {
"--requestheader-allowed-names=front-proxy-client",
"--authorization-mode=Node,RBAC",
"--advertise-address=2001:db8::1",
"--etcd-servers=http://127.0.0.1:2379",
"--etcd-certfile=fiz",
"--etcd-keyfile=faz",
"--etcd-servers=https://127.0.0.1:2379",
"--etcd-cafile=" + testCertsDir + "/ca.crt",
"--etcd-certfile=" + testCertsDir + "/apiserver-etcd-client.crt",
"--etcd-keyfile=" + testCertsDir + "/apiserver-etcd-client.key",
},
},
{
@ -395,13 +466,14 @@ func TestGetAPIServerCommand(t *testing.T) {
API: kubeadmapi.API{BindPort: 123, AdvertiseAddress: "2001:db8::1"},
Networking: kubeadmapi.Networking{ServiceSubnet: "bar"},
FeatureGates: map[string]bool{features.HighAvailability: true},
Etcd: kubeadmapi.Etcd{Endpoints: []string{"https://8.6.4.1:2379", "https://8.6.4.2:2379"}, CAFile: "fuz", CertFile: "fiz", KeyFile: "faz"},
CertificatesDir: testCertsDir,
KubernetesVersion: "v1.9.0-beta.0",
},
expected: []string{
"kube-apiserver",
"--insecure-port=0",
"--admission-control=Initializers,NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,ResourceQuota",
"--admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota",
"--service-cluster-ip-range=bar",
"--service-account-key-file=" + testCertsDir + "/sa.pub",
"--client-ca-file=" + testCertsDir + "/ca.crt",
@ -422,10 +494,131 @@ func TestGetAPIServerCommand(t *testing.T) {
"--requestheader-allowed-names=front-proxy-client",
"--authorization-mode=Node,RBAC",
"--advertise-address=2001:db8::1",
"--etcd-servers=http://127.0.0.1:2379",
"--etcd-servers=https://8.6.4.1:2379,https://8.6.4.2:2379",
"--etcd-cafile=fuz",
"--etcd-certfile=fiz",
"--etcd-keyfile=faz",
fmt.Sprintf("--endpoint-reconciler-type=%s", reconcilers.LeaseEndpointReconcilerType),
},
},
{
cfg: &kubeadmapi.MasterConfiguration{
API: kubeadmapi.API{BindPort: 123, AdvertiseAddress: "2001:db8::1"},
Networking: kubeadmapi.Networking{ServiceSubnet: "bar"},
Etcd: kubeadmapi.Etcd{Endpoints: []string{"http://127.0.0.1:2379", "http://127.0.0.1:2380"}},
CertificatesDir: testCertsDir,
KubernetesVersion: "v1.9.0-beta.0",
},
expected: []string{
"kube-apiserver",
"--insecure-port=0",
"--admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota",
"--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=http://127.0.0.1:2379,http://127.0.0.1:2380",
},
},
{
cfg: &kubeadmapi.MasterConfiguration{
API: kubeadmapi.API{BindPort: 123, AdvertiseAddress: "2001:db8::1"},
Networking: kubeadmapi.Networking{ServiceSubnet: "bar"},
Etcd: kubeadmapi.Etcd{CAFile: "fuz"},
CertificatesDir: testCertsDir,
KubernetesVersion: "v1.9.0-beta.0",
},
expected: []string{
"kube-apiserver",
"--insecure-port=0",
"--admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota",
"--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 + "/ca.crt",
"--etcd-certfile=" + testCertsDir + "/apiserver-etcd-client.crt",
"--etcd-keyfile=" + testCertsDir + "/apiserver-etcd-client.key",
},
},
{
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,
KubernetesVersion: "v1.9.0-beta.0",
AuditPolicyConfiguration: kubeadmapi.AuditPolicyConfiguration{
LogMaxAge: utilpointer.Int32Ptr(0),
},
},
expected: []string{
"kube-apiserver",
"--insecure-port=0",
"--admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota",
"--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 + "/ca.crt",
"--etcd-certfile=" + testCertsDir + "/apiserver-etcd-client.crt",
"--etcd-keyfile=" + testCertsDir + "/apiserver-etcd-client.key",
fmt.Sprintf("--endpoint-reconciler-type=%s", reconcilers.LeaseEndpointReconcilerType),
"--audit-policy-file=/etc/kubernetes/audit/audit.yaml",
"--audit-log-path=/var/log/kubernetes/audit/audit.log",
"--audit-log-maxage=0",
},
},
{
cfg: &kubeadmapi.MasterConfiguration{
API: kubeadmapi.API{BindPort: 123, AdvertiseAddress: "1.2.3.4"},
@ -437,7 +630,7 @@ func TestGetAPIServerCommand(t *testing.T) {
expected: []string{
"kube-apiserver",
"--insecure-port=0",
"--admission-control=Initializers,NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeLabel,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,ResourceQuota",
"--admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeLabel,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota",
"--service-cluster-ip-range=bar",
"--service-account-key-file=" + testCertsDir + "/sa.pub",
"--client-ca-file=" + testCertsDir + "/ca.crt",
@ -458,7 +651,10 @@ func TestGetAPIServerCommand(t *testing.T) {
"--requestheader-allowed-names=front-proxy-client",
"--authorization-mode=Node,RBAC",
"--advertise-address=1.2.3.4",
"--etcd-servers=http://127.0.0.1:2379",
"--etcd-servers=https://127.0.0.1:2379",
"--etcd-cafile=" + testCertsDir + "/ca.crt",
"--etcd-certfile=" + testCertsDir + "/apiserver-etcd-client.crt",
"--etcd-keyfile=" + testCertsDir + "/apiserver-etcd-client.key",
"--cloud-provider=gce",
},
},
@ -473,7 +669,7 @@ func TestGetAPIServerCommand(t *testing.T) {
expected: []string{
"kube-apiserver",
"--insecure-port=0",
"--admission-control=Initializers,NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeLabel,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,ResourceQuota",
"--admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeLabel,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota",
"--service-cluster-ip-range=bar",
"--service-account-key-file=" + testCertsDir + "/sa.pub",
"--client-ca-file=" + testCertsDir + "/ca.crt",
@ -494,7 +690,10 @@ func TestGetAPIServerCommand(t *testing.T) {
"--requestheader-allowed-names=front-proxy-client",
"--authorization-mode=Node,RBAC",
"--advertise-address=1.2.3.4",
"--etcd-servers=http://127.0.0.1:2379",
"--etcd-servers=https://127.0.0.1:2379",
"--etcd-cafile=" + testCertsDir + "/ca.crt",
"--etcd-certfile=" + testCertsDir + "/apiserver-etcd-client.crt",
"--etcd-keyfile=" + testCertsDir + "/apiserver-etcd-client.key",
"--cloud-provider=aws",
},
},
@ -577,7 +776,7 @@ func TestGetControllerManagerCommand(t *testing.T) {
},
{
cfg: &kubeadmapi.MasterConfiguration{
Networking: kubeadmapi.Networking{PodSubnet: "2001:101:115::/48"},
Networking: kubeadmapi.Networking{PodSubnet: "2001:db8::/64"},
CertificatesDir: testCertsDir,
KubernetesVersion: "v1.7.0",
},
@ -593,8 +792,8 @@ func TestGetControllerManagerCommand(t *testing.T) {
"--use-service-account-credentials=true",
"--controllers=*,bootstrapsigner,tokencleaner",
"--allocate-node-cidrs=true",
"--cluster-cidr=2001:101:115::/48",
"--node-cidr-mask-size=64",
"--cluster-cidr=2001:db8::/64",
"--node-cidr-mask-size=80",
},
},
}
@ -609,6 +808,77 @@ func TestGetControllerManagerCommand(t *testing.T) {
}
}
func TestCalcNodeCidrSize(t *testing.T) {
tests := []struct {
name string
podSubnet string
expectedPrefix string
}{
{
name: "Malformed pod subnet",
podSubnet: "10.10.10/160",
expectedPrefix: "24",
},
{
name: "V4: Always uses 24",
podSubnet: "10.10.10.10/16",
expectedPrefix: "24",
},
{
name: "V6: Use pod subnet size, when not enough space",
podSubnet: "2001:db8::/128",
expectedPrefix: "128",
},
{
name: "V6: Use pod subnet size, when not enough space",
podSubnet: "2001:db8::/113",
expectedPrefix: "113",
},
{
name: "V6: Special case with 256 nodes",
podSubnet: "2001:db8::/112",
expectedPrefix: "120",
},
{
name: "V6: Using /120 for node CIDR",
podSubnet: "2001:db8::/104",
expectedPrefix: "120",
},
{
name: "V6: Using /112 for node CIDR",
podSubnet: "2001:db8::/103",
expectedPrefix: "112",
},
{
name: "V6: Using /112 for node CIDR",
podSubnet: "2001:db8::/96",
expectedPrefix: "112",
},
{
name: "V6: Using /104 for node CIDR",
podSubnet: "2001:db8::/95",
expectedPrefix: "104",
},
{
name: "V6: Largest subnet currently supported",
podSubnet: "2001:db8::/66",
expectedPrefix: "80",
},
{
name: "V6: For /64 pod net, use /80",
podSubnet: "2001:db8::/64",
expectedPrefix: "80",
},
}
for _, test := range tests {
actualPrefix := calcNodeCidrSize(test.podSubnet)
if actualPrefix != test.expectedPrefix {
t.Errorf("Case [%s]\nCalc of node CIDR size for pod subnet %q failed: Expected %q, saw %q",
test.name, test.podSubnet, test.expectedPrefix, actualPrefix)
}
}
}
func TestGetControllerManagerCommandExternalCA(t *testing.T) {
tests := []struct {

View File

@ -26,6 +26,7 @@ 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"
)
@ -47,6 +48,7 @@ var caCertsPkiVolumePath = "/etc/pki"
func getHostPathVolumesForTheControlPlane(cfg *kubeadmapi.MasterConfiguration) controlPlaneHostPathMounts {
hostPathDirectoryOrCreate := v1.HostPathDirectoryOrCreate
hostPathFileOrCreate := v1.HostPathFileOrCreate
hostPathFile := v1.HostPathFile
mounts := newControlPlaneHostPathMounts()
// HostPath volumes for the API Server
@ -55,7 +57,12 @@ 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 len(cfg.Etcd.Endpoints) != 0 {
etcdVols, etcdVolMounts := getEtcdCertVolumes(cfg.Etcd, cfg.CertificatesDir)

View File

@ -26,6 +26,7 @@ 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) {
@ -258,6 +259,7 @@ 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{
@ -278,6 +280,24 @@ 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",
@ -328,6 +348,16 @@ 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",
@ -481,6 +511,11 @@ func TestGetHostPathVolumesForTheControlPlane(t *testing.T) {
cfg: &kubeadmapi.MasterConfiguration{
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,

View File

@ -9,8 +9,7 @@ load(
go_test(
name = "go_default_test",
srcs = ["local_test.go"],
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/phases/etcd",
library = ":go_default_library",
embed = [":go_default_library"],
deps = [
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
"//cmd/kubeadm/app/constants:go_default_library",

View File

@ -18,6 +18,7 @@ package etcd
import (
"fmt"
"path/filepath"
"k8s.io/api/core/v1"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
@ -28,7 +29,8 @@ import (
)
const (
etcdVolumeName = "etcd"
etcdVolumeName = "etcd-data"
certsVolumeName = "k8s-certs"
)
// CreateLocalEtcdStaticPodManifestFile will write local etcd static pod manifest file.
@ -46,18 +48,23 @@ func CreateLocalEtcdStaticPodManifestFile(manifestDir string, cfg *kubeadmapi.Ma
}
// GetEtcdPodSpec returns the etcd static Pod actualized to the context of the current MasterConfiguration
// NB. GetEtcdPodSpec methods holds the information about how kubeadm creates etcd static pod mainfests.
// NB. GetEtcdPodSpec methods holds the information about how kubeadm creates etcd static pod manifests.
func GetEtcdPodSpec(cfg *kubeadmapi.MasterConfiguration) v1.Pod {
pathType := v1.HostPathDirectoryOrCreate
etcdMounts := map[string]v1.Volume{
etcdVolumeName: staticpodutil.NewVolume(etcdVolumeName, cfg.Etcd.DataDir, &pathType),
etcdVolumeName: staticpodutil.NewVolume(etcdVolumeName, cfg.Etcd.DataDir, &pathType),
certsVolumeName: staticpodutil.NewVolume(certsVolumeName, cfg.CertificatesDir, &pathType),
}
return staticpodutil.ComponentPod(v1.Container{
Name: kubeadmconstants.Etcd,
Command: getEtcdCommand(cfg),
Image: images.GetCoreImage(kubeadmconstants.Etcd, cfg.ImageRepository, cfg.KubernetesVersion, cfg.Etcd.Image),
Name: kubeadmconstants.Etcd,
Command: getEtcdCommand(cfg),
Image: images.GetCoreImage(kubeadmconstants.Etcd, cfg.ImageRepository, cfg.KubernetesVersion, cfg.Etcd.Image),
ImagePullPolicy: cfg.ImagePullPolicy,
// Mount the etcd datadir path read-write so etcd can store data in a more persistent manner
VolumeMounts: []v1.VolumeMount{staticpodutil.NewVolumeMount(etcdVolumeName, cfg.Etcd.DataDir, false)},
VolumeMounts: []v1.VolumeMount{
staticpodutil.NewVolumeMount(etcdVolumeName, cfg.Etcd.DataDir, false),
staticpodutil.NewVolumeMount(certsVolumeName, cfg.CertificatesDir, false),
},
LivenessProbe: staticpodutil.ComponentProbe(cfg, kubeadmconstants.Etcd, 2379, "/health", v1.URISchemeHTTP),
}, etcdMounts)
}
@ -65,9 +72,17 @@ func GetEtcdPodSpec(cfg *kubeadmapi.MasterConfiguration) v1.Pod {
// getEtcdCommand builds the right etcd command from the given config object
func getEtcdCommand(cfg *kubeadmapi.MasterConfiguration) []string {
defaultArguments := map[string]string{
"listen-client-urls": "http://127.0.0.1:2379",
"advertise-client-urls": "http://127.0.0.1:2379",
"listen-client-urls": "https://127.0.0.1:2379",
"advertise-client-urls": "https://127.0.0.1:2379",
"data-dir": cfg.Etcd.DataDir,
"cert-file": filepath.Join(cfg.CertificatesDir, kubeadmconstants.EtcdServerCertName),
"key-file": filepath.Join(cfg.CertificatesDir, kubeadmconstants.EtcdServerKeyName),
"trusted-ca-file": filepath.Join(cfg.CertificatesDir, kubeadmconstants.CACertName),
"client-cert-auth": "true",
"peer-cert-file": filepath.Join(cfg.CertificatesDir, kubeadmconstants.EtcdPeerCertName),
"peer-key-file": filepath.Join(cfg.CertificatesDir, kubeadmconstants.EtcdPeerKeyName),
"peer-trusted-ca-file": filepath.Join(cfg.CertificatesDir, kubeadmconstants.CACertName),
"peer-client-cert-auth": "true",
}
command := []string{"etcd"}

View File

@ -41,7 +41,7 @@ func TestGetEtcdPodSpec(t *testing.T) {
// Assert each specs refers to the right pod
if spec.Spec.Containers[0].Name != kubeadmconstants.Etcd {
t.Errorf("getKubeConfigSpecs spec for etcd contains pod %s, expectes %s", spec.Spec.Containers[0].Name, kubeadmconstants.Etcd)
t.Errorf("getKubeConfigSpecs spec for etcd contains pod %s, expects %s", spec.Spec.Containers[0].Name, kubeadmconstants.Etcd)
}
}
@ -79,9 +79,17 @@ func TestGetEtcdCommand(t *testing.T) {
},
expected: []string{
"etcd",
"--listen-client-urls=http://127.0.0.1:2379",
"--advertise-client-urls=http://127.0.0.1:2379",
"--listen-client-urls=https://127.0.0.1:2379",
"--advertise-client-urls=https://127.0.0.1:2379",
"--data-dir=/var/lib/etcd",
"--cert-file=" + kubeadmconstants.EtcdServerCertName,
"--key-file=" + kubeadmconstants.EtcdServerKeyName,
"--trusted-ca-file=" + kubeadmconstants.CACertName,
"--client-cert-auth=true",
"--peer-cert-file=" + kubeadmconstants.EtcdPeerCertName,
"--peer-key-file=" + kubeadmconstants.EtcdPeerKeyName,
"--peer-trusted-ca-file=" + kubeadmconstants.CACertName,
"--peer-client-cert-auth=true",
},
},
{
@ -89,16 +97,24 @@ func TestGetEtcdCommand(t *testing.T) {
Etcd: kubeadmapi.Etcd{
DataDir: "/var/lib/etcd",
ExtraArgs: map[string]string{
"listen-client-urls": "http://10.0.1.10:2379",
"advertise-client-urls": "http://10.0.1.10:2379",
"listen-client-urls": "https://10.0.1.10:2379",
"advertise-client-urls": "https://10.0.1.10:2379",
},
},
},
expected: []string{
"etcd",
"--listen-client-urls=http://10.0.1.10:2379",
"--advertise-client-urls=http://10.0.1.10:2379",
"--listen-client-urls=https://10.0.1.10:2379",
"--advertise-client-urls=https://10.0.1.10:2379",
"--data-dir=/var/lib/etcd",
"--cert-file=" + kubeadmconstants.EtcdServerCertName,
"--key-file=" + kubeadmconstants.EtcdServerKeyName,
"--trusted-ca-file=" + kubeadmconstants.CACertName,
"--client-cert-auth=true",
"--peer-cert-file=" + kubeadmconstants.EtcdPeerCertName,
"--peer-key-file=" + kubeadmconstants.EtcdPeerKeyName,
"--peer-trusted-ca-file=" + kubeadmconstants.CACertName,
"--peer-client-cert-auth=true",
},
},
{
@ -107,9 +123,17 @@ func TestGetEtcdCommand(t *testing.T) {
},
expected: []string{
"etcd",
"--listen-client-urls=http://127.0.0.1:2379",
"--advertise-client-urls=http://127.0.0.1:2379",
"--listen-client-urls=https://127.0.0.1:2379",
"--advertise-client-urls=https://127.0.0.1:2379",
"--data-dir=/etc/foo",
"--cert-file=" + kubeadmconstants.EtcdServerCertName,
"--key-file=" + kubeadmconstants.EtcdServerKeyName,
"--trusted-ca-file=" + kubeadmconstants.CACertName,
"--client-cert-auth=true",
"--peer-cert-file=" + kubeadmconstants.EtcdPeerCertName,
"--peer-key-file=" + kubeadmconstants.EtcdPeerKeyName,
"--peer-trusted-ca-file=" + kubeadmconstants.CACertName,
"--peer-client-cert-auth=true",
},
},
}

View File

@ -68,7 +68,7 @@ func AddKnownTypes(s *runtime.Scheme) error {
type EtcdClusterList struct {
metav1.TypeMeta `json:",inline"`
// Standard list metadata
// More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata
// More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata
metav1.ListMeta `json:"metadata,omitempty"`
Items []EtcdCluster `json:"items"`
}

View File

@ -16,7 +16,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
// This file was autogenerated by deepcopy-gen. Do not edit it manually!
// Code generated by deepcopy-gen. DO NOT EDIT.
package spec
@ -91,9 +91,8 @@ func (in *EtcdCluster) DeepCopy() *EtcdCluster {
func (in *EtcdCluster) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
} else {
return nil
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
@ -125,9 +124,8 @@ func (in *EtcdClusterList) DeepCopy() *EtcdClusterList {
func (in *EtcdClusterList) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
} else {
return nil
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

View File

@ -41,8 +41,7 @@ filegroup(
go_test(
name = "go_default_test",
srcs = ["kubeconfig_test.go"],
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig",
library = ":go_default_library",
embed = [":go_default_library"],
deps = [
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
"//cmd/kubeadm/app/constants:go_default_library",

View File

@ -231,7 +231,7 @@ func createKubeConfigFileIfNotExists(outDir, filename string, config *clientcmda
return fmt.Errorf("failed to save kubeconfig file %s on disk: %v", kubeConfigFilePath, err)
}
fmt.Printf("[kubeconfig] Wrote KubeConfig file to disk: %q\n", filename)
fmt.Printf("[kubeconfig] Wrote KubeConfig file to disk: %q\n", kubeConfigFilePath)
return nil
}
@ -258,7 +258,7 @@ func createKubeConfigFileIfNotExists(outDir, filename string, config *clientcmda
// 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", filename)
fmt.Printf("[kubeconfig] Using existing up-to-date KubeConfig file: %q\n", kubeConfigFilePath)
return nil
}

View File

@ -71,12 +71,25 @@ func TestGetKubeConfigSpecs(t *testing.T) {
NodeName: "valid-node-name",
}
// Creates a Master Configuration pointing to the pkidir folder
cfgDNS := &kubeadmapi.MasterConfiguration{
API: kubeadmapi.API{ControlPlaneEndpoint: "api.k8s.io", BindPort: 1234},
CertificatesDir: pkidir,
NodeName: "valid-node-name",
}
// Executes getKubeConfigSpecs
specs, err := getKubeConfigSpecs(cfg)
if err != nil {
t.Fatal("getKubeConfigSpecs failed!")
}
// Executes getKubeConfigSpecs
specsDNS, err := getKubeConfigSpecs(cfgDNS)
if err != nil {
t.Fatal("getKubeConfigSpecs failed!")
}
var assertions = []struct {
kubeConfigFile string
clientName string
@ -136,6 +149,39 @@ func TestGetKubeConfigSpecs(t *testing.T) {
} else {
t.Errorf("getKubeConfigSpecs didn't create spec for %s ", assertion.kubeConfigFile)
}
// assert the spec for the kubeConfigFile exists
if spec, ok := specsDNS[assertion.kubeConfigFile]; ok {
// Assert clientName
if spec.ClientName != assertion.clientName {
t.Errorf("getKubeConfigSpecs for %s clientName is %s, expected %s", assertion.kubeConfigFile, spec.ClientName, assertion.clientName)
}
// Assert Organizations
if spec.ClientCertAuth == nil || !reflect.DeepEqual(spec.ClientCertAuth.Organizations, assertion.organizations) {
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(cfgDNS)
if err != nil {
t.Error(err)
}
if spec.APIServer != masterEndpoint {
t.Errorf("getKubeConfigSpecs didn't injected cfg.APIServer endpoint into spec for %s", assertion.kubeConfigFile)
}
// Asserts CA certs and CA keys loaded into specs
if spec.CACert == nil {
t.Errorf("getKubeConfigSpecs didn't loaded CACert into spec for %s!", assertion.kubeConfigFile)
}
if spec.ClientCertAuth == nil || spec.ClientCertAuth.CAKey == nil {
t.Errorf("getKubeConfigSpecs didn't loaded CAKey into spec for %s!", assertion.kubeConfigFile)
}
} else {
t.Errorf("getKubeConfigSpecs didn't create spec for %s ", assertion.kubeConfigFile)
}
}
}
@ -143,7 +189,7 @@ func TestBuildKubeConfigFromSpecWithClientAuth(t *testing.T) {
// Creates a CA
caCert, caKey := certstestutil.SetupCertificateAuthorithy(t)
// Executes buildKubeConfigFromSpec passing a KubeConfigSpec wiht a ClientAuth
// Executes buildKubeConfigFromSpec passing a KubeConfigSpec with a ClientAuth
config := setupdKubeConfigWithClientAuth(t, caCert, caKey, "https://1.2.3.4:1234", "myClientName", "myOrg1", "myOrg2")
// Asserts spec data are propagated to the kubeconfig
@ -155,7 +201,7 @@ func TestBuildKubeConfigFromSpecWithTokenAuth(t *testing.T) {
// Creates a CA
caCert, _ := certstestutil.SetupCertificateAuthorithy(t)
// Executes buildKubeConfigFromSpec passing a KubeConfigSpec wiht a Token
// Executes buildKubeConfigFromSpec passing a KubeConfigSpec with a Token
config := setupdKubeConfigWithTokenAuth(t, caCert, "https://1.2.3.4:1234", "myClientName", "123456")
// Asserts spec data are propagated to the kubeconfig
@ -219,7 +265,7 @@ func TestCreateKubeConfigFileIfNotExists(t *testing.T) {
t.Errorf("createKubeConfigFileIfNotExists failed")
}
// Assert creted files is there
// Assert that the created file is there
testutil.AssertFileExists(t, tmpdir, "test.conf")
}
}
@ -338,10 +384,10 @@ func TestWriteKubeConfig(t *testing.T) {
// Adds a pki folder with a ca cert to the temp folder
pkidir := testutil.SetupPkiDirWithCertificateAuthorithy(t, tmpdir)
// Retrives ca cert for assertions
// Retrieves ca cert for assertions
caCert, _, err := pkiutil.TryLoadCertAndKeyFromDisk(pkidir, kubeadmconstants.CACertAndKeyBaseName)
if err != nil {
t.Fatalf("couldn't retrive ca cert: %v", err)
t.Fatalf("couldn't retrieve ca cert: %v", err)
}
// Creates a Master Configuration pointing to the pkidir folder

View File

@ -13,7 +13,7 @@ go_library(
"//cmd/kubeadm/app/util/kubeconfig:go_default_library",
"//pkg/apis/rbac/v1:go_default_library",
"//pkg/kubelet/apis/kubeletconfig/scheme:go_default_library",
"//pkg/kubelet/apis/kubeletconfig/v1alpha1:go_default_library",
"//pkg/kubelet/apis/kubeletconfig/v1beta1: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",
@ -28,12 +28,11 @@ go_library(
go_test(
name = "go_default_test",
srcs = ["kubelet_test.go"],
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/phases/kubelet",
library = ":go_default_library",
embed = [":go_default_library"],
deps = [
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
"//cmd/kubeadm/app/constants:go_default_library",
"//pkg/kubelet/apis/kubeletconfig/v1alpha1:go_default_library",
"//pkg/kubelet/apis/kubeletconfig/v1beta1: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",

View File

@ -38,7 +38,7 @@ import (
kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig"
rbachelper "k8s.io/kubernetes/pkg/apis/rbac/v1"
kubeletconfigscheme "k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/scheme"
kubeletconfigv1alpha1 "k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/v1alpha1"
kubeletconfigv1beta1 "k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/v1beta1"
)
// CreateBaseKubeletConfiguration creates base kubelet configuration for dynamic kubelet configuration feature.
@ -50,7 +50,7 @@ func CreateBaseKubeletConfiguration(cfg *kubeadmapi.MasterConfiguration, client
if err != nil {
return err
}
kubeletBytes, err := kubeadmutil.MarshalToYamlForCodecs(cfg.KubeletConfiguration.BaseConfig, kubeletconfigv1alpha1.SchemeGroupVersion, *kubeletCodecs)
kubeletBytes, err := kubeadmutil.MarshalToYamlForCodecs(cfg.KubeletConfiguration.BaseConfig, kubeletconfigv1beta1.SchemeGroupVersion, *kubeletCodecs)
if err != nil {
return err
}
@ -210,7 +210,7 @@ func WriteInitKubeletConfigToDiskOnMaster(cfg *kubeadmapi.MasterConfiguration) e
return err
}
kubeletBytes, err := kubeadmutil.MarshalToYamlForCodecs(cfg.KubeletConfiguration.BaseConfig, kubeletconfigv1alpha1.SchemeGroupVersion, *kubeletCodecs)
kubeletBytes, err := kubeadmutil.MarshalToYamlForCodecs(cfg.KubeletConfiguration.BaseConfig, kubeletconfigv1beta1.SchemeGroupVersion, *kubeletCodecs)
if err != nil {
return err
}

View File

@ -26,7 +26,7 @@ import (
core "k8s.io/client-go/testing"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
kubeletconfigv1alpha1 "k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/v1alpha1"
kubeletconfigv1beta1 "k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/v1beta1"
)
func TestCreateBaseKubeletConfiguration(t *testing.T) {
@ -35,7 +35,7 @@ func TestCreateBaseKubeletConfiguration(t *testing.T) {
cfg := &kubeadmapi.MasterConfiguration{
NodeName: nodeName,
KubeletConfiguration: kubeadmapi.KubeletConfiguration{
BaseConfig: &kubeletconfigv1alpha1.KubeletConfiguration{
BaseConfig: &kubeletconfigv1beta1.KubeletConfiguration{
TypeMeta: metav1.TypeMeta{
Kind: "KubeletConfiguration",
},

View File

@ -9,8 +9,7 @@ load(
go_test(
name = "go_default_test",
srcs = ["markmaster_test.go"],
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/phases/markmaster",
library = ":go_default_library",
embed = [":go_default_library"],
deps = [
"//cmd/kubeadm/app/constants:go_default_library",
"//pkg/kubelet/apis:go_default_library",

View File

@ -32,9 +32,13 @@ import (
)
// MarkMaster taints the master and sets the master label
func MarkMaster(client clientset.Interface, masterName string) error {
func MarkMaster(client clientset.Interface, masterName string, taint bool) error {
fmt.Printf("[markmaster] Will mark node %s as master by adding a label and a taint\n", masterName)
if taint {
fmt.Printf("[markmaster] Will mark node %s as master by adding a label and a taint\n", masterName)
} else {
fmt.Printf("[markmaster] Will mark node %s as master by adding a label\n", masterName)
}
// Loop on every falsy return. Return with an error if raised. Exit successfully if true is returned.
return wait.Poll(kubeadmconstants.APICallRetryInterval, kubeadmconstants.MarkMasterTimeout, func() (bool, error) {
@ -56,7 +60,7 @@ func MarkMaster(client clientset.Interface, masterName string) error {
}
// The master node should be tainted and labelled accordingly
markMasterNode(n)
markMasterNode(n, taint)
newData, err := json.Marshal(n)
if err != nil {
@ -76,15 +80,23 @@ func MarkMaster(client clientset.Interface, masterName string) error {
return false, err
}
fmt.Printf("[markmaster] Master %s tainted and labelled with key/value: %s=%q\n", masterName, kubeadmconstants.LabelNodeRoleMaster, "")
if taint {
fmt.Printf("[markmaster] Master %s tainted and labelled with key/value: %s=%q\n", masterName, kubeadmconstants.LabelNodeRoleMaster, "")
} else {
fmt.Printf("[markmaster] Master %s labelled with key/value: %s=%q\n", masterName, kubeadmconstants.LabelNodeRoleMaster, "")
}
return true, nil
})
}
func markMasterNode(n *v1.Node) {
func markMasterNode(n *v1.Node, taint bool) {
n.ObjectMeta.Labels[kubeadmconstants.LabelNodeRoleMaster] = ""
addTaintIfNotExists(n, kubeadmconstants.MasterTaint)
if taint {
addTaintIfNotExists(n, kubeadmconstants.MasterTaint)
} else {
delTaintIfExists(n, kubeadmconstants.MasterTaint)
}
}
func addTaintIfNotExists(n *v1.Node, t v1.Taint) {
@ -96,3 +108,14 @@ func addTaintIfNotExists(n *v1.Node, t v1.Taint) {
n.Spec.Taints = append(n.Spec.Taints, t)
}
func delTaintIfExists(n *v1.Node, t v1.Taint) {
var taints []v1.Taint
for _, taint := range n.Spec.Taints {
if taint == t {
continue
}
taints = append(taints, t)
}
n.Spec.Taints = taints
}

View File

@ -43,32 +43,51 @@ func TestMarkMaster(t *testing.T) {
name string
existingLabel string
existingTaint *v1.Taint
wantTaint bool
expectedPatch string
}{
{
"master label and taint missing",
"",
nil,
true,
"{\"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",
"",
nil,
false,
"{\"metadata\":{\"labels\":{\"node-role.kubernetes.io/master\":\"\"}}}",
},
{
"master label missing",
"",
&kubeadmconstants.MasterTaint,
true,
"{\"metadata\":{\"labels\":{\"node-role.kubernetes.io/master\":\"\"}}}",
},
{
"master taint missing",
kubeadmconstants.LabelNodeRoleMaster,
nil,
true,
"{\"spec\":{\"taints\":[{\"effect\":\"NoSchedule\",\"key\":\"node-role.kubernetes.io/master\"}]}}",
},
{
"nothing missing",
kubeadmconstants.LabelNodeRoleMaster,
&kubeadmconstants.MasterTaint,
true,
"{}",
},
{
"nothing missing but taint unwanted",
kubeadmconstants.LabelNodeRoleMaster,
&kubeadmconstants.MasterTaint,
false,
"{\"spec\":{\"taints\":null}}",
},
}
for _, tc := range tests {
@ -125,7 +144,7 @@ func TestMarkMaster(t *testing.T) {
t.Fatalf("MarkMaster(%s): unexpected error building clientset: %v", tc.name, err)
}
err = MarkMaster(cs, hostname)
err = MarkMaster(cs, hostname, tc.wantTaint)
if err != nil {
t.Errorf("MarkMaster(%s) returned unexpected error: %v", tc.name, err)
}

View File

@ -13,13 +13,12 @@ go_test(
"selfhosting_test.go",
"selfhosting_volumes_test.go",
],
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/phases/selfhosting",
library = ":go_default_library",
embed = [":go_default_library"],
deps = [
"//cmd/kubeadm/app/constants:go_default_library",
"//cmd/kubeadm/app/util:go_default_library",
"//pkg/volume/util:go_default_library",
"//vendor/k8s.io/api/apps/v1beta2:go_default_library",
"//vendor/k8s.io/api/apps/v1:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
],
)
@ -39,7 +38,7 @@ go_library(
"//cmd/kubeadm/app/util:go_default_library",
"//cmd/kubeadm/app/util/apiclient:go_default_library",
"//pkg/volume/util:go_default_library",
"//vendor/k8s.io/api/apps/v1beta2: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/client-go/kubernetes:go_default_library",

Some files were not shown because too many files have changed in this diff Show More