kubeadm: add structured ExtraArgs in v1beta4

Add a new type Arg that holds a dedicated Name and Value.
Instead of using map[string]string for ExtraArgs in the
API use []Arg.

Adapt v1beta3 conversion to convert to/from the
legacy map[string]string.
This commit is contained in:
Lubomir I. Ivanov 2023-07-05 13:19:23 +03:00
parent b51ad13bf7
commit bc6fcb72a8
9 changed files with 279 additions and 79 deletions

View File

@ -145,11 +145,10 @@ type ClusterConfiguration struct {
// ControlPlaneComponent holds settings common to control plane component of the cluster // ControlPlaneComponent holds settings common to control plane component of the cluster
type ControlPlaneComponent struct { type ControlPlaneComponent struct {
// ExtraArgs is an extra set of flags to pass to the control plane component. // ExtraArgs is an extra set of flags to pass to the control plane component.
// A key in this map is the flag name as it appears on the // An argument name in this list is the flag name as it appears on the
// command line except without leading dash(es). // command line except without leading dash(es). Extra arguments will override existing
// TODO: This is temporary and ideally we would like to switch all components to // default arguments. Duplicate extra arguments are allowed.
// use ComponentConfig + ConfigMaps. ExtraArgs []Arg
ExtraArgs map[string]string
// ExtraVolumes is an extra set of host volumes, mounted to the control plane component. // ExtraVolumes is an extra set of host volumes, mounted to the control plane component.
ExtraVolumes []HostPathMount ExtraVolumes []HostPathMount
@ -220,9 +219,9 @@ type NodeRegistrationOptions struct {
// KubeletExtraArgs passes through extra arguments to the kubelet. The arguments here are passed to the kubelet command line via the environment file // KubeletExtraArgs 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 ConfigMap // kubeadm writes at runtime for the kubelet to source. This overrides the generic base-level configuration in the kubelet-config ConfigMap
// Flags have higher priority when parsing. These values are local and specific to the node kubeadm is executing on. // Flags have higher priority when parsing. These values are local and specific to the node kubeadm is executing on.
// A key in this map is the flag name as it appears on the // An argument name in this list is the flag name as it appears on the command line except without leading dash(es).
// command line except without leading dash(es). // Extra arguments will override existing default arguments. Duplicate extra arguments are allowed.
KubeletExtraArgs map[string]string KubeletExtraArgs []Arg
// IgnorePreflightErrors provides a slice of pre-flight errors to be ignored when the current node is registered, e.g. 'IsPrivilegedUser,Swap'. // IgnorePreflightErrors provides a slice of pre-flight errors to be ignored when the current node is registered, e.g. 'IsPrivilegedUser,Swap'.
// Value 'all' ignores errors from all checks. // Value 'all' ignores errors from all checks.
@ -267,9 +266,10 @@ type LocalEtcd struct {
// ExtraArgs are extra arguments provided to the etcd binary // ExtraArgs are extra arguments provided to the etcd binary
// when run inside a static pod. // when run inside a static pod.
// A key in this map is the flag name as it appears on the // An argument name in this list is the flag name as it appears on the
// command line except without leading dash(es). // command line except without leading dash(es). Extra arguments will override existing
ExtraArgs map[string]string // default arguments. Duplicate extra arguments are allowed.
ExtraArgs []Arg
// ExtraEnvs is an extra set of environment variables to pass to the control plane component. // ExtraEnvs is an extra set of environment variables to pass to the control plane component.
// Environment variables passed using ExtraEnvs will override any existing environment variables, or *_proxy environment variables that kubeadm adds by default. // Environment variables passed using ExtraEnvs will override any existing environment variables, or *_proxy environment variables that kubeadm adds by default.
@ -505,3 +505,9 @@ type ResetConfiguration struct {
// ComponentConfigMap is a map between a group name (as in GVK group) and a ComponentConfig // ComponentConfigMap is a map between a group name (as in GVK group) and a ComponentConfig
type ComponentConfigMap map[string]ComponentConfig type ComponentConfigMap map[string]ComponentConfig
// Arg represents an argument with a name and a value.
type Arg struct {
Name string
Value string
}

View File

@ -17,6 +17,8 @@ limitations under the License.
package v1beta3 package v1beta3
import ( import (
"sort"
v1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/conversion" "k8s.io/apimachinery/pkg/conversion"
@ -43,19 +45,65 @@ func Convert_v1beta3_InitConfiguration_To_kubeadm_InitConfiguration(in *InitConf
// Convert_v1beta3_ControlPlaneComponent_To_kubeadm_ControlPlaneComponent is required due to the missing ControlPlaneComponent.ExtraEnvs in v1beta3. // Convert_v1beta3_ControlPlaneComponent_To_kubeadm_ControlPlaneComponent is required due to the missing ControlPlaneComponent.ExtraEnvs in v1beta3.
func Convert_v1beta3_ControlPlaneComponent_To_kubeadm_ControlPlaneComponent(in *ControlPlaneComponent, out *kubeadm.ControlPlaneComponent, s conversion.Scope) error { func Convert_v1beta3_ControlPlaneComponent_To_kubeadm_ControlPlaneComponent(in *ControlPlaneComponent, out *kubeadm.ControlPlaneComponent, s conversion.Scope) error {
out.ExtraEnvs = []v1.EnvVar{} out.ExtraEnvs = []v1.EnvVar{}
out.ExtraArgs = convertToArgs(in.ExtraArgs)
return autoConvert_v1beta3_ControlPlaneComponent_To_kubeadm_ControlPlaneComponent(in, out, s) return autoConvert_v1beta3_ControlPlaneComponent_To_kubeadm_ControlPlaneComponent(in, out, s)
} }
func Convert_kubeadm_ControlPlaneComponent_To_v1beta3_ControlPlaneComponent(in *kubeadm.ControlPlaneComponent, out *ControlPlaneComponent, s conversion.Scope) error { func Convert_kubeadm_ControlPlaneComponent_To_v1beta3_ControlPlaneComponent(in *kubeadm.ControlPlaneComponent, out *ControlPlaneComponent, s conversion.Scope) error {
out.ExtraArgs = convertFromArgs(in.ExtraArgs)
return autoConvert_kubeadm_ControlPlaneComponent_To_v1beta3_ControlPlaneComponent(in, out, s) return autoConvert_kubeadm_ControlPlaneComponent_To_v1beta3_ControlPlaneComponent(in, out, s)
} }
// Convert_v1beta3_LocalEtcd_To_kubeadm_LocalEtcd is required due to the missing LocalEtcd.ExtraEnvs in v1beta3. // Convert_v1beta3_LocalEtcd_To_kubeadm_LocalEtcd is required due to the missing LocalEtcd.ExtraEnvs in v1beta3.
func Convert_v1beta3_LocalEtcd_To_kubeadm_LocalEtcd(in *LocalEtcd, out *kubeadm.LocalEtcd, s conversion.Scope) error { func Convert_v1beta3_LocalEtcd_To_kubeadm_LocalEtcd(in *LocalEtcd, out *kubeadm.LocalEtcd, s conversion.Scope) error {
out.ExtraEnvs = []v1.EnvVar{} out.ExtraEnvs = []v1.EnvVar{}
out.ExtraArgs = convertToArgs(in.ExtraArgs)
return autoConvert_v1beta3_LocalEtcd_To_kubeadm_LocalEtcd(in, out, s) return autoConvert_v1beta3_LocalEtcd_To_kubeadm_LocalEtcd(in, out, s)
} }
func Convert_kubeadm_LocalEtcd_To_v1beta3_LocalEtcd(in *kubeadm.LocalEtcd, out *LocalEtcd, s conversion.Scope) error { func Convert_kubeadm_LocalEtcd_To_v1beta3_LocalEtcd(in *kubeadm.LocalEtcd, out *LocalEtcd, s conversion.Scope) error {
out.ExtraArgs = convertFromArgs(in.ExtraArgs)
return autoConvert_kubeadm_LocalEtcd_To_v1beta3_LocalEtcd(in, out, s) return autoConvert_kubeadm_LocalEtcd_To_v1beta3_LocalEtcd(in, out, s)
} }
func Convert_v1beta3_NodeRegistrationOptions_To_kubeadm_NodeRegistrationOptions(in *NodeRegistrationOptions, out *kubeadm.NodeRegistrationOptions, s conversion.Scope) error {
out.KubeletExtraArgs = convertToArgs(in.KubeletExtraArgs)
return autoConvert_v1beta3_NodeRegistrationOptions_To_kubeadm_NodeRegistrationOptions(in, out, s)
}
func Convert_kubeadm_NodeRegistrationOptions_To_v1beta3_NodeRegistrationOptions(in *kubeadm.NodeRegistrationOptions, out *NodeRegistrationOptions, s conversion.Scope) error {
out.KubeletExtraArgs = convertFromArgs(in.KubeletExtraArgs)
return autoConvert_kubeadm_NodeRegistrationOptions_To_v1beta3_NodeRegistrationOptions(in, out, s)
}
// convertToArgs takes a argument map and converts it to a slice of arguments.
// Te resulting argument slice is sorted alpha-numerically.
func convertToArgs(in map[string]string) []kubeadm.Arg {
if in == nil {
return nil
}
args := make([]kubeadm.Arg, 0, len(in))
for k, v := range in {
args = append(args, kubeadm.Arg{Name: k, Value: v})
}
sort.Slice(args, func(i, j int) bool {
if args[i].Name == args[j].Name {
return args[i].Value < args[j].Value
}
return args[i].Name < args[j].Name
})
return args
}
// convertFromArgs takes a slice of arguments and returns an argument map.
// Duplicate argument keys will be de-duped, where later keys will take precedence.
func convertFromArgs(in []kubeadm.Arg) map[string]string {
if in == nil {
return nil
}
args := make(map[string]string, len(in))
for _, arg := range in {
args[arg.Name] = arg.Value
}
return args
}

View File

@ -0,0 +1,95 @@
/*
Copyright 2023 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 v1beta3
import (
"reflect"
"testing"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
)
func TestConvertToArgs(t *testing.T) {
var tests = []struct {
name string
args map[string]string
expectedArgs []kubeadmapi.Arg
}{
{
name: "nil map returns nil args",
args: nil,
expectedArgs: nil,
},
{
name: "valid args are parsed (sorted)",
args: map[string]string{"c": "d", "a": "b"},
expectedArgs: []kubeadmapi.Arg{
{Name: "a", Value: "b"},
{Name: "c", Value: "d"},
},
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
actual := convertToArgs(tc.args)
if !reflect.DeepEqual(tc.expectedArgs, actual) {
t.Errorf("expected args: %v\n\t got: %v\n\t", tc.expectedArgs, actual)
}
})
}
}
func TestConvertFromArgs(t *testing.T) {
var tests = []struct {
name string
args []kubeadmapi.Arg
expectedArgs map[string]string
}{
{
name: "nil args return nil map",
args: nil,
expectedArgs: nil,
},
{
name: "valid args are parsed",
args: []kubeadmapi.Arg{
{Name: "a", Value: "b"},
{Name: "c", Value: "d"},
},
expectedArgs: map[string]string{"a": "b", "c": "d"},
},
{
name: "duplicates are dropped",
args: []kubeadmapi.Arg{
{Name: "a", Value: "b"},
{Name: "c", Value: "d1"},
{Name: "c", Value: "d2"},
},
expectedArgs: map[string]string{"a": "b", "c": "d2"},
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
actual := convertFromArgs(tc.args)
if !reflect.DeepEqual(tc.expectedArgs, actual) {
t.Errorf("expected args: %v\n\t got: %v\n\t", tc.expectedArgs, actual)
}
})
}
}

View File

@ -174,16 +174,6 @@ func RegisterConversions(s *runtime.Scheme) error {
}); err != nil { }); err != nil {
return err return err
} }
if err := s.AddGeneratedConversionFunc((*NodeRegistrationOptions)(nil), (*kubeadm.NodeRegistrationOptions)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1beta3_NodeRegistrationOptions_To_kubeadm_NodeRegistrationOptions(a.(*NodeRegistrationOptions), b.(*kubeadm.NodeRegistrationOptions), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*kubeadm.NodeRegistrationOptions)(nil), (*NodeRegistrationOptions)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_kubeadm_NodeRegistrationOptions_To_v1beta3_NodeRegistrationOptions(a.(*kubeadm.NodeRegistrationOptions), b.(*NodeRegistrationOptions), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*Patches)(nil), (*kubeadm.Patches)(nil), func(a, b interface{}, scope conversion.Scope) error { if err := s.AddGeneratedConversionFunc((*Patches)(nil), (*kubeadm.Patches)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1beta3_Patches_To_kubeadm_Patches(a.(*Patches), b.(*kubeadm.Patches), scope) return Convert_v1beta3_Patches_To_kubeadm_Patches(a.(*Patches), b.(*kubeadm.Patches), scope)
}); err != nil { }); err != nil {
@ -214,6 +204,11 @@ func RegisterConversions(s *runtime.Scheme) error {
}); err != nil { }); err != nil {
return err return err
} }
if err := s.AddConversionFunc((*kubeadm.NodeRegistrationOptions)(nil), (*NodeRegistrationOptions)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_kubeadm_NodeRegistrationOptions_To_v1beta3_NodeRegistrationOptions(a.(*kubeadm.NodeRegistrationOptions), b.(*NodeRegistrationOptions), scope)
}); err != nil {
return err
}
if err := s.AddConversionFunc((*ControlPlaneComponent)(nil), (*kubeadm.ControlPlaneComponent)(nil), func(a, b interface{}, scope conversion.Scope) error { if err := s.AddConversionFunc((*ControlPlaneComponent)(nil), (*kubeadm.ControlPlaneComponent)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1beta3_ControlPlaneComponent_To_kubeadm_ControlPlaneComponent(a.(*ControlPlaneComponent), b.(*kubeadm.ControlPlaneComponent), scope) return Convert_v1beta3_ControlPlaneComponent_To_kubeadm_ControlPlaneComponent(a.(*ControlPlaneComponent), b.(*kubeadm.ControlPlaneComponent), scope)
}); err != nil { }); err != nil {
@ -229,6 +224,11 @@ func RegisterConversions(s *runtime.Scheme) error {
}); err != nil { }); err != nil {
return err return err
} }
if err := s.AddConversionFunc((*NodeRegistrationOptions)(nil), (*kubeadm.NodeRegistrationOptions)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1beta3_NodeRegistrationOptions_To_kubeadm_NodeRegistrationOptions(a.(*NodeRegistrationOptions), b.(*kubeadm.NodeRegistrationOptions), scope)
}); err != nil {
return err
}
return nil return nil
} }
@ -378,13 +378,13 @@ func Convert_kubeadm_ClusterConfiguration_To_v1beta3_ClusterConfiguration(in *ku
} }
func autoConvert_v1beta3_ControlPlaneComponent_To_kubeadm_ControlPlaneComponent(in *ControlPlaneComponent, out *kubeadm.ControlPlaneComponent, s conversion.Scope) error { func autoConvert_v1beta3_ControlPlaneComponent_To_kubeadm_ControlPlaneComponent(in *ControlPlaneComponent, out *kubeadm.ControlPlaneComponent, s conversion.Scope) error {
out.ExtraArgs = *(*map[string]string)(unsafe.Pointer(&in.ExtraArgs)) // WARNING: in.ExtraArgs requires manual conversion: inconvertible types (map[string]string vs []k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm.Arg)
out.ExtraVolumes = *(*[]kubeadm.HostPathMount)(unsafe.Pointer(&in.ExtraVolumes)) out.ExtraVolumes = *(*[]kubeadm.HostPathMount)(unsafe.Pointer(&in.ExtraVolumes))
return nil return nil
} }
func autoConvert_kubeadm_ControlPlaneComponent_To_v1beta3_ControlPlaneComponent(in *kubeadm.ControlPlaneComponent, out *ControlPlaneComponent, s conversion.Scope) error { func autoConvert_kubeadm_ControlPlaneComponent_To_v1beta3_ControlPlaneComponent(in *kubeadm.ControlPlaneComponent, out *ControlPlaneComponent, s conversion.Scope) error {
out.ExtraArgs = *(*map[string]string)(unsafe.Pointer(&in.ExtraArgs)) // WARNING: in.ExtraArgs requires manual conversion: inconvertible types ([]k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm.Arg vs map[string]string)
out.ExtraVolumes = *(*[]HostPathMount)(unsafe.Pointer(&in.ExtraVolumes)) out.ExtraVolumes = *(*[]HostPathMount)(unsafe.Pointer(&in.ExtraVolumes))
// WARNING: in.ExtraEnvs requires manual conversion: does not exist in peer-type // WARNING: in.ExtraEnvs requires manual conversion: does not exist in peer-type
return nil return nil
@ -669,7 +669,7 @@ func autoConvert_v1beta3_LocalEtcd_To_kubeadm_LocalEtcd(in *LocalEtcd, out *kube
return err return err
} }
out.DataDir = in.DataDir out.DataDir = in.DataDir
out.ExtraArgs = *(*map[string]string)(unsafe.Pointer(&in.ExtraArgs)) // WARNING: in.ExtraArgs requires manual conversion: inconvertible types (map[string]string vs []k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm.Arg)
out.ServerCertSANs = *(*[]string)(unsafe.Pointer(&in.ServerCertSANs)) out.ServerCertSANs = *(*[]string)(unsafe.Pointer(&in.ServerCertSANs))
out.PeerCertSANs = *(*[]string)(unsafe.Pointer(&in.PeerCertSANs)) out.PeerCertSANs = *(*[]string)(unsafe.Pointer(&in.PeerCertSANs))
return nil return nil
@ -680,7 +680,7 @@ func autoConvert_kubeadm_LocalEtcd_To_v1beta3_LocalEtcd(in *kubeadm.LocalEtcd, o
return err return err
} }
out.DataDir = in.DataDir out.DataDir = in.DataDir
out.ExtraArgs = *(*map[string]string)(unsafe.Pointer(&in.ExtraArgs)) // WARNING: in.ExtraArgs requires manual conversion: inconvertible types ([]k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm.Arg vs map[string]string)
// WARNING: in.ExtraEnvs requires manual conversion: does not exist in peer-type // WARNING: in.ExtraEnvs requires manual conversion: does not exist in peer-type
out.ServerCertSANs = *(*[]string)(unsafe.Pointer(&in.ServerCertSANs)) out.ServerCertSANs = *(*[]string)(unsafe.Pointer(&in.ServerCertSANs))
out.PeerCertSANs = *(*[]string)(unsafe.Pointer(&in.PeerCertSANs)) out.PeerCertSANs = *(*[]string)(unsafe.Pointer(&in.PeerCertSANs))
@ -715,32 +715,22 @@ func autoConvert_v1beta3_NodeRegistrationOptions_To_kubeadm_NodeRegistrationOpti
out.Name = in.Name out.Name = in.Name
out.CRISocket = in.CRISocket out.CRISocket = in.CRISocket
out.Taints = *(*[]corev1.Taint)(unsafe.Pointer(&in.Taints)) out.Taints = *(*[]corev1.Taint)(unsafe.Pointer(&in.Taints))
out.KubeletExtraArgs = *(*map[string]string)(unsafe.Pointer(&in.KubeletExtraArgs)) // WARNING: in.KubeletExtraArgs requires manual conversion: inconvertible types (map[string]string vs []k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm.Arg)
out.IgnorePreflightErrors = *(*[]string)(unsafe.Pointer(&in.IgnorePreflightErrors)) out.IgnorePreflightErrors = *(*[]string)(unsafe.Pointer(&in.IgnorePreflightErrors))
out.ImagePullPolicy = corev1.PullPolicy(in.ImagePullPolicy) out.ImagePullPolicy = corev1.PullPolicy(in.ImagePullPolicy)
return nil return nil
} }
// Convert_v1beta3_NodeRegistrationOptions_To_kubeadm_NodeRegistrationOptions is an autogenerated conversion function.
func Convert_v1beta3_NodeRegistrationOptions_To_kubeadm_NodeRegistrationOptions(in *NodeRegistrationOptions, out *kubeadm.NodeRegistrationOptions, s conversion.Scope) error {
return autoConvert_v1beta3_NodeRegistrationOptions_To_kubeadm_NodeRegistrationOptions(in, out, s)
}
func autoConvert_kubeadm_NodeRegistrationOptions_To_v1beta3_NodeRegistrationOptions(in *kubeadm.NodeRegistrationOptions, out *NodeRegistrationOptions, s conversion.Scope) error { func autoConvert_kubeadm_NodeRegistrationOptions_To_v1beta3_NodeRegistrationOptions(in *kubeadm.NodeRegistrationOptions, out *NodeRegistrationOptions, s conversion.Scope) error {
out.Name = in.Name out.Name = in.Name
out.CRISocket = in.CRISocket out.CRISocket = in.CRISocket
out.Taints = *(*[]corev1.Taint)(unsafe.Pointer(&in.Taints)) out.Taints = *(*[]corev1.Taint)(unsafe.Pointer(&in.Taints))
out.KubeletExtraArgs = *(*map[string]string)(unsafe.Pointer(&in.KubeletExtraArgs)) // WARNING: in.KubeletExtraArgs requires manual conversion: inconvertible types ([]k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm.Arg vs map[string]string)
out.IgnorePreflightErrors = *(*[]string)(unsafe.Pointer(&in.IgnorePreflightErrors)) out.IgnorePreflightErrors = *(*[]string)(unsafe.Pointer(&in.IgnorePreflightErrors))
out.ImagePullPolicy = corev1.PullPolicy(in.ImagePullPolicy) out.ImagePullPolicy = corev1.PullPolicy(in.ImagePullPolicy)
return nil return nil
} }
// Convert_kubeadm_NodeRegistrationOptions_To_v1beta3_NodeRegistrationOptions is an autogenerated conversion function.
func Convert_kubeadm_NodeRegistrationOptions_To_v1beta3_NodeRegistrationOptions(in *kubeadm.NodeRegistrationOptions, out *NodeRegistrationOptions, s conversion.Scope) error {
return autoConvert_kubeadm_NodeRegistrationOptions_To_v1beta3_NodeRegistrationOptions(in, out, s)
}
func autoConvert_v1beta3_Patches_To_kubeadm_Patches(in *Patches, out *kubeadm.Patches, s conversion.Scope) error { func autoConvert_v1beta3_Patches_To_kubeadm_Patches(in *Patches, out *kubeadm.Patches, s conversion.Scope) error {
out.Directory = in.Directory out.Directory = in.Directory
return nil return nil

View File

@ -26,9 +26,12 @@ limitations under the License.
// //
// - TODO https://github.com/kubernetes/kubeadm/issues/2890 // - TODO https://github.com/kubernetes/kubeadm/issues/2890
// - Support custom environment variables in control plane components under `ClusterConfiguration`. // - Support custom environment variables in control plane components under `ClusterConfiguration`.
// Use `APIServer.ExtraEnvs`, `ControllerManager.ExtraEnvs`, `Scheduler.ExtraEnvs`, `Etcd.Local.ExtraEnvs`. // Use `APIServer.ExtraEnvs`, `ControllerManager.ExtraEnvs`, `Scheduler.ExtraEnvs`, `Etcd.Local.ExtraEnvs`.
// - The ResetConfiguration API type is now supported in v1beta4. Users are able to reset a node by passing a --config file to "kubeadm reset". // - The ResetConfiguration API type is now supported in v1beta4. Users are able to reset a node by passing a --config file to "kubeadm reset".
// - `dry-run` mode in is now configurable in InitConfiguration and JoinConfiguration config files. // - `dry-run` mode in is now configurable in InitConfiguration and JoinConfiguration config files.
// - Replace the existing string/string extra argument maps with structured extra arguments that support duplicates.
// The change applies to `ClusterConfiguration` - `APIServer.ExtraArgs, `ControllerManager.ExtraArgs`,
// `Scheduler.ExtraArgs`, `Etcd.Local.ExtraArgs`. Also to `NodeRegistrationOptions.KubeletExtraArgs`.
// //
// Migration from old kubeadm config versions // Migration from old kubeadm config versions
// //

View File

@ -144,12 +144,11 @@ type ClusterConfiguration struct {
// ControlPlaneComponent holds settings common to control plane component of the cluster // ControlPlaneComponent holds settings common to control plane component of the cluster
type ControlPlaneComponent struct { type ControlPlaneComponent struct {
// ExtraArgs is an extra set of flags to pass to the control plane component. // ExtraArgs is an extra set of flags to pass to the control plane component.
// A key in this map is the flag name as it appears on the // An argument name in this list is the flag name as it appears on the
// command line except without leading dash(es). // command line except without leading dash(es). Extra arguments will override existing
// TODO: This is temporary and ideally we would like to switch all components to // default arguments. Duplicate extra arguments are allowed.
// use ComponentConfig + ConfigMaps.
// +optional // +optional
ExtraArgs map[string]string `json:"extraArgs,omitempty"` ExtraArgs []Arg `json:"extraArgs,omitempty"`
// ExtraVolumes is an extra set of host volumes, mounted to the control plane component. // ExtraVolumes is an extra set of host volumes, mounted to the control plane component.
// +optional // +optional
@ -232,10 +231,10 @@ type NodeRegistrationOptions struct {
// KubeletExtraArgs passes through extra arguments to the kubelet. The arguments here are passed to the kubelet command line via the environment file // KubeletExtraArgs 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 ConfigMap // kubeadm writes at runtime for the kubelet to source. This overrides the generic base-level configuration in the kubelet-config ConfigMap
// Flags have higher priority when parsing. These values are local and specific to the node kubeadm is executing on. // Flags have higher priority when parsing. These values are local and specific to the node kubeadm is executing on.
// A key in this map is the flag name as it appears on the // An argument name in this list is the flag name as it appears on the command line except without leading dash(es).
// command line except without leading dash(es). // Extra arguments will override existing default arguments. Duplicate extra arguments are allowed.
// +optional // +optional
KubeletExtraArgs map[string]string `json:"kubeletExtraArgs,omitempty"` KubeletExtraArgs []Arg `json:"kubeletExtraArgs,omitempty"`
// IgnorePreflightErrors provides a slice of pre-flight errors to be ignored when the current node is registered, e.g. 'IsPrivilegedUser,Swap'. // IgnorePreflightErrors provides a slice of pre-flight errors to be ignored when the current node is registered, e.g. 'IsPrivilegedUser,Swap'.
// Value 'all' ignores errors from all checks. // Value 'all' ignores errors from all checks.
@ -287,10 +286,11 @@ type LocalEtcd struct {
// ExtraArgs are extra arguments provided to the etcd binary // ExtraArgs are extra arguments provided to the etcd binary
// when run inside a static pod. // when run inside a static pod.
// A key in this map is the flag name as it appears on the // An argument name in this list is the flag name as it appears on the
// command line except without leading dash(es). // command line except without leading dash(es). Extra arguments will override existing
// default arguments. Duplicate extra arguments are allowed.
// +optional // +optional
ExtraArgs map[string]string `json:"extraArgs,omitempty"` ExtraArgs []Arg `json:"extraArgs,omitempty"`
// ExtraEnvs is an extra set of environment variables to pass to the control plane component. // ExtraEnvs is an extra set of environment variables to pass to the control plane component.
// Environment variables passed using ExtraEnvs will override any existing environment variables, or *_proxy environment variables that kubeadm adds by default. // Environment variables passed using ExtraEnvs will override any existing environment variables, or *_proxy environment variables that kubeadm adds by default.
@ -500,3 +500,9 @@ type ResetConfiguration struct {
// +optional // +optional
SkipPhases []string `json:"skipPhases,omitempty"` SkipPhases []string `json:"skipPhases,omitempty"`
} }
// Arg represents an argument with a name and a value.
type Arg struct {
Name string `json:"name"`
Value string `json:"value"`
}

View File

@ -59,6 +59,16 @@ func RegisterConversions(s *runtime.Scheme) error {
}); err != nil { }); err != nil {
return err return err
} }
if err := s.AddGeneratedConversionFunc((*Arg)(nil), (*kubeadm.Arg)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1beta4_Arg_To_kubeadm_Arg(a.(*Arg), b.(*kubeadm.Arg), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*kubeadm.Arg)(nil), (*Arg)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_kubeadm_Arg_To_v1beta4_Arg(a.(*kubeadm.Arg), b.(*Arg), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*BootstrapTokenDiscovery)(nil), (*kubeadm.BootstrapTokenDiscovery)(nil), func(a, b interface{}, scope conversion.Scope) error { if err := s.AddGeneratedConversionFunc((*BootstrapTokenDiscovery)(nil), (*kubeadm.BootstrapTokenDiscovery)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1beta4_BootstrapTokenDiscovery_To_kubeadm_BootstrapTokenDiscovery(a.(*BootstrapTokenDiscovery), b.(*kubeadm.BootstrapTokenDiscovery), scope) return Convert_v1beta4_BootstrapTokenDiscovery_To_kubeadm_BootstrapTokenDiscovery(a.(*BootstrapTokenDiscovery), b.(*kubeadm.BootstrapTokenDiscovery), scope)
}); err != nil { }); err != nil {
@ -292,6 +302,28 @@ func Convert_kubeadm_APIServer_To_v1beta4_APIServer(in *kubeadm.APIServer, out *
return autoConvert_kubeadm_APIServer_To_v1beta4_APIServer(in, out, s) return autoConvert_kubeadm_APIServer_To_v1beta4_APIServer(in, out, s)
} }
func autoConvert_v1beta4_Arg_To_kubeadm_Arg(in *Arg, out *kubeadm.Arg, s conversion.Scope) error {
out.Name = in.Name
out.Value = in.Value
return nil
}
// Convert_v1beta4_Arg_To_kubeadm_Arg is an autogenerated conversion function.
func Convert_v1beta4_Arg_To_kubeadm_Arg(in *Arg, out *kubeadm.Arg, s conversion.Scope) error {
return autoConvert_v1beta4_Arg_To_kubeadm_Arg(in, out, s)
}
func autoConvert_kubeadm_Arg_To_v1beta4_Arg(in *kubeadm.Arg, out *Arg, s conversion.Scope) error {
out.Name = in.Name
out.Value = in.Value
return nil
}
// Convert_kubeadm_Arg_To_v1beta4_Arg is an autogenerated conversion function.
func Convert_kubeadm_Arg_To_v1beta4_Arg(in *kubeadm.Arg, out *Arg, s conversion.Scope) error {
return autoConvert_kubeadm_Arg_To_v1beta4_Arg(in, out, s)
}
func autoConvert_v1beta4_BootstrapTokenDiscovery_To_kubeadm_BootstrapTokenDiscovery(in *BootstrapTokenDiscovery, out *kubeadm.BootstrapTokenDiscovery, s conversion.Scope) error { func autoConvert_v1beta4_BootstrapTokenDiscovery_To_kubeadm_BootstrapTokenDiscovery(in *BootstrapTokenDiscovery, out *kubeadm.BootstrapTokenDiscovery, s conversion.Scope) error {
out.Token = in.Token out.Token = in.Token
out.APIServerEndpoint = in.APIServerEndpoint out.APIServerEndpoint = in.APIServerEndpoint
@ -388,7 +420,7 @@ func Convert_kubeadm_ClusterConfiguration_To_v1beta4_ClusterConfiguration(in *ku
} }
func autoConvert_v1beta4_ControlPlaneComponent_To_kubeadm_ControlPlaneComponent(in *ControlPlaneComponent, out *kubeadm.ControlPlaneComponent, s conversion.Scope) error { func autoConvert_v1beta4_ControlPlaneComponent_To_kubeadm_ControlPlaneComponent(in *ControlPlaneComponent, out *kubeadm.ControlPlaneComponent, s conversion.Scope) error {
out.ExtraArgs = *(*map[string]string)(unsafe.Pointer(&in.ExtraArgs)) out.ExtraArgs = *(*[]kubeadm.Arg)(unsafe.Pointer(&in.ExtraArgs))
out.ExtraVolumes = *(*[]kubeadm.HostPathMount)(unsafe.Pointer(&in.ExtraVolumes)) out.ExtraVolumes = *(*[]kubeadm.HostPathMount)(unsafe.Pointer(&in.ExtraVolumes))
out.ExtraEnvs = *(*[]corev1.EnvVar)(unsafe.Pointer(&in.ExtraEnvs)) out.ExtraEnvs = *(*[]corev1.EnvVar)(unsafe.Pointer(&in.ExtraEnvs))
return nil return nil
@ -400,7 +432,7 @@ func Convert_v1beta4_ControlPlaneComponent_To_kubeadm_ControlPlaneComponent(in *
} }
func autoConvert_kubeadm_ControlPlaneComponent_To_v1beta4_ControlPlaneComponent(in *kubeadm.ControlPlaneComponent, out *ControlPlaneComponent, s conversion.Scope) error { func autoConvert_kubeadm_ControlPlaneComponent_To_v1beta4_ControlPlaneComponent(in *kubeadm.ControlPlaneComponent, out *ControlPlaneComponent, s conversion.Scope) error {
out.ExtraArgs = *(*map[string]string)(unsafe.Pointer(&in.ExtraArgs)) out.ExtraArgs = *(*[]Arg)(unsafe.Pointer(&in.ExtraArgs))
out.ExtraVolumes = *(*[]HostPathMount)(unsafe.Pointer(&in.ExtraVolumes)) out.ExtraVolumes = *(*[]HostPathMount)(unsafe.Pointer(&in.ExtraVolumes))
out.ExtraEnvs = *(*[]corev1.EnvVar)(unsafe.Pointer(&in.ExtraEnvs)) out.ExtraEnvs = *(*[]corev1.EnvVar)(unsafe.Pointer(&in.ExtraEnvs))
return nil return nil
@ -681,7 +713,7 @@ func autoConvert_v1beta4_LocalEtcd_To_kubeadm_LocalEtcd(in *LocalEtcd, out *kube
return err return err
} }
out.DataDir = in.DataDir out.DataDir = in.DataDir
out.ExtraArgs = *(*map[string]string)(unsafe.Pointer(&in.ExtraArgs)) out.ExtraArgs = *(*[]kubeadm.Arg)(unsafe.Pointer(&in.ExtraArgs))
out.ExtraEnvs = *(*[]corev1.EnvVar)(unsafe.Pointer(&in.ExtraEnvs)) out.ExtraEnvs = *(*[]corev1.EnvVar)(unsafe.Pointer(&in.ExtraEnvs))
out.ServerCertSANs = *(*[]string)(unsafe.Pointer(&in.ServerCertSANs)) out.ServerCertSANs = *(*[]string)(unsafe.Pointer(&in.ServerCertSANs))
out.PeerCertSANs = *(*[]string)(unsafe.Pointer(&in.PeerCertSANs)) out.PeerCertSANs = *(*[]string)(unsafe.Pointer(&in.PeerCertSANs))
@ -698,7 +730,7 @@ func autoConvert_kubeadm_LocalEtcd_To_v1beta4_LocalEtcd(in *kubeadm.LocalEtcd, o
return err return err
} }
out.DataDir = in.DataDir out.DataDir = in.DataDir
out.ExtraArgs = *(*map[string]string)(unsafe.Pointer(&in.ExtraArgs)) out.ExtraArgs = *(*[]Arg)(unsafe.Pointer(&in.ExtraArgs))
out.ExtraEnvs = *(*[]corev1.EnvVar)(unsafe.Pointer(&in.ExtraEnvs)) out.ExtraEnvs = *(*[]corev1.EnvVar)(unsafe.Pointer(&in.ExtraEnvs))
out.ServerCertSANs = *(*[]string)(unsafe.Pointer(&in.ServerCertSANs)) out.ServerCertSANs = *(*[]string)(unsafe.Pointer(&in.ServerCertSANs))
out.PeerCertSANs = *(*[]string)(unsafe.Pointer(&in.PeerCertSANs)) out.PeerCertSANs = *(*[]string)(unsafe.Pointer(&in.PeerCertSANs))
@ -738,7 +770,7 @@ func autoConvert_v1beta4_NodeRegistrationOptions_To_kubeadm_NodeRegistrationOpti
out.Name = in.Name out.Name = in.Name
out.CRISocket = in.CRISocket out.CRISocket = in.CRISocket
out.Taints = *(*[]corev1.Taint)(unsafe.Pointer(&in.Taints)) out.Taints = *(*[]corev1.Taint)(unsafe.Pointer(&in.Taints))
out.KubeletExtraArgs = *(*map[string]string)(unsafe.Pointer(&in.KubeletExtraArgs)) out.KubeletExtraArgs = *(*[]kubeadm.Arg)(unsafe.Pointer(&in.KubeletExtraArgs))
out.IgnorePreflightErrors = *(*[]string)(unsafe.Pointer(&in.IgnorePreflightErrors)) out.IgnorePreflightErrors = *(*[]string)(unsafe.Pointer(&in.IgnorePreflightErrors))
out.ImagePullPolicy = corev1.PullPolicy(in.ImagePullPolicy) out.ImagePullPolicy = corev1.PullPolicy(in.ImagePullPolicy)
return nil return nil
@ -753,7 +785,7 @@ func autoConvert_kubeadm_NodeRegistrationOptions_To_v1beta4_NodeRegistrationOpti
out.Name = in.Name out.Name = in.Name
out.CRISocket = in.CRISocket out.CRISocket = in.CRISocket
out.Taints = *(*[]corev1.Taint)(unsafe.Pointer(&in.Taints)) out.Taints = *(*[]corev1.Taint)(unsafe.Pointer(&in.Taints))
out.KubeletExtraArgs = *(*map[string]string)(unsafe.Pointer(&in.KubeletExtraArgs)) out.KubeletExtraArgs = *(*[]Arg)(unsafe.Pointer(&in.KubeletExtraArgs))
out.IgnorePreflightErrors = *(*[]string)(unsafe.Pointer(&in.IgnorePreflightErrors)) out.IgnorePreflightErrors = *(*[]string)(unsafe.Pointer(&in.IgnorePreflightErrors))
out.ImagePullPolicy = corev1.PullPolicy(in.ImagePullPolicy) out.ImagePullPolicy = corev1.PullPolicy(in.ImagePullPolicy)
return nil return nil

View File

@ -71,6 +71,22 @@ func (in *APIServer) DeepCopy() *APIServer {
return out return out
} }
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Arg) DeepCopyInto(out *Arg) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Arg.
func (in *Arg) DeepCopy() *Arg {
if in == nil {
return nil
}
out := new(Arg)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *BootstrapTokenDiscovery) DeepCopyInto(out *BootstrapTokenDiscovery) { func (in *BootstrapTokenDiscovery) DeepCopyInto(out *BootstrapTokenDiscovery) {
*out = *in *out = *in
@ -135,10 +151,8 @@ func (in *ControlPlaneComponent) DeepCopyInto(out *ControlPlaneComponent) {
*out = *in *out = *in
if in.ExtraArgs != nil { if in.ExtraArgs != nil {
in, out := &in.ExtraArgs, &out.ExtraArgs in, out := &in.ExtraArgs, &out.ExtraArgs
*out = make(map[string]string, len(*in)) *out = make([]Arg, len(*in))
for key, val := range *in { copy(*out, *in)
(*out)[key] = val
}
} }
if in.ExtraVolumes != nil { if in.ExtraVolumes != nil {
in, out := &in.ExtraVolumes, &out.ExtraVolumes in, out := &in.ExtraVolumes, &out.ExtraVolumes
@ -417,10 +431,8 @@ func (in *LocalEtcd) DeepCopyInto(out *LocalEtcd) {
out.ImageMeta = in.ImageMeta out.ImageMeta = in.ImageMeta
if in.ExtraArgs != nil { if in.ExtraArgs != nil {
in, out := &in.ExtraArgs, &out.ExtraArgs in, out := &in.ExtraArgs, &out.ExtraArgs
*out = make(map[string]string, len(*in)) *out = make([]Arg, len(*in))
for key, val := range *in { copy(*out, *in)
(*out)[key] = val
}
} }
if in.ExtraEnvs != nil { if in.ExtraEnvs != nil {
in, out := &in.ExtraEnvs, &out.ExtraEnvs in, out := &in.ExtraEnvs, &out.ExtraEnvs
@ -480,10 +492,8 @@ func (in *NodeRegistrationOptions) DeepCopyInto(out *NodeRegistrationOptions) {
} }
if in.KubeletExtraArgs != nil { if in.KubeletExtraArgs != nil {
in, out := &in.KubeletExtraArgs, &out.KubeletExtraArgs in, out := &in.KubeletExtraArgs, &out.KubeletExtraArgs
*out = make(map[string]string, len(*in)) *out = make([]Arg, len(*in))
for key, val := range *in { copy(*out, *in)
(*out)[key] = val
}
} }
if in.IgnorePreflightErrors != nil { if in.IgnorePreflightErrors != nil {
in, out := &in.IgnorePreflightErrors, &out.IgnorePreflightErrors in, out := &in.IgnorePreflightErrors, &out.IgnorePreflightErrors

View File

@ -71,6 +71,22 @@ func (in *APIServer) DeepCopy() *APIServer {
return out return out
} }
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Arg) DeepCopyInto(out *Arg) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Arg.
func (in *Arg) DeepCopy() *Arg {
if in == nil {
return nil
}
out := new(Arg)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *BootstrapTokenDiscovery) DeepCopyInto(out *BootstrapTokenDiscovery) { func (in *BootstrapTokenDiscovery) DeepCopyInto(out *BootstrapTokenDiscovery) {
*out = *in *out = *in
@ -164,10 +180,8 @@ func (in *ControlPlaneComponent) DeepCopyInto(out *ControlPlaneComponent) {
*out = *in *out = *in
if in.ExtraArgs != nil { if in.ExtraArgs != nil {
in, out := &in.ExtraArgs, &out.ExtraArgs in, out := &in.ExtraArgs, &out.ExtraArgs
*out = make(map[string]string, len(*in)) *out = make([]Arg, len(*in))
for key, val := range *in { copy(*out, *in)
(*out)[key] = val
}
} }
if in.ExtraVolumes != nil { if in.ExtraVolumes != nil {
in, out := &in.ExtraVolumes, &out.ExtraVolumes in, out := &in.ExtraVolumes, &out.ExtraVolumes
@ -447,10 +461,8 @@ func (in *LocalEtcd) DeepCopyInto(out *LocalEtcd) {
out.ImageMeta = in.ImageMeta out.ImageMeta = in.ImageMeta
if in.ExtraArgs != nil { if in.ExtraArgs != nil {
in, out := &in.ExtraArgs, &out.ExtraArgs in, out := &in.ExtraArgs, &out.ExtraArgs
*out = make(map[string]string, len(*in)) *out = make([]Arg, len(*in))
for key, val := range *in { copy(*out, *in)
(*out)[key] = val
}
} }
if in.ExtraEnvs != nil { if in.ExtraEnvs != nil {
in, out := &in.ExtraEnvs, &out.ExtraEnvs in, out := &in.ExtraEnvs, &out.ExtraEnvs
@ -510,10 +522,8 @@ func (in *NodeRegistrationOptions) DeepCopyInto(out *NodeRegistrationOptions) {
} }
if in.KubeletExtraArgs != nil { if in.KubeletExtraArgs != nil {
in, out := &in.KubeletExtraArgs, &out.KubeletExtraArgs in, out := &in.KubeletExtraArgs, &out.KubeletExtraArgs
*out = make(map[string]string, len(*in)) *out = make([]Arg, len(*in))
for key, val := range *in { copy(*out, *in)
(*out)[key] = val
}
} }
if in.IgnorePreflightErrors != nil { if in.IgnorePreflightErrors != nil {
in, out := &in.IgnorePreflightErrors, &out.IgnorePreflightErrors in, out := &in.IgnorePreflightErrors, &out.IgnorePreflightErrors