kubeadm: Move .NodeName and .CRISocket to a common sub-struct

This commit is contained in:
Lucas Käldström 2018-05-29 17:51:39 +03:00
parent e3a4104479
commit b48f23b786
No known key found for this signature in database
GPG Key ID: 3FA3783D77751514
26 changed files with 309 additions and 253 deletions

View File

@ -21,6 +21,7 @@ import (
fuzz "github.com/google/gofuzz" fuzz "github.com/google/gofuzz"
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer" runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
@ -43,7 +44,6 @@ func Funcs(codecs runtimeserializer.CodecFactory) []interface{} {
obj.APIServerCertSANs = []string{"foo"} obj.APIServerCertSANs = []string{"foo"}
obj.Token = "foo" obj.Token = "foo"
obj.CRISocket = "foo"
obj.TokenTTL = &metav1.Duration{Duration: 1 * time.Hour} obj.TokenTTL = &metav1.Duration{Duration: 1 * time.Hour}
obj.TokenUsages = []string{"foo"} obj.TokenUsages = []string{"foo"}
obj.TokenGroups = []string{"foo"} obj.TokenGroups = []string{"foo"}
@ -59,6 +59,9 @@ func Funcs(codecs runtimeserializer.CodecFactory) []interface{} {
MountPath: "foo", MountPath: "foo",
Writable: false, Writable: false,
}} }}
// Note: We don't set values here for obj.Etcd.External, as these are mutually exlusive.
// And to make sure the fuzzer doesn't set a random value for obj.Etcd.External, we let
// kubeadmapi.Etcd implement fuzz.Interface (we handle that ourselves)
obj.Etcd.Local = &kubeadm.LocalEtcd{ obj.Etcd.Local = &kubeadm.LocalEtcd{
Image: "foo", Image: "foo",
DataDir: "foo", DataDir: "foo",
@ -66,9 +69,11 @@ func Funcs(codecs runtimeserializer.CodecFactory) []interface{} {
PeerCertSANs: []string{"foo"}, PeerCertSANs: []string{"foo"},
ExtraArgs: map[string]string{"foo": "foo"}, ExtraArgs: map[string]string{"foo": "foo"},
} }
// Note: We don't set values here for obj.Etcd.External, as these are mutually exlusive. obj.NodeRegistration = kubeadm.NodeRegistrationOptions{
// And to make sure the fuzzer doesn't set a random value for obj.Etcd.External, we let CRISocket: "foo",
// kubeadmapi.Etcd implement fuzz.Interface (we handle that ourselves) Name: "foo",
Taints: []v1.Taint{},
}
obj.KubeletConfiguration = kubeadm.KubeletConfiguration{ obj.KubeletConfiguration = kubeadm.KubeletConfiguration{
BaseConfig: &kubeletconfigv1beta1.KubeletConfiguration{ BaseConfig: &kubeletconfigv1beta1.KubeletConfiguration{
StaticPodPath: "foo", StaticPodPath: "foo",
@ -139,8 +144,11 @@ func Funcs(codecs runtimeserializer.CodecFactory) []interface{} {
obj.DiscoveryTimeout = &metav1.Duration{Duration: 1} obj.DiscoveryTimeout = &metav1.Duration{Duration: 1}
obj.TLSBootstrapToken = "foo" obj.TLSBootstrapToken = "foo"
obj.Token = "foo" obj.Token = "foo"
obj.CRISocket = "foo"
obj.ClusterName = "foo" obj.ClusterName = "foo"
obj.NodeRegistration = kubeadm.NodeRegistrationOptions{
CRISocket: "foo",
Name: "foo",
}
}, },
} }
} }

View File

@ -44,13 +44,9 @@ type MasterConfiguration struct {
Networking Networking Networking Networking
// KubernetesVersion is the target version of the control plane. // KubernetesVersion is the target version of the control plane.
KubernetesVersion string KubernetesVersion string
// NodeName is the name of the node that will host the k8s control plane.
// Defaults to the hostname if not provided. // NodeRegistration holds fields that relate to registering the new master node to the cluster
NodeName string NodeRegistration NodeRegistrationOptions
// 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 is used for establishing bidirectional trust between nodes and masters. // Token is used for establishing bidirectional trust between nodes and masters.
// Used for joining nodes in the cluster. // Used for joining nodes in the cluster.
@ -62,9 +58,6 @@ type MasterConfiguration struct {
// Extra groups that this token will authenticate as when used for authentication // Extra groups that this token will authenticate as when used for authentication
TokenGroups []string TokenGroups []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 // APIServerExtraArgs is a set of extra flags to pass to the API Server or override
// default ones in form of <flagname>=<value>. // default ones in form of <flagname>=<value>.
// TODO: This is temporary and ideally we would like to switch all components to // TODO: This is temporary and ideally we would like to switch all components to
@ -138,6 +131,28 @@ type API struct {
BindPort int32 BindPort int32
} }
// NodeRegistrationOptions holds fields that relate to registering a new master or node to the cluster, either via "kubeadm init" or "kubeadm join"
type NodeRegistrationOptions struct {
// Name is the `.Metadata.Name` field of the Node API object that will be created in this `kubeadm init` or `kubeadm joiń` operation.
// This field is also used in the CommonName field of the kubelet's client certificate to the API server.
// Defaults to the hostname of the node if not provided.
Name string
// CRISocket is used to retrieve container runtime info. This information will be annotated to the Node API object, for later re-use
CRISocket string
// Taints specifies the taints the Node API object should be registered with. If this field is unset, i.e. nil, in the `kubeadm init` process
// it will be defaulted to []v1.Taint{'node-role.kubernetes.io/master=""'}. If you don't want to taint your master node, set this field to an
// empty slice, i.e. `taints: {}` in the YAML file. This field is solely used for Node registration.
Taints []v1.Taint
// ExtraArgs passes through extra arguments to the kubelet. The arguments here are passed to the kubelet command line via the environment file
// kubeadm writes at runtime for the kubelet to source. This overrides the generic base-level configuration in the kubelet-config-1.X ConfigMap
// Flags have higher higher priority when parsing. These values are local and specific to the node kubeadm is executing on.
ExtraArgs map[string]string
}
// TokenDiscovery contains elements needed for token discovery. // TokenDiscovery contains elements needed for token discovery.
type TokenDiscovery struct { type TokenDiscovery struct {
// ID is the first part of a bootstrap token. Considered public information. // ID is the first part of a bootstrap token. Considered public information.
@ -223,6 +238,9 @@ type ExternalEtcd struct {
type NodeConfiguration struct { type NodeConfiguration struct {
metav1.TypeMeta metav1.TypeMeta
// NodeRegistration holds fields that relate to registering the new master node to the cluster
NodeRegistration NodeRegistrationOptions
// CACertPath is the path to the SSL certificate authority used to // CACertPath is the path to the SSL certificate authority used to
// secure comunications between node and master. // secure comunications between node and master.
// Defaults to "/etc/kubernetes/pki/ca.crt". // Defaults to "/etc/kubernetes/pki/ca.crt".
@ -239,16 +257,11 @@ type NodeConfiguration struct {
DiscoveryTokenAPIServers []string DiscoveryTokenAPIServers []string
// DiscoveryTimeout modifies the discovery timeout // DiscoveryTimeout modifies the discovery timeout
DiscoveryTimeout *metav1.Duration DiscoveryTimeout *metav1.Duration
// 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. // TLSBootstrapToken is a token used for TLS bootstrapping.
// Defaults to Token. // Defaults to Token.
TLSBootstrapToken string TLSBootstrapToken string
// Token is used for both discovery and TLS bootstrapping. // Token is used for both discovery and TLS bootstrapping.
Token string Token string
// CRISocket is used to retrieve container runtime info.
CRISocket string
// The cluster name // The cluster name
ClusterName string ClusterName string
@ -332,13 +345,13 @@ type CommonConfiguration interface {
// GetCRISocket will return the CRISocket that is defined for the MasterConfiguration. // GetCRISocket will return the CRISocket that is defined for the MasterConfiguration.
// This is used internally to deduplicate the kubeadm preflight checks. // This is used internally to deduplicate the kubeadm preflight checks.
func (cfg *MasterConfiguration) GetCRISocket() string { func (cfg *MasterConfiguration) GetCRISocket() string {
return cfg.CRISocket return cfg.NodeRegistration.CRISocket
} }
// GetNodeName will return the NodeName that is defined for the MasterConfiguration. // GetNodeName will return the NodeName that is defined for the MasterConfiguration.
// This is used internally to deduplicate the kubeadm preflight checks. // This is used internally to deduplicate the kubeadm preflight checks.
func (cfg *MasterConfiguration) GetNodeName() string { func (cfg *MasterConfiguration) GetNodeName() string {
return cfg.NodeName return cfg.NodeRegistration.Name
} }
// GetKubernetesVersion will return the KubernetesVersion that is defined for the MasterConfiguration. // GetKubernetesVersion will return the KubernetesVersion that is defined for the MasterConfiguration.
@ -350,13 +363,13 @@ func (cfg *MasterConfiguration) GetKubernetesVersion() string {
// GetCRISocket will return the CRISocket that is defined for the NodeConfiguration. // GetCRISocket will return the CRISocket that is defined for the NodeConfiguration.
// This is used internally to deduplicate the kubeadm preflight checks. // This is used internally to deduplicate the kubeadm preflight checks.
func (cfg *NodeConfiguration) GetCRISocket() string { func (cfg *NodeConfiguration) GetCRISocket() string {
return cfg.CRISocket return cfg.NodeRegistration.CRISocket
} }
// GetNodeName will return the NodeName that is defined for the NodeConfiguration. // GetNodeName will return the NodeName that is defined for the NodeConfiguration.
// This is used internally to deduplicate the kubeadm preflight checks. // This is used internally to deduplicate the kubeadm preflight checks.
func (cfg *NodeConfiguration) GetNodeName() string { func (cfg *NodeConfiguration) GetNodeName() string {
return cfg.NodeName return cfg.NodeRegistration.Name
} }
// GetKubernetesVersion will return an empty string since KubernetesVersion is not a // GetKubernetesVersion will return an empty string since KubernetesVersion is not a

View File

@ -20,15 +20,20 @@ import (
"reflect" "reflect"
"strings" "strings"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/conversion" "k8s.io/apimachinery/pkg/conversion"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
) )
func addConversionFuncs(scheme *runtime.Scheme) error { func addConversionFuncs(scheme *runtime.Scheme) error {
// Add non-generated conversion functions // Add non-generated conversion functions
err := scheme.AddConversionFuncs( err := scheme.AddConversionFuncs(
Convert_v1alpha1_MasterConfiguration_To_kubeadm_MasterConfiguration, Convert_v1alpha1_MasterConfiguration_To_kubeadm_MasterConfiguration,
Convert_kubeadm_MasterConfiguration_To_v1alpha1_MasterConfiguration,
Convert_v1alpha1_NodeConfiguration_To_kubeadm_NodeConfiguration,
Convert_kubeadm_NodeConfiguration_To_v1alpha1_NodeConfiguration,
Convert_v1alpha1_Etcd_To_kubeadm_Etcd, Convert_v1alpha1_Etcd_To_kubeadm_Etcd,
Convert_kubeadm_Etcd_To_v1alpha1_Etcd, Convert_kubeadm_Etcd_To_v1alpha1_Etcd,
) )
@ -39,6 +44,8 @@ func addConversionFuncs(scheme *runtime.Scheme) error {
return nil return nil
} }
// Upgrades below
func Convert_v1alpha1_MasterConfiguration_To_kubeadm_MasterConfiguration(in *MasterConfiguration, out *kubeadm.MasterConfiguration, s conversion.Scope) error { func Convert_v1alpha1_MasterConfiguration_To_kubeadm_MasterConfiguration(in *MasterConfiguration, out *kubeadm.MasterConfiguration, s conversion.Scope) error {
if err := autoConvert_v1alpha1_MasterConfiguration_To_kubeadm_MasterConfiguration(in, out, s); err != nil { if err := autoConvert_v1alpha1_MasterConfiguration_To_kubeadm_MasterConfiguration(in, out, s); err != nil {
return err return err
@ -46,12 +53,26 @@ func Convert_v1alpha1_MasterConfiguration_To_kubeadm_MasterConfiguration(in *Mas
UpgradeCloudProvider(in, out) UpgradeCloudProvider(in, out)
UpgradeAuthorizationModes(in, out) UpgradeAuthorizationModes(in, out)
UpgradeNodeRegistrationOptionsForMaster(in, out)
// We don't support migrating information from the .PrivilegedPods field which was removed in v1alpha2 // We don't support migrating information from the .PrivilegedPods field which was removed in v1alpha2
// We don't support migrating information from the .ImagePullPolicy field which was removed in v1alpha2 // We don't support migrating information from the .ImagePullPolicy field which was removed in v1alpha2
return nil return nil
} }
func Convert_v1alpha1_NodeConfiguration_To_kubeadm_NodeConfiguration(in *NodeConfiguration, out *kubeadm.NodeConfiguration, s conversion.Scope) error {
if err := autoConvert_v1alpha1_NodeConfiguration_To_kubeadm_NodeConfiguration(in, out, s); err != nil {
return err
}
// .NodeName has moved to .NodeRegistration.Name
out.NodeRegistration.Name = in.NodeName
// .CRISocket has moved to .NodeRegistration.CRISocket
out.NodeRegistration.CRISocket = in.CRISocket
return nil
}
func Convert_v1alpha1_Etcd_To_kubeadm_Etcd(in *Etcd, out *kubeadm.Etcd, s conversion.Scope) error { func Convert_v1alpha1_Etcd_To_kubeadm_Etcd(in *Etcd, out *kubeadm.Etcd, s conversion.Scope) error {
if err := autoConvert_v1alpha1_Etcd_To_kubeadm_Etcd(in, out, s); err != nil { if err := autoConvert_v1alpha1_Etcd_To_kubeadm_Etcd(in, out, s); err != nil {
return err return err
@ -123,3 +144,45 @@ func UpgradeAuthorizationModes(in *MasterConfiguration, out *kubeadm.MasterConfi
out.APIServerExtraArgs["authorization-mode"] = strings.Join(in.AuthorizationModes, ",") out.APIServerExtraArgs["authorization-mode"] = strings.Join(in.AuthorizationModes, ",")
} }
} }
func UpgradeNodeRegistrationOptionsForMaster(in *MasterConfiguration, out *kubeadm.MasterConfiguration) {
// .NodeName has moved to .NodeRegistration.Name
out.NodeRegistration.Name = in.NodeName
// .CRISocket has moved to .NodeRegistration.CRISocket
out.NodeRegistration.CRISocket = in.CRISocket
// Transfer the information from .NoTaintMaster to the new layout
if in.NoTaintMaster {
out.NodeRegistration.Taints = []v1.Taint{}
} else {
out.NodeRegistration.Taints = []v1.Taint{constants.MasterTaint}
}
}
// Downgrades below
func Convert_kubeadm_MasterConfiguration_To_v1alpha1_MasterConfiguration(in *kubeadm.MasterConfiguration, out *MasterConfiguration, s conversion.Scope) error {
if err := autoConvert_kubeadm_MasterConfiguration_To_v1alpha1_MasterConfiguration(in, out, s); err != nil {
return err
}
// Converting from newer API version to an older API version isn't supported. This is here only for the roundtrip tests meanwhile.
out.NodeName = in.NodeRegistration.Name
out.CRISocket = in.NodeRegistration.CRISocket
out.NoTaintMaster = in.NodeRegistration.Taints != nil && len(in.NodeRegistration.Taints) == 0
return nil
}
func Convert_kubeadm_NodeConfiguration_To_v1alpha1_NodeConfiguration(in *kubeadm.NodeConfiguration, out *NodeConfiguration, s conversion.Scope) error {
if err := autoConvert_kubeadm_NodeConfiguration_To_v1alpha1_NodeConfiguration(in, out, s); err != nil {
return err
}
// Converting from newer API version to an older API version isn't supported. This is here only for the roundtrip tests meanwhile.
out.NodeName = in.NodeRegistration.Name
out.CRISocket = in.NodeRegistration.CRISocket
return nil
}

View File

@ -103,10 +103,6 @@ func SetDefaults_MasterConfiguration(obj *MasterConfiguration) {
} }
} }
if obj.CRISocket == "" {
obj.CRISocket = DefaultCRISocket
}
if len(obj.TokenUsages) == 0 { if len(obj.TokenUsages) == 0 {
obj.TokenUsages = constants.DefaultTokenUsages obj.TokenUsages = constants.DefaultTokenUsages
} }
@ -123,6 +119,7 @@ func SetDefaults_MasterConfiguration(obj *MasterConfiguration) {
obj.ClusterName = DefaultClusterName obj.ClusterName = DefaultClusterName
} }
SetDefaults_NodeRegistrationOptions(&obj.NodeRegistration)
SetDefaults_KubeletConfiguration(obj) SetDefaults_KubeletConfiguration(obj)
SetDefaults_Etcd(obj) SetDefaults_Etcd(obj)
SetDefaults_ProxyConfiguration(obj) SetDefaults_ProxyConfiguration(obj)
@ -168,9 +165,6 @@ func SetDefaults_NodeConfiguration(obj *NodeConfiguration) {
if len(obj.DiscoveryToken) == 0 && len(obj.DiscoveryFile) == 0 { if len(obj.DiscoveryToken) == 0 && len(obj.DiscoveryFile) == 0 {
obj.DiscoveryToken = obj.Token obj.DiscoveryToken = obj.Token
} }
if obj.CRISocket == "" {
obj.CRISocket = DefaultCRISocket
}
// Make sure file URLs become paths // Make sure file URLs become paths
if len(obj.DiscoveryFile) != 0 { if len(obj.DiscoveryFile) != 0 {
u, err := url.Parse(obj.DiscoveryFile) u, err := url.Parse(obj.DiscoveryFile)
@ -186,6 +180,8 @@ func SetDefaults_NodeConfiguration(obj *NodeConfiguration) {
if obj.ClusterName == "" { if obj.ClusterName == "" {
obj.ClusterName = DefaultClusterName obj.ClusterName = DefaultClusterName
} }
SetDefaults_NodeRegistrationOptions(&obj.NodeRegistration)
} }
// SetDefaults_KubeletConfiguration assigns default values to kubelet // SetDefaults_KubeletConfiguration assigns default values to kubelet
@ -237,6 +233,12 @@ func SetDefaults_KubeletConfiguration(obj *MasterConfiguration) {
} }
} }
func SetDefaults_NodeRegistrationOptions(obj *NodeRegistrationOptions) {
if obj.CRISocket == "" {
obj.CRISocket = DefaultCRISocket
}
}
// SetDefaults_AuditPolicyConfiguration sets default values for the AuditPolicyConfiguration // SetDefaults_AuditPolicyConfiguration sets default values for the AuditPolicyConfiguration
func SetDefaults_AuditPolicyConfiguration(obj *MasterConfiguration) { func SetDefaults_AuditPolicyConfiguration(obj *MasterConfiguration) {
if obj.AuditPolicyConfiguration.LogDir == "" { if obj.AuditPolicyConfiguration.LogDir == "" {

View File

@ -40,15 +40,12 @@ type MasterConfiguration struct {
KubeletConfiguration KubeletConfiguration `json:"kubeletConfiguration"` KubeletConfiguration KubeletConfiguration `json:"kubeletConfiguration"`
// Networking holds configuration for the networking topology of the cluster. // Networking holds configuration for the networking topology of the cluster.
Networking Networking `json:"networking"` Networking Networking `json:"networking"`
// NodeRegistration holds fields that relate to registering the new master node to the cluster
NodeRegistration NodeRegistrationOptions `json:"nodeRegistration"`
// KubernetesVersion is the target version of the control plane. // KubernetesVersion is the target version of the control plane.
KubernetesVersion string `json:"kubernetesVersion"` KubernetesVersion string `json:"kubernetesVersion"`
// 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"`
// 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 is used for establishing bidirectional trust between nodes and masters. // Token is used for establishing bidirectional trust between nodes and masters.
// Used for joining nodes in the cluster. // Used for joining nodes in the cluster.
@ -60,9 +57,6 @@ type MasterConfiguration struct {
// Extra groups that this token will authenticate as when used for authentication // Extra groups that this token will authenticate as when used for authentication
TokenGroups []string `json:"tokenGroups,omitempty"` TokenGroups []string `json:"tokenGroups,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 // APIServerExtraArgs is a set of extra flags to pass to the API Server or override
// default ones in form of <flagname>=<value>. // default ones in form of <flagname>=<value>.
// TODO: This is temporary and ideally we would like to switch all components to // TODO: This is temporary and ideally we would like to switch all components to
@ -129,6 +123,28 @@ type API struct {
BindPort int32 `json:"bindPort"` BindPort int32 `json:"bindPort"`
} }
// NodeRegistrationOptions holds fields that relate to registering a new master or node to the cluster, either via "kubeadm init" or "kubeadm join"
type NodeRegistrationOptions struct {
// Name is the `.Metadata.Name` field of the Node API object that will be created in this `kubeadm init` or `kubeadm joiń` operation.
// This field is also used in the CommonName field of the kubelet's client certificate to the API server.
// Defaults to the hostname of the node if not provided.
Name string `json:"name"`
// CRISocket is used to retrieve container runtime info. This information will be annotated to the Node API object, for later re-use
CRISocket string `json:"criSocket"`
// Taints specifies the taints the Node API object should be registered with. If this field is unset, i.e. nil, in the `kubeadm init` process
// it will be defaulted to []v1.Taint{'node-role.kubernetes.io/master=""'}. If you don't want to taint your master node, set this field to an
// empty slice, i.e. `taints: {}` in the YAML file. This field is solely used for Node registration.
Taints []v1.Taint `json:"taints,omitempty"`
// ExtraArgs passes through extra arguments to the kubelet. The arguments here are passed to the kubelet command line via the environment file
// kubeadm writes at runtime for the kubelet to source. This overrides the generic base-level configuration in the kubelet-config-1.X ConfigMap
// Flags have higher higher priority when parsing. These values are local and specific to the node kubeadm is executing on.
ExtraArgs map[string]string `json:"kubeletExtraArgs,omitempty"`
}
// TokenDiscovery contains elements needed for token discovery. // TokenDiscovery contains elements needed for token discovery.
type TokenDiscovery struct { type TokenDiscovery struct {
// ID is the first part of a bootstrap token. Considered public information. // ID is the first part of a bootstrap token. Considered public information.
@ -206,6 +222,9 @@ type ExternalEtcd struct {
type NodeConfiguration struct { type NodeConfiguration struct {
metav1.TypeMeta `json:",inline"` metav1.TypeMeta `json:",inline"`
// NodeRegistration holds fields that relate to registering the new master node to the cluster
NodeRegistration NodeRegistrationOptions `json:"nodeRegistration"`
// CACertPath is the path to the SSL certificate authority used to // CACertPath is the path to the SSL certificate authority used to
// secure comunications between node and master. // secure comunications between node and master.
// Defaults to "/etc/kubernetes/pki/ca.crt". // Defaults to "/etc/kubernetes/pki/ca.crt".
@ -222,16 +241,12 @@ type NodeConfiguration struct {
DiscoveryTokenAPIServers []string `json:"discoveryTokenAPIServers,omitempty"` DiscoveryTokenAPIServers []string `json:"discoveryTokenAPIServers,omitempty"`
// DiscoveryTimeout modifies the discovery timeout // DiscoveryTimeout modifies the discovery timeout
DiscoveryTimeout *metav1.Duration `json:"discoveryTimeout,omitempty"` DiscoveryTimeout *metav1.Duration `json:"discoveryTimeout,omitempty"`
// 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. // TLSBootstrapToken is a token used for TLS bootstrapping.
// Defaults to Token. // Defaults to Token.
TLSBootstrapToken string `json:"tlsBootstrapToken"` TLSBootstrapToken string `json:"tlsBootstrapToken"`
// Token is used for both discovery and TLS bootstrapping. // Token is used for both discovery and TLS bootstrapping.
Token string `json:"token"` Token string `json:"token"`
// CRISocket is used to retrieve container runtime info.
CRISocket string `json:"criSocket,omitempty"`
// ClusterName is the name for the cluster in kubeconfig. // ClusterName is the name for the cluster in kubeconfig.
ClusterName string `json:"clusterName,omitempty"` ClusterName string `json:"clusterName,omitempty"`

View File

@ -54,7 +54,7 @@ func ValidateMasterConfiguration(c *kubeadm.MasterConfiguration) field.ErrorList
allErrs = append(allErrs, ValidateNetworking(&c.Networking, field.NewPath("networking"))...) allErrs = append(allErrs, ValidateNetworking(&c.Networking, field.NewPath("networking"))...)
allErrs = append(allErrs, ValidateCertSANs(c.APIServerCertSANs, field.NewPath("apiServerCertSANs"))...) allErrs = append(allErrs, ValidateCertSANs(c.APIServerCertSANs, field.NewPath("apiServerCertSANs"))...)
allErrs = append(allErrs, ValidateAbsolutePath(c.CertificatesDir, field.NewPath("certificatesDir"))...) allErrs = append(allErrs, ValidateAbsolutePath(c.CertificatesDir, field.NewPath("certificatesDir"))...)
allErrs = append(allErrs, ValidateNodeName(c.NodeName, field.NewPath("nodeName"))...) allErrs = append(allErrs, ValidateNodeRegistrationOptions(&c.NodeRegistration, field.NewPath("nodeRegistration"))...)
allErrs = append(allErrs, ValidateToken(c.Token, field.NewPath("token"))...) allErrs = append(allErrs, ValidateToken(c.Token, field.NewPath("token"))...)
allErrs = append(allErrs, ValidateTokenUsages(c.TokenUsages, field.NewPath("tokenUsages"))...) allErrs = append(allErrs, ValidateTokenUsages(c.TokenUsages, field.NewPath("tokenUsages"))...)
allErrs = append(allErrs, ValidateTokenGroups(c.TokenUsages, c.TokenGroups, field.NewPath("tokenGroups"))...) allErrs = append(allErrs, ValidateTokenGroups(c.TokenUsages, c.TokenGroups, field.NewPath("tokenGroups"))...)
@ -62,9 +62,7 @@ func ValidateMasterConfiguration(c *kubeadm.MasterConfiguration) field.ErrorList
allErrs = append(allErrs, ValidateAPIEndpoint(&c.API, field.NewPath("api"))...) allErrs = append(allErrs, ValidateAPIEndpoint(&c.API, field.NewPath("api"))...)
allErrs = append(allErrs, ValidateProxy(c.KubeProxy.Config, field.NewPath("kubeProxy").Child("config"))...) allErrs = append(allErrs, ValidateProxy(c.KubeProxy.Config, field.NewPath("kubeProxy").Child("config"))...)
allErrs = append(allErrs, ValidateEtcd(&c.Etcd, field.NewPath("etcd"))...) allErrs = append(allErrs, ValidateEtcd(&c.Etcd, field.NewPath("etcd"))...)
if features.Enabled(c.FeatureGates, features.DynamicKubeletConfig) { allErrs = append(allErrs, ValidateKubeletConfiguration(&c.KubeletConfiguration, field.NewPath("kubeletConfiguration"))...)
allErrs = append(allErrs, ValidateKubeletConfiguration(&c.KubeletConfiguration, field.NewPath("kubeletConfiguration"))...)
}
return allErrs return allErrs
} }
@ -86,6 +84,7 @@ func ValidateProxy(c *kubeproxyconfigv1alpha1.KubeProxyConfiguration, fldPath *f
func ValidateNodeConfiguration(c *kubeadm.NodeConfiguration) field.ErrorList { func ValidateNodeConfiguration(c *kubeadm.NodeConfiguration) field.ErrorList {
allErrs := field.ErrorList{} allErrs := field.ErrorList{}
allErrs = append(allErrs, ValidateDiscovery(c)...) allErrs = append(allErrs, ValidateDiscovery(c)...)
allErrs = append(allErrs, ValidateNodeRegistrationOptions(&c.NodeRegistration, field.NewPath("nodeRegistration"))...)
if !filepath.IsAbs(c.CACertPath) || !strings.HasSuffix(c.CACertPath, ".crt") { if !filepath.IsAbs(c.CACertPath) || !strings.HasSuffix(c.CACertPath, ".crt") {
allErrs = append(allErrs, field.Invalid(field.NewPath("caCertPath"), c.CACertPath, "the ca certificate path must be an absolute path")) allErrs = append(allErrs, field.Invalid(field.NewPath("caCertPath"), c.CACertPath, "the ca certificate path must be an absolute path"))
@ -93,6 +92,15 @@ func ValidateNodeConfiguration(c *kubeadm.NodeConfiguration) field.ErrorList {
return allErrs return allErrs
} }
// ValidateNodeRegistrationOptions validates the NodeRegistrationOptions object
func ValidateNodeRegistrationOptions(nro *kubeadm.NodeRegistrationOptions, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
allErrs = append(allErrs, ValidateNodeName(nro.Name, fldPath.Child("name"))...)
allErrs = append(allErrs, ValidateAbsolutePath(nro.CRISocket, fldPath.Child("criSocket"))...)
// TODO: Maybe validate .Taints as well in the future using something like validateNodeTaints() in pkg/apis/core/validation
return allErrs
}
// ValidateDiscovery validates discovery related configuration and collects all encountered errors // ValidateDiscovery validates discovery related configuration and collects all encountered errors
func ValidateDiscovery(c *kubeadm.NodeConfiguration) field.ErrorList { func ValidateDiscovery(c *kubeadm.NodeConfiguration) field.ErrorList {
allErrs := field.ErrorList{} allErrs := field.ErrorList{}
@ -422,6 +430,10 @@ func ValidateIgnorePreflightErrors(ignorePreflightErrors []string, skipPreflight
func ValidateKubeletConfiguration(c *kubeadm.KubeletConfiguration, fldPath *field.Path) field.ErrorList { func ValidateKubeletConfiguration(c *kubeadm.KubeletConfiguration, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{} allErrs := field.ErrorList{}
if c.BaseConfig == nil {
return allErrs
}
scheme, _, err := kubeletscheme.NewSchemeAndCodecs() scheme, _, err := kubeletscheme.NewSchemeAndCodecs()
if err != nil { if err != nil {
allErrs = append(allErrs, field.Invalid(fldPath, "kubeletConfiguration", err.Error())) allErrs = append(allErrs, field.Invalid(fldPath, "kubeletConfiguration", err.Error()))

View File

@ -401,5 +401,5 @@ func AddImagesCommonConfigFlags(flagSet *flag.FlagSet, cfg *kubeadmapiv1alpha2.M
// AddImagesPullFlags adds flags related to the `kubeadm config images pull` command // AddImagesPullFlags adds flags related to the `kubeadm config images pull` command
func AddImagesPullFlags(flagSet *flag.FlagSet, cfg *kubeadmapiv1alpha2.MasterConfiguration) { func AddImagesPullFlags(flagSet *flag.FlagSet, cfg *kubeadmapiv1alpha2.MasterConfiguration) {
flagSet.StringVar(&cfg.CRISocket, "cri-socket-path", cfg.CRISocket, "Path to the CRI socket.") flagSet.StringVar(&cfg.NodeRegistration.CRISocket, "cri-socket-path", cfg.NodeRegistration.CRISocket, "Path to the CRI socket.")
} }

View File

@ -189,7 +189,7 @@ func AddInitConfigFlags(flagSet *flag.FlagSet, cfg *kubeadmapiv1alpha2.MasterCon
`Optional extra Subject Alternative Names (SANs) to use for the API Server serving certificate. Can be both IP addresses and DNS names.`, `Optional extra Subject Alternative Names (SANs) to use for the API Server serving certificate. Can be both IP addresses and DNS names.`,
) )
flagSet.StringVar( flagSet.StringVar(
&cfg.NodeName, "node-name", cfg.NodeName, &cfg.NodeRegistration.Name, "node-name", cfg.NodeRegistration.Name,
`Specify the node name.`, `Specify the node name.`,
) )
flagSet.StringVar( flagSet.StringVar(
@ -201,7 +201,7 @@ func AddInitConfigFlags(flagSet *flag.FlagSet, cfg *kubeadmapiv1alpha2.MasterCon
"The duration before the bootstrap token is automatically deleted. If set to '0', the token will never expire.", "The duration before the bootstrap token is automatically deleted. If set to '0', the token will never expire.",
) )
flagSet.StringVar( flagSet.StringVar(
&cfg.CRISocket, "cri-socket", cfg.CRISocket, &cfg.NodeRegistration.CRISocket, "cri-socket", cfg.NodeRegistration.CRISocket,
`Specify the CRI socket to connect to.`, `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. "+ flagSet.StringVar(featureGatesString, "feature-gates", *featureGatesString, "A set of key=value pairs that describe feature gates for various features. "+
@ -276,8 +276,10 @@ type Init struct {
// Run executes master node provisioning, including certificates, needed static pod manifests, etc. // Run executes master node provisioning, including certificates, needed static pod manifests, etc.
func (i *Init) Run(out io.Writer) error { func (i *Init) Run(out io.Writer) error {
// Write env file with flags for the kubelet to use // Write env file with flags for the kubelet to use. We do not need to write the --register-with-taints for the master,
if err := kubeletphase.WriteKubeletDynamicEnvFile(i.cfg); err != nil { // as we handle that ourselves in the markmaster phase
// TODO: Maybe we want to do that some time in the future, in order to remove some logic from the markmaster phase?
if err := kubeletphase.WriteKubeletDynamicEnvFile(&i.cfg.NodeRegistration, false); err != nil {
return err return err
} }
@ -362,7 +364,7 @@ func (i *Init) Run(out io.Writer) error {
} }
// Write the kubelet configuration to disk. // Write the kubelet configuration to disk.
if err := kubeletphase.WriteConfigToDisk(i.cfg.KubeletConfiguration.BaseConfig, kubeletVersion); err != nil { if err := kubeletphase.WriteConfigToDisk(i.cfg.KubeletConfiguration.BaseConfig); err != nil {
return fmt.Errorf("error writing kubelet configuration to disk: %v", err) return fmt.Errorf("error writing kubelet configuration to disk: %v", err)
} }
@ -411,7 +413,7 @@ func (i *Init) Run(out io.Writer) error {
// PHASE 4: Mark the master with the right label/taint // PHASE 4: Mark the master with the right label/taint
glog.V(1).Infof("[init] marking the master with right label") glog.V(1).Infof("[init] marking the master with right label")
if err := markmasterphase.MarkMaster(client, i.cfg.NodeName, !i.cfg.NoTaintMaster); err != nil { if err := markmasterphase.MarkMaster(client, i.cfg.NodeRegistration.Name, i.cfg.NodeRegistration.Taints); err != nil {
return fmt.Errorf("error marking master: %v", err) return fmt.Errorf("error marking master: %v", err)
} }
@ -419,7 +421,7 @@ func (i *Init) Run(out io.Writer) error {
// This feature is disabled by default, as it is alpha still // This feature is disabled by default, as it is alpha still
if features.Enabled(i.cfg.FeatureGates, features.DynamicKubeletConfig) { if features.Enabled(i.cfg.FeatureGates, features.DynamicKubeletConfig) {
// Enable dynamic kubelet configuration for the node. // Enable dynamic kubelet configuration for the node.
if err := kubeletphase.EnableDynamicConfigForNode(client, i.cfg.NodeName, kubeletVersion); err != nil { if err := kubeletphase.EnableDynamicConfigForNode(client, i.cfg.NodeRegistration.Name, kubeletVersion); err != nil {
return fmt.Errorf("error enabling dynamic kubelet configuration: %v", err) return fmt.Errorf("error enabling dynamic kubelet configuration: %v", err)
} }
} }
@ -507,7 +509,7 @@ func (i *Init) Run(out io.Writer) error {
func createClient(cfg *kubeadmapi.MasterConfiguration, dryRun bool) (clientset.Interface, error) { func createClient(cfg *kubeadmapi.MasterConfiguration, dryRun bool) (clientset.Interface, error) {
if dryRun { if dryRun {
// If we're dry-running; we should create a faked client that answers some GETs in order to be able to do the full init flow and just logs the rest of requests // If we're dry-running; we should create a faked client that answers some GETs in order to be able to do the full init flow and just logs the rest of requests
dryRunGetter := apiclient.NewInitDryRunGetter(cfg.NodeName, cfg.Networking.ServiceSubnet) dryRunGetter := apiclient.NewInitDryRunGetter(cfg.NodeRegistration.Name, cfg.Networking.ServiceSubnet)
return apiclient.NewDryRunClient(dryRunGetter, os.Stdout), nil return apiclient.NewDryRunClient(dryRunGetter, os.Stdout), nil
} }

View File

@ -155,7 +155,7 @@ func AddJoinConfigFlags(flagSet *flag.FlagSet, cfg *kubeadmapiv1alpha2.NodeConfi
&cfg.DiscoveryToken, "discovery-token", "", &cfg.DiscoveryToken, "discovery-token", "",
"A token used to validate cluster information fetched from the master.") "A token used to validate cluster information fetched from the master.")
flagSet.StringVar( flagSet.StringVar(
&cfg.NodeName, "node-name", "", &cfg.NodeRegistration.Name, "node-name", cfg.NodeRegistration.Name,
"Specify the node name.") "Specify the node name.")
flagSet.StringVar( flagSet.StringVar(
&cfg.TLSBootstrapToken, "tls-bootstrap-token", "", &cfg.TLSBootstrapToken, "tls-bootstrap-token", "",
@ -174,7 +174,7 @@ func AddJoinConfigFlags(flagSet *flag.FlagSet, cfg *kubeadmapiv1alpha2.NodeConfi
"A set of key=value pairs that describe feature gates for various features. "+ "A set of key=value pairs that describe feature gates for various features. "+
"Options are:\n"+strings.Join(features.KnownFeatures(&features.InitFeatureGates), "\n")) "Options are:\n"+strings.Join(features.KnownFeatures(&features.InitFeatureGates), "\n"))
flagSet.StringVar( flagSet.StringVar(
&cfg.CRISocket, "cri-socket", cfg.CRISocket, &cfg.NodeRegistration.CRISocket, "cri-socket", cfg.NodeRegistration.CRISocket,
`Specify the CRI socket to connect to.`, `Specify the CRI socket to connect to.`,
) )
} }
@ -204,7 +204,7 @@ type Join struct {
// NewJoin instantiates Join struct with given arguments // NewJoin instantiates Join struct with given arguments
func NewJoin(cfgPath string, args []string, defaultcfg *kubeadmapiv1alpha2.NodeConfiguration, ignorePreflightErrors sets.String) (*Join, error) { func NewJoin(cfgPath string, args []string, defaultcfg *kubeadmapiv1alpha2.NodeConfiguration, ignorePreflightErrors sets.String) (*Join, error) {
if defaultcfg.NodeName == "" { if defaultcfg.NodeRegistration.Name == "" {
glog.V(1).Infoln("[join] found NodeName empty") glog.V(1).Infoln("[join] found NodeName empty")
glog.V(1).Infoln("[join] considered OS hostname as NodeName") glog.V(1).Infoln("[join] considered OS hostname as NodeName")
} }
@ -231,6 +231,12 @@ func NewJoin(cfgPath string, args []string, defaultcfg *kubeadmapiv1alpha2.NodeC
// Run executes worker node provisioning and tries to join an existing cluster. // Run executes worker node provisioning and tries to join an existing cluster.
func (j *Join) Run(out io.Writer) error { func (j *Join) Run(out io.Writer) error {
// Write env file with flags for the kubelet to use. Also register taints
if err := kubeletphase.WriteKubeletDynamicEnvFile(&j.cfg.NodeRegistration, true); err != nil {
return err
}
glog.V(1).Infoln("[join] retrieving KubeConfig objects") glog.V(1).Infoln("[join] retrieving KubeConfig objects")
cfg, err := discovery.For(j.cfg) cfg, err := discovery.For(j.cfg)
if err != nil { if err != nil {
@ -273,7 +279,7 @@ func (j *Join) Run(out io.Writer) error {
return err return err
} }
if err := kubeletphase.EnableDynamicConfigForNode(client, j.cfg.NodeName, kubeletVersion); err != nil { if err := kubeletphase.EnableDynamicConfigForNode(client, j.cfg.NodeRegistration.Name, kubeletVersion); err != nil {
return fmt.Errorf("error consuming base kubelet configuration: %v", err) return fmt.Errorf("error consuming base kubelet configuration: %v", err)
} }
} }

View File

@ -184,7 +184,7 @@ func getKubeConfigSubCommands(out io.Writer, outDir, defaultKubernetesVersion st
cmd.Flags().Int32Var(&cfg.API.BindPort, "apiserver-bind-port", cfg.API.BindPort, "The port 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(&outDir, "kubeconfig-dir", outDir, "The path where to save the kubeconfig file") cmd.Flags().StringVar(&outDir, "kubeconfig-dir", outDir, "The path where to save the kubeconfig file")
if properties.use == "all" || properties.use == "kubelet" { if properties.use == "all" || properties.use == "kubelet" {
cmd.Flags().StringVar(&cfg.NodeName, "node-name", cfg.NodeName, `The node name that should be used for the kubelet client certificate`) cmd.Flags().StringVar(&cfg.NodeRegistration.Name, "node-name", cfg.NodeRegistration.Name, `The node name that should be used for the kubelet client certificate`)
} }
if properties.use == "user" { if properties.use == "user" {
cmd.Flags().StringVar(&token, "token", token, "The token that should be used as the authentication mechanism for this kubeconfig, instead of client certificates") cmd.Flags().StringVar(&token, "token", token, "The token that should be used as the authentication mechanism for this kubeconfig, instead of client certificates")

View File

@ -134,9 +134,6 @@ func NewCmdKubeletWriteConfigToDisk(kubeConfigFile *string) *cobra.Command {
kubeadmutil.CheckErr(fmt.Errorf("The --kubelet-version argument is required")) kubeadmutil.CheckErr(fmt.Errorf("The --kubelet-version argument is required"))
} }
kubeletVersion, err := version.ParseSemantic(kubeletVersionStr)
kubeadmutil.CheckErr(err)
client, err := kubeconfigutil.ClientSetFromFile(*kubeConfigFile) client, err := kubeconfigutil.ClientSetFromFile(*kubeConfigFile)
kubeadmutil.CheckErr(err) kubeadmutil.CheckErr(err)
@ -144,7 +141,7 @@ func NewCmdKubeletWriteConfigToDisk(kubeConfigFile *string) *cobra.Command {
internalcfg, err := configutil.FetchConfigFromFileOrCluster(client, os.Stdout, "kubelet", cfgPath) internalcfg, err := configutil.FetchConfigFromFileOrCluster(client, os.Stdout, "kubelet", cfgPath)
kubeadmutil.CheckErr(err) kubeadmutil.CheckErr(err)
err = kubeletphase.WriteConfigToDisk(internalcfg.KubeletConfiguration.BaseConfig, kubeletVersion) err = kubeletphase.WriteConfigToDisk(internalcfg.KubeletConfiguration.BaseConfig)
kubeadmutil.CheckErr(err) kubeadmutil.CheckErr(err)
}, },
} }

View File

@ -75,14 +75,14 @@ func NewCmdMarkMaster() *cobra.Command {
client, err := kubeconfigutil.ClientSetFromFile(kubeConfigFile) client, err := kubeconfigutil.ClientSetFromFile(kubeConfigFile)
kubeadmutil.CheckErr(err) kubeadmutil.CheckErr(err)
err = markmasterphase.MarkMaster(client, internalcfg.NodeName, !internalcfg.NoTaintMaster) err = markmasterphase.MarkMaster(client, internalcfg.NodeRegistration.Name, internalcfg.NodeRegistration.Taints)
kubeadmutil.CheckErr(err) kubeadmutil.CheckErr(err)
}, },
} }
cmd.Flags().StringVar(&kubeConfigFile, "kubeconfig", "/etc/kubernetes/admin.conf", "The KubeConfig file to use when talking to the cluster") cmd.Flags().StringVar(&kubeConfigFile, "kubeconfig", "/etc/kubernetes/admin.conf", "The KubeConfig file to use when talking to the cluster")
cmd.Flags().StringVar(&cfgPath, "config", cfgPath, "Path to kubeadm config file. WARNING: Usage of a configuration file is experimental") cmd.Flags().StringVar(&cfgPath, "config", cfgPath, "Path to kubeadm config file. WARNING: Usage of a configuration file is experimental")
cmd.Flags().StringVar(&cfg.NodeName, "node-name", cfg.NodeName, `The node name to which label and taints should apply`) cmd.Flags().StringVar(&cfg.NodeRegistration.Name, "node-name", cfg.NodeRegistration.Name, `The node name to which label and taints should apply`)
return cmd return cmd
} }

View File

@ -165,8 +165,8 @@ const (
APICallRetryInterval = 500 * time.Millisecond APICallRetryInterval = 500 * time.Millisecond
// DiscoveryRetryInterval specifies how long kubeadm should wait before retrying to connect to the master when doing discovery // DiscoveryRetryInterval specifies how long kubeadm should wait before retrying to connect to the master when doing discovery
DiscoveryRetryInterval = 5 * time.Second DiscoveryRetryInterval = 5 * time.Second
// MarkMasterTimeout specifies how long kubeadm should wait for applying the label and taint on the master before timing out // PatchNodeTimeout specifies how long kubeadm should wait for applying the label and taint on the master before timing out
MarkMasterTimeout = 2 * time.Minute PatchNodeTimeout = 2 * time.Minute
// UpdateNodeTimeout specifies how long kubeadm should wait for updating node with the initial remote configuration of kubelet before timing out // UpdateNodeTimeout specifies how long kubeadm should wait for updating node with the initial remote configuration of kubelet before timing out
UpdateNodeTimeout = 2 * time.Minute UpdateNodeTimeout = 2 * time.Minute
@ -295,9 +295,6 @@ var (
// MinimumKubeletVersion specifies the minimum version of kubelet which kubeadm supports // MinimumKubeletVersion specifies the minimum version of kubelet which kubeadm supports
MinimumKubeletVersion = version.MustParseSemantic("v1.10.0") MinimumKubeletVersion = version.MustParseSemantic("v1.10.0")
// MinimumKubeletConfigVersion specifies the minimum version of Kubernetes where kubeadm supports specifying --config to the kubelet
MinimumKubeletConfigVersion = version.MustParseSemantic("v1.11.0-alpha.1")
// SupportedEtcdVersion lists officially supported etcd versions with corresponding kubernetes releases // SupportedEtcdVersion lists officially supported etcd versions with corresponding kubernetes releases
SupportedEtcdVersion = map[uint8]string{ SupportedEtcdVersion = map[uint8]string{
10: "3.1.12", 10: "3.1.12",

View File

@ -275,7 +275,7 @@ func GetAPIServerAltNames(cfg *kubeadmapi.MasterConfiguration) (*certutil.AltNam
// create AltNames with defaults DNSNames/IPs // create AltNames with defaults DNSNames/IPs
altNames := &certutil.AltNames{ altNames := &certutil.AltNames{
DNSNames: []string{ DNSNames: []string{
cfg.NodeName, cfg.NodeRegistration.Name,
"kubernetes", "kubernetes",
"kubernetes.default", "kubernetes.default",
"kubernetes.default.svc", "kubernetes.default.svc",
@ -336,7 +336,7 @@ func GetEtcdPeerAltNames(cfg *kubeadmapi.MasterConfiguration) (*certutil.AltName
// create AltNames with defaults DNSNames/IPs // create AltNames with defaults DNSNames/IPs
altNames := &certutil.AltNames{ altNames := &certutil.AltNames{
DNSNames: []string{cfg.NodeName}, DNSNames: []string{cfg.NodeRegistration.Name},
IPs: []net.IP{advertiseAddress}, IPs: []net.IP{advertiseAddress},
} }

View File

@ -160,7 +160,7 @@ func getKubeConfigSpecs(cfg *kubeadmapi.MasterConfiguration) (map[string]*kubeCo
kubeadmconstants.KubeletKubeConfigFileName: { kubeadmconstants.KubeletKubeConfigFileName: {
CACert: caCert, CACert: caCert,
APIServer: masterEndpoint, APIServer: masterEndpoint,
ClientName: fmt.Sprintf("system:node:%s", cfg.NodeName), ClientName: fmt.Sprintf("system:node:%s", cfg.NodeRegistration.Name),
ClientCertAuth: &clientCertAuth{ ClientCertAuth: &clientCertAuth{
CAKey: caKey, CAKey: caKey,
Organizations: []string{kubeadmconstants.NodesGroup}, Organizations: []string{kubeadmconstants.NodesGroup},

View File

@ -37,12 +37,7 @@ import (
// WriteConfigToDisk writes the kubelet config object down to a file // WriteConfigToDisk writes the kubelet config object down to a file
// Used at "kubeadm init" and "kubeadm upgrade" time // Used at "kubeadm init" and "kubeadm upgrade" time
func WriteConfigToDisk(kubeletConfig *kubeletconfigv1beta1.KubeletConfiguration, kubeletVersion *version.Version) error { func WriteConfigToDisk(kubeletConfig *kubeletconfigv1beta1.KubeletConfiguration) error {
// If the kubelet version is v1.10.x, exit
if kubeletVersion.LessThan(kubeadmconstants.MinimumKubeletConfigVersion) {
return nil
}
kubeletBytes, err := getConfigBytes(kubeletConfig) kubeletBytes, err := getConfigBytes(kubeletConfig)
if err != nil { if err != nil {
@ -60,11 +55,6 @@ func CreateConfigMap(cfg *kubeadmapi.MasterConfiguration, client clientset.Inter
return err return err
} }
// If Kubernetes version is v1.10.x, exit
if k8sVersion.LessThan(kubeadmconstants.MinimumKubeletConfigVersion) {
return nil
}
configMapName := configMapName(k8sVersion) configMapName := configMapName(k8sVersion)
fmt.Printf("[kubelet] Creating a ConfigMap %q in namespace %s with the configuration for the kubelets in the cluster\n", configMapName, metav1.NamespaceSystem) fmt.Printf("[kubelet] Creating a ConfigMap %q in namespace %s with the configuration for the kubelets in the cluster\n", configMapName, metav1.NamespaceSystem)
@ -132,11 +122,6 @@ func createConfigMapRBACRules(client clientset.Interface, k8sVersion *version.Ve
// Used at "kubeadm join" time // Used at "kubeadm join" time
func DownloadConfig(kubeletKubeConfig string, kubeletVersion *version.Version) error { func DownloadConfig(kubeletKubeConfig string, kubeletVersion *version.Version) error {
// If the kubelet version is v1.10.x, exit
if kubeletVersion.LessThan(kubeadmconstants.MinimumKubeletConfigVersion) {
return nil
}
// Download the ConfigMap from the cluster based on what version the kubelet is // Download the ConfigMap from the cluster based on what version the kubelet is
configMapName := configMapName(kubeletVersion) configMapName := configMapName(kubeletVersion)

View File

@ -17,19 +17,17 @@ limitations under the License.
package kubelet package kubelet
import ( import (
"encoding/json"
"fmt" "fmt"
"os" "os"
"path/filepath" "path/filepath"
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
apierrs "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/strategicpatch"
"k8s.io/apimachinery/pkg/util/wait" "k8s.io/apimachinery/pkg/util/wait"
clientset "k8s.io/client-go/kubernetes" clientset "k8s.io/client-go/kubernetes"
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
"k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig" kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig"
"k8s.io/kubernetes/pkg/util/version" "k8s.io/kubernetes/pkg/util/version"
) )
@ -39,64 +37,33 @@ import (
// This func is ONLY run if the user enables the `DynamicKubeletConfig` feature gate, which is by default off // This func is ONLY run if the user enables the `DynamicKubeletConfig` feature gate, which is by default off
func EnableDynamicConfigForNode(client clientset.Interface, nodeName string, kubeletVersion *version.Version) error { func EnableDynamicConfigForNode(client clientset.Interface, nodeName string, kubeletVersion *version.Version) error {
// If the kubelet version is v1.10.x, exit
if kubeletVersion.LessThan(kubeadmconstants.MinimumKubeletConfigVersion) {
return nil
}
configMapName := configMapName(kubeletVersion) configMapName := configMapName(kubeletVersion)
fmt.Printf("[kubelet] Enabling Dynamic Kubelet Config for Node %q; config sourced from ConfigMap %q in namespace %s\n", fmt.Printf("[kubelet] Enabling Dynamic Kubelet Config for Node %q; config sourced from ConfigMap %q in namespace %s\n",
nodeName, configMapName, metav1.NamespaceSystem) nodeName, configMapName, metav1.NamespaceSystem)
fmt.Println("[kubelet] WARNING: The Dynamic Kubelet Config feature is alpha and off by default. It hasn't been well-tested yet at this stage, use with caution.") fmt.Println("[kubelet] WARNING: The Dynamic Kubelet Config feature is alpha and off by default. It hasn't been well-tested yet at this stage, use with caution.")
kubeletConfigMap, err := client.CoreV1().ConfigMaps(metav1.NamespaceSystem).Get(configMapName, metav1.GetOptions{})
if err != nil {
return fmt.Errorf("couldn't get the kubelet configuration ConfigMap: %v", err)
}
// Loop on every falsy return. Return with an error if raised. Exit successfully if true is returned. // Loop on every falsy return. Return with an error if raised. Exit successfully if true is returned.
return wait.Poll(kubeadmconstants.APICallRetryInterval, kubeadmconstants.UpdateNodeTimeout, func() (bool, error) { return apiclient.PatchNode(client, nodeName, func(n *v1.Node) {
node, err := client.CoreV1().Nodes().Get(nodeName, metav1.GetOptions{}) patchNodeForDynamicConfig(n, configMapName, kubeletConfigMap.UID)
if err != nil {
return false, nil
}
oldData, err := json.Marshal(node)
if err != nil {
return false, err
}
kubeletCfg, err := client.CoreV1().ConfigMaps(metav1.NamespaceSystem).Get(configMapName, metav1.GetOptions{})
if err != nil {
return false, nil
}
node.Spec.ConfigSource = &v1.NodeConfigSource{
ConfigMap: &v1.ConfigMapNodeConfigSource{
Name: configMapName,
Namespace: metav1.NamespaceSystem,
UID: kubeletCfg.UID,
KubeletConfigKey: kubeadmconstants.KubeletBaseConfigurationConfigMapKey,
},
}
newData, err := json.Marshal(node)
if err != nil {
return false, err
}
patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, v1.Node{})
if err != nil {
return false, err
}
if _, err := client.CoreV1().Nodes().Patch(node.Name, types.StrategicMergePatchType, patchBytes); err != nil {
if apierrs.IsConflict(err) {
fmt.Println("Temporarily unable to update node metadata due to conflict (will retry)")
return false, nil
}
return false, err
}
return true, nil
}) })
} }
func patchNodeForDynamicConfig(n *v1.Node, configMapName string, configMapUID types.UID) {
n.Spec.ConfigSource = &v1.NodeConfigSource{
ConfigMap: &v1.ConfigMapNodeConfigSource{
Name: configMapName,
Namespace: metav1.NamespaceSystem,
UID: configMapUID,
KubeletConfigKey: kubeadmconstants.KubeletBaseConfigurationConfigMapKey,
},
}
}
// GetLocalNodeTLSBootstrappedClient waits for the kubelet to perform the TLS bootstrap // GetLocalNodeTLSBootstrappedClient waits for the kubelet to perform the TLS bootstrap
// and then creates a client from config file /etc/kubernetes/kubelet.conf // and then creates a client from config file /etc/kubernetes/kubelet.conf
func GetLocalNodeTLSBootstrappedClient() (clientset.Interface, error) { func GetLocalNodeTLSBootstrappedClient() (clientset.Interface, error) {

View File

@ -31,10 +31,9 @@ import (
// WriteKubeletDynamicEnvFile writes a environment file with dynamic flags to the kubelet. // WriteKubeletDynamicEnvFile writes a environment file with dynamic flags to the kubelet.
// Used at "kubeadm init" and "kubeadm join" time. // Used at "kubeadm init" and "kubeadm join" time.
func WriteKubeletDynamicEnvFile(cfg *kubeadmapi.MasterConfiguration) error { func WriteKubeletDynamicEnvFile(nodeRegOpts *kubeadmapi.NodeRegistrationOptions, registerTaintsUsingFlags bool) error {
// TODO: Pass through extra arguments from the config file here in the future argList := kubeadmutil.BuildArgumentListFromMap(buildKubeletArgMap(nodeRegOpts, registerTaintsUsingFlags), nodeRegOpts.ExtraArgs)
argList := kubeadmutil.BuildArgumentListFromMap(buildKubeletArgMap(cfg), map[string]string{})
envFileContent := fmt.Sprintf("%s=%s\n", constants.KubeletEnvFileVariableName, strings.Join(argList, " ")) envFileContent := fmt.Sprintf("%s=%s\n", constants.KubeletEnvFileVariableName, strings.Join(argList, " "))
return writeKubeletFlagBytesToDisk([]byte(envFileContent)) return writeKubeletFlagBytesToDisk([]byte(envFileContent))
@ -42,20 +41,28 @@ func WriteKubeletDynamicEnvFile(cfg *kubeadmapi.MasterConfiguration) error {
// buildKubeletArgMap takes a MasterConfiguration object and builds based on that a string-string map with flags // buildKubeletArgMap takes a MasterConfiguration object and builds based on that a string-string map with flags
// that should be given to the local kubelet daemon. // that should be given to the local kubelet daemon.
func buildKubeletArgMap(cfg *kubeadmapi.MasterConfiguration) map[string]string { func buildKubeletArgMap(nodeRegOpts *kubeadmapi.NodeRegistrationOptions, registerTaintsUsingFlags bool) map[string]string {
kubeletFlags := map[string]string{} kubeletFlags := map[string]string{}
if cfg.CRISocket == kubeadmapiv1alpha2.DefaultCRISocket { if nodeRegOpts.CRISocket == kubeadmapiv1alpha2.DefaultCRISocket {
// These flags should only be set when running docker // These flags should only be set when running docker
kubeletFlags["network-plugin"] = "cni" kubeletFlags["network-plugin"] = "cni"
kubeletFlags["cni-conf-dir"] = "/etc/cni/net.d" kubeletFlags["cni-conf-dir"] = "/etc/cni/net.d"
kubeletFlags["cni-bin-dir"] = "/opt/cni/bin" kubeletFlags["cni-bin-dir"] = "/opt/cni/bin"
} else { } else {
kubeletFlags["container-runtime"] = "remote" kubeletFlags["container-runtime"] = "remote"
kubeletFlags["container-runtime-endpoint"] = cfg.CRISocket kubeletFlags["container-runtime-endpoint"] = nodeRegOpts.CRISocket
} }
// TODO: Add support for registering custom Taints and Labels
// TODO: Add support for overriding flags with ExtraArgs if registerTaintsUsingFlags && nodeRegOpts.Taints != nil && len(nodeRegOpts.Taints) > 0 {
taintStrs := []string{}
for _, taint := range nodeRegOpts.Taints {
taintStrs = append(taintStrs, taint.ToString())
}
kubeletFlags["register-with-taints"] = strings.Join(taintStrs, ",")
}
// TODO: Pass through --hostname-override if a custom name is used? // TODO: Pass through --hostname-override if a custom name is used?
// TODO: Check if `systemd-resolved` is running, and set `--resolv-conf` based on that // TODO: Check if `systemd-resolved` is running, and set `--resolv-conf` based on that
// TODO: Conditionally set `--cgroup-driver` to either `systemd` or `cgroupfs` // TODO: Conditionally set `--cgroup-driver` to either `systemd` or `cgroupfs`

View File

@ -17,107 +17,30 @@ limitations under the License.
package markmaster package markmaster
import ( import (
"encoding/json"
"fmt"
"github.com/golang/glog" "github.com/golang/glog"
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
apierrs "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/strategicpatch"
"k8s.io/apimachinery/pkg/util/wait"
clientset "k8s.io/client-go/kubernetes" clientset "k8s.io/client-go/kubernetes"
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" "k8s.io/kubernetes/cmd/kubeadm/app/constants"
kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis" "k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
) )
// MarkMaster taints the master and sets the master label // MarkMaster taints the master and sets the master label
func MarkMaster(client clientset.Interface, masterName string, taint bool) error { func MarkMaster(client clientset.Interface, masterName string, taints []v1.Taint) error {
if taint { glog.Infof("[markmaster] Marking the node %s as master by adding the label \"%s=''\"\n", masterName, constants.LabelNodeRoleMaster)
glog.Infof("[markmaster] will mark node %s as master by adding a label and a taint\n", masterName)
} else { if taints != nil && len(taints) > 0 {
glog.Infof("[markmaster] will mark node %s as master by adding a label\n", masterName) glog.Infof("[markmaster] Marking the node %s as master by adding the taints %v\n", masterName, taints)
} }
// Loop on every falsy return. Return with an error if raised. Exit successfully if true is returned. return apiclient.PatchNode(client, masterName, func(n *v1.Node) {
return wait.Poll(kubeadmconstants.APICallRetryInterval, kubeadmconstants.MarkMasterTimeout, func() (bool, error) { markMasterNode(n, taints)
// First get the node object
n, err := client.CoreV1().Nodes().Get(masterName, metav1.GetOptions{})
if err != nil {
return false, nil
}
// The node may appear to have no labels at first,
// so we wait for it to get hostname label.
if _, found := n.ObjectMeta.Labels[kubeletapis.LabelHostname]; !found {
return false, nil
}
oldData, err := json.Marshal(n)
if err != nil {
return false, err
}
// The master node should be tainted and labelled accordingly
markMasterNode(n, taint)
newData, err := json.Marshal(n)
if err != nil {
return false, err
}
patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, v1.Node{})
if err != nil {
return false, err
}
if _, err := client.CoreV1().Nodes().Patch(n.Name, types.StrategicMergePatchType, patchBytes); err != nil {
if apierrs.IsConflict(err) {
fmt.Println("[markmaster] Temporarily unable to update master node metadata due to conflict (will retry)")
return false, nil
}
return false, err
}
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, taint bool) { func markMasterNode(n *v1.Node, taints []v1.Taint) {
n.ObjectMeta.Labels[kubeadmconstants.LabelNodeRoleMaster] = "" n.ObjectMeta.Labels[constants.LabelNodeRoleMaster] = ""
if taint { // TODO: Append taints, don't override?
addTaintIfNotExists(n, kubeadmconstants.MasterTaint)
} else {
delTaintIfExists(n, kubeadmconstants.MasterTaint)
}
}
func addTaintIfNotExists(n *v1.Node, t v1.Taint) {
for _, taint := range n.Spec.Taints {
if taint == t {
return
}
}
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 n.Spec.Taints = taints
} }

View File

@ -118,7 +118,7 @@ func CreateSelfHostedControlPlane(manifestsDir, kubeConfigDir string, cfg *kubea
// Wait for the mirror Pod hash to be removed; otherwise we'll run into race conditions here when the kubelet hasn't had time to // Wait for the mirror Pod hash to be removed; otherwise we'll run into race conditions here when the kubelet hasn't had time to
// remove the Static Pod (or the mirror Pod respectively). This implicitly also tests that the API server endpoint is healthy, // remove the Static Pod (or the mirror Pod respectively). This implicitly also tests that the API server endpoint is healthy,
// because this blocks until the API server returns a 404 Not Found when getting the Static Pod // because this blocks until the API server returns a 404 Not Found when getting the Static Pod
staticPodName := fmt.Sprintf("%s-%s", componentName, cfg.NodeName) staticPodName := fmt.Sprintf("%s-%s", componentName, cfg.NodeRegistration.Name)
if err := waiter.WaitForPodToDisappear(staticPodName); err != nil { if err := waiter.WaitForPodToDisappear(staticPodName); err != nil {
return err return err
} }

View File

@ -206,7 +206,7 @@ func upgradeComponent(component string, waiter apiclient.Waiter, pathMgr StaticP
// notice the removal of the Static Pod, leading to a false positive below where we check that the API endpoint is healthy // notice the removal of the Static Pod, leading to a false positive below where we check that the API endpoint is healthy
// If we don't do this, there is a case where we remove the Static Pod manifest, kubelet is slow to react, kubeadm checks the // If we don't do this, there is a case where we remove the Static Pod manifest, kubelet is slow to react, kubeadm checks the
// API endpoint below of the OLD Static Pod component and proceeds quickly enough, which might lead to unexpected results. // API endpoint below of the OLD Static Pod component and proceeds quickly enough, which might lead to unexpected results.
if err := waiter.WaitForStaticPodHashChange(cfg.NodeName, component, beforePodHash); err != nil { if err := waiter.WaitForStaticPodHashChange(cfg.NodeRegistration.Name, component, beforePodHash); err != nil {
return rollbackOldManifests(recoverManifests, err, pathMgr, recoverEtcd) return rollbackOldManifests(recoverManifests, err, pathMgr, recoverEtcd)
} }
@ -266,7 +266,7 @@ func performEtcdStaticPodUpgrade(waiter apiclient.Waiter, pathMgr StaticPodPathM
return false, nil return false, nil
} }
beforeEtcdPodHash, err := waiter.WaitForStaticPodSingleHash(cfg.NodeName, constants.Etcd) beforeEtcdPodHash, err := waiter.WaitForStaticPodSingleHash(cfg.NodeRegistration.Name, constants.Etcd)
if err != nil { if err != nil {
return true, fmt.Errorf("failed to get etcd pod's hash: %v", err) return true, fmt.Errorf("failed to get etcd pod's hash: %v", err)
} }
@ -376,7 +376,7 @@ func StaticPodControlPlane(waiter apiclient.Waiter, pathMgr StaticPodPathManager
var isTLSUpgrade bool var isTLSUpgrade bool
var isExternalEtcd bool var isExternalEtcd bool
beforePodHashMap, err := waiter.WaitForStaticPodControlPlaneHashes(cfg.NodeName) beforePodHashMap, err := waiter.WaitForStaticPodControlPlaneHashes(cfg.NodeRegistration.Name)
if err != nil { if err != nil {
return err return err
} }

View File

@ -906,7 +906,7 @@ func RunInitMasterChecks(execer utilsexec.Interface, cfg *kubeadmapi.MasterConfi
checks = addCommonChecks(execer, cfg, checks) checks = addCommonChecks(execer, cfg, checks)
// Check ipvs required kernel module once we use ipvs kube-proxy mode // Check ipvs required kernel module once we use ipvs kube-proxy mode
if cfg.KubeProxy.Config.Mode == ipvsutil.IPVSProxyMode { if cfg.KubeProxy.Config != nil && cfg.KubeProxy.Config.Mode == ipvsutil.IPVSProxyMode {
checks = append(checks, checks = append(checks,
ipvsutil.RequiredIPVSKernelModulesAvailableCheck{Executor: execer}, ipvsutil.RequiredIPVSKernelModulesAvailableCheck{Executor: execer},
) )

View File

@ -17,6 +17,7 @@ limitations under the License.
package apiclient package apiclient
import ( import (
"encoding/json"
"fmt" "fmt"
apps "k8s.io/api/apps/v1" apps "k8s.io/api/apps/v1"
@ -24,7 +25,12 @@ import (
rbac "k8s.io/api/rbac/v1" rbac "k8s.io/api/rbac/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors" apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/strategicpatch"
"k8s.io/apimachinery/pkg/util/wait"
clientset "k8s.io/client-go/kubernetes" clientset "k8s.io/client-go/kubernetes"
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis"
) )
// TODO: We should invent a dynamic mechanism for this using the dynamic client instead of hard-coding these functions per-type // TODO: We should invent a dynamic mechanism for this using the dynamic client instead of hard-coding these functions per-type
@ -186,3 +192,49 @@ func CreateOrUpdateClusterRoleBinding(client clientset.Interface, clusterRoleBin
} }
return nil return nil
} }
// PatchNode tries to patch a node using the following client, executing patchFn for the actual mutating logic
func PatchNode(client clientset.Interface, nodeName string, patchFn func(*v1.Node)) error {
// Loop on every false return. Return with an error if raised. Exit successfully if true is returned.
return wait.Poll(constants.APICallRetryInterval, constants.PatchNodeTimeout, func() (bool, error) {
// First get the node object
n, err := client.CoreV1().Nodes().Get(nodeName, metav1.GetOptions{})
if err != nil {
return false, nil
}
// The node may appear to have no labels at first,
// so we wait for it to get hostname label.
if _, found := n.ObjectMeta.Labels[kubeletapis.LabelHostname]; !found {
return false, nil
}
oldData, err := json.Marshal(n)
if err != nil {
return false, err
}
// Execute the mutating function
patchFn(n)
newData, err := json.Marshal(n)
if err != nil {
return false, err
}
patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, v1.Node{})
if err != nil {
return false, err
}
if _, err := client.CoreV1().Nodes().Patch(n.Name, types.StrategicMergePatchType, patchBytes); err != nil {
if apierrors.IsConflict(err) {
fmt.Println("[patchnode] Temporarily unable to update node metadata due to conflict (will retry)")
return false, nil
}
return false, err
}
return true, nil
})
}

View File

@ -23,6 +23,7 @@ import (
"github.com/golang/glog" "github.com/golang/glog"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
netutil "k8s.io/apimachinery/pkg/util/net" netutil "k8s.io/apimachinery/pkg/util/net"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
@ -72,7 +73,12 @@ func SetInitDynamicDefaults(cfg *kubeadmapi.MasterConfiguration) error {
} }
} }
cfg.NodeName = node.GetHostname(cfg.NodeName) cfg.NodeRegistration.Name = node.GetHostname(cfg.NodeRegistration.Name)
// Only if the slice is nil, we should append the master taint. This allows the user to specify an empty slice for no default master taint
if cfg.NodeRegistration.Taints == nil {
cfg.NodeRegistration.Taints = []v1.Taint{kubeadmconstants.MasterTaint}
}
return nil return nil
} }

View File

@ -33,7 +33,7 @@ import (
// SetJoinDynamicDefaults checks and sets configuration values for the NodeConfiguration object // SetJoinDynamicDefaults checks and sets configuration values for the NodeConfiguration object
func SetJoinDynamicDefaults(cfg *kubeadmapi.NodeConfiguration) error { func SetJoinDynamicDefaults(cfg *kubeadmapi.NodeConfiguration) error {
cfg.NodeName = node.GetHostname(cfg.NodeName) cfg.NodeRegistration.Name = node.GetHostname(cfg.NodeRegistration.Name)
return nil return nil
} }

View File

@ -57,9 +57,10 @@ func SetupMasterConfigurationFile(t *testing.T, tmpdir string, cfg *kubeadmapi.M
kind: MasterConfiguration kind: MasterConfiguration
certificatesDir: {{.CertificatesDir}} certificatesDir: {{.CertificatesDir}}
api: api:
advertiseAddress: {{.API.AdvertiseAddress}} advertiseAddress: {{.API.AdvertiseAddress}}
bindPort: {{.API.BindPort}} bindPort: {{.API.BindPort}}
nodeName: {{.NodeName}} nodeRegistration:
name: {{.NodeRegistration.Name}}
`))) `)))
f, err := os.Create(cfgPath) f, err := os.Create(cfgPath)