mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-04 12:18:16 +00:00 
			
		
		
		
	Merge pull request #119156 from neolit123/1.28-add-support-for-dup-extraargs
kubeadm add support for structured ExtraArgs
This commit is contained in:
		
							
								
								
									
										63
									
								
								cmd/kubeadm/app/apis/kubeadm/argument.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								cmd/kubeadm/app/apis/kubeadm/argument.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,63 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					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 kubeadm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GetArgValue traverses an argument slice backwards and returns the value
 | 
				
			||||||
 | 
					// of the given argument name and the index where it was found.
 | 
				
			||||||
 | 
					// If the argument does not exist an empty string and -1 are returned.
 | 
				
			||||||
 | 
					// startIdx defines where the iteration starts. If startIdx is a negative
 | 
				
			||||||
 | 
					// value or larger than the size of the argument slice the iteration
 | 
				
			||||||
 | 
					// will start from the last element.
 | 
				
			||||||
 | 
					func GetArgValue(args []Arg, name string, startIdx int) (string, int) {
 | 
				
			||||||
 | 
						if startIdx < 0 || startIdx > len(args)-1 {
 | 
				
			||||||
 | 
							startIdx = len(args) - 1
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for i := startIdx; i >= 0; i-- {
 | 
				
			||||||
 | 
							arg := args[i]
 | 
				
			||||||
 | 
							if arg.Name == name {
 | 
				
			||||||
 | 
								return arg.Value, i
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return "", -1
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SetArgValues updates the value of one or more arguments or adds a new
 | 
				
			||||||
 | 
					// one if missing. The function works backwards in the argument list.
 | 
				
			||||||
 | 
					// nArgs holds how many existing arguments with this name should be set.
 | 
				
			||||||
 | 
					// If nArgs is less than 1, all of them will be updated.
 | 
				
			||||||
 | 
					func SetArgValues(args []Arg, name, value string, nArgs int) []Arg {
 | 
				
			||||||
 | 
						var count int
 | 
				
			||||||
 | 
						var found bool
 | 
				
			||||||
 | 
						for i := len(args) - 1; i >= 0; i-- {
 | 
				
			||||||
 | 
							if args[i].Name == name {
 | 
				
			||||||
 | 
								found = true
 | 
				
			||||||
 | 
								args[i].Value = value
 | 
				
			||||||
 | 
								if nArgs < 1 {
 | 
				
			||||||
 | 
									continue
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								count++
 | 
				
			||||||
 | 
								if count >= nArgs {
 | 
				
			||||||
 | 
									return args
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if found {
 | 
				
			||||||
 | 
							return args
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						args = append(args, Arg{Name: name, Value: value})
 | 
				
			||||||
 | 
						return args
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										123
									
								
								cmd/kubeadm/app/apis/kubeadm/argument_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								cmd/kubeadm/app/apis/kubeadm/argument_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,123 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					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 kubeadm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"reflect"
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestGetArgValue(t *testing.T) {
 | 
				
			||||||
 | 
						var tests = []struct {
 | 
				
			||||||
 | 
							testName      string
 | 
				
			||||||
 | 
							args          []Arg
 | 
				
			||||||
 | 
							name          string
 | 
				
			||||||
 | 
							expectedValue string
 | 
				
			||||||
 | 
							startIdx      int
 | 
				
			||||||
 | 
							expectedIdx   int
 | 
				
			||||||
 | 
						}{
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								testName:      "argument exists with non-empty value",
 | 
				
			||||||
 | 
								args:          []Arg{{Name: "a", Value: "a1"}, {Name: "b", Value: "b1"}, {Name: "c", Value: "c1"}},
 | 
				
			||||||
 | 
								name:          "b",
 | 
				
			||||||
 | 
								expectedValue: "b1",
 | 
				
			||||||
 | 
								expectedIdx:   1,
 | 
				
			||||||
 | 
								startIdx:      -1,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								testName:      "argument exists with non-empty value (offset index)",
 | 
				
			||||||
 | 
								args:          []Arg{{Name: "a", Value: "a1"}, {Name: "b", Value: "b1"}, {Name: "c", Value: "c1"}},
 | 
				
			||||||
 | 
								name:          "a",
 | 
				
			||||||
 | 
								expectedValue: "a1",
 | 
				
			||||||
 | 
								expectedIdx:   0,
 | 
				
			||||||
 | 
								startIdx:      0,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								testName:      "argument exists with empty value",
 | 
				
			||||||
 | 
								args:          []Arg{{Name: "foo1", Value: ""}, {Name: "foo2", Value: ""}},
 | 
				
			||||||
 | 
								name:          "foo2",
 | 
				
			||||||
 | 
								expectedValue: "",
 | 
				
			||||||
 | 
								expectedIdx:   1,
 | 
				
			||||||
 | 
								startIdx:      -1,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								testName:      "argument does not exists",
 | 
				
			||||||
 | 
								args:          []Arg{{Name: "foo", Value: "bar"}},
 | 
				
			||||||
 | 
								name:          "z",
 | 
				
			||||||
 | 
								expectedValue: "",
 | 
				
			||||||
 | 
								expectedIdx:   -1,
 | 
				
			||||||
 | 
								startIdx:      -1,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, rt := range tests {
 | 
				
			||||||
 | 
							t.Run(rt.testName, func(t *testing.T) {
 | 
				
			||||||
 | 
								value, idx := GetArgValue(rt.args, rt.name, rt.startIdx)
 | 
				
			||||||
 | 
								if idx != rt.expectedIdx {
 | 
				
			||||||
 | 
									t.Errorf("expected index: %v, got: %v", rt.expectedIdx, idx)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if value != rt.expectedValue {
 | 
				
			||||||
 | 
									t.Errorf("expected value: %s, got: %s", rt.expectedValue, value)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestSetArgValues(t *testing.T) {
 | 
				
			||||||
 | 
						var tests = []struct {
 | 
				
			||||||
 | 
							testName     string
 | 
				
			||||||
 | 
							args         []Arg
 | 
				
			||||||
 | 
							name         string
 | 
				
			||||||
 | 
							value        string
 | 
				
			||||||
 | 
							nArgs        int
 | 
				
			||||||
 | 
							expectedArgs []Arg
 | 
				
			||||||
 | 
						}{
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								testName:     "update 1 argument",
 | 
				
			||||||
 | 
								args:         []Arg{{Name: "foo", Value: "bar1"}, {Name: "foo", Value: "bar2"}},
 | 
				
			||||||
 | 
								name:         "foo",
 | 
				
			||||||
 | 
								value:        "zz",
 | 
				
			||||||
 | 
								nArgs:        1,
 | 
				
			||||||
 | 
								expectedArgs: []Arg{{Name: "foo", Value: "bar1"}, {Name: "foo", Value: "zz"}},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								testName:     "update all arguments",
 | 
				
			||||||
 | 
								args:         []Arg{{Name: "foo", Value: "bar1"}, {Name: "foo", Value: "bar2"}},
 | 
				
			||||||
 | 
								name:         "foo",
 | 
				
			||||||
 | 
								value:        "zz",
 | 
				
			||||||
 | 
								nArgs:        -1,
 | 
				
			||||||
 | 
								expectedArgs: []Arg{{Name: "foo", Value: "zz"}, {Name: "foo", Value: "zz"}},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								testName:     "add new argument",
 | 
				
			||||||
 | 
								args:         []Arg{{Name: "foo", Value: "bar1"}, {Name: "foo", Value: "bar2"}},
 | 
				
			||||||
 | 
								name:         "z",
 | 
				
			||||||
 | 
								value:        "zz",
 | 
				
			||||||
 | 
								nArgs:        -1,
 | 
				
			||||||
 | 
								expectedArgs: []Arg{{Name: "foo", Value: "bar1"}, {Name: "foo", Value: "bar2"}, {Name: "z", Value: "zz"}},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, rt := range tests {
 | 
				
			||||||
 | 
							t.Run(rt.testName, func(t *testing.T) {
 | 
				
			||||||
 | 
								args := SetArgValues(rt.args, rt.name, rt.value, rt.nArgs)
 | 
				
			||||||
 | 
								if !reflect.DeepEqual(args, rt.expectedArgs) {
 | 
				
			||||||
 | 
									t.Errorf("expected args: %#v, got: %#v", rt.expectedArgs, args)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -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
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										95
									
								
								cmd/kubeadm/app/apis/kubeadm/v1beta3/conversion_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								cmd/kubeadm/app/apis/kubeadm/v1beta3/conversion_test.go
									
									
									
									
									
										Normal 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)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -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
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -65,6 +65,8 @@ func ValidateClusterConfiguration(c *kubeadm.ClusterConfiguration) field.ErrorLi
 | 
				
			|||||||
	allErrs = append(allErrs, ValidateDNS(&c.DNS, field.NewPath("dns"))...)
 | 
						allErrs = append(allErrs, ValidateDNS(&c.DNS, field.NewPath("dns"))...)
 | 
				
			||||||
	allErrs = append(allErrs, ValidateNetworking(c, field.NewPath("networking"))...)
 | 
						allErrs = append(allErrs, ValidateNetworking(c, field.NewPath("networking"))...)
 | 
				
			||||||
	allErrs = append(allErrs, ValidateAPIServer(&c.APIServer, field.NewPath("apiServer"))...)
 | 
						allErrs = append(allErrs, ValidateAPIServer(&c.APIServer, field.NewPath("apiServer"))...)
 | 
				
			||||||
 | 
						allErrs = append(allErrs, ValidateControllerManager(&c.ControllerManager, field.NewPath("controllerManager"))...)
 | 
				
			||||||
 | 
						allErrs = append(allErrs, ValidateScheduler(&c.Scheduler, field.NewPath("scheduler"))...)
 | 
				
			||||||
	allErrs = append(allErrs, ValidateAbsolutePath(c.CertificatesDir, field.NewPath("certificatesDir"))...)
 | 
						allErrs = append(allErrs, ValidateAbsolutePath(c.CertificatesDir, field.NewPath("certificatesDir"))...)
 | 
				
			||||||
	allErrs = append(allErrs, ValidateFeatureGates(c.FeatureGates, field.NewPath("featureGates"))...)
 | 
						allErrs = append(allErrs, ValidateFeatureGates(c.FeatureGates, field.NewPath("featureGates"))...)
 | 
				
			||||||
	allErrs = append(allErrs, ValidateHostPort(c.ControlPlaneEndpoint, field.NewPath("controlPlaneEndpoint"))...)
 | 
						allErrs = append(allErrs, ValidateHostPort(c.ControlPlaneEndpoint, field.NewPath("controlPlaneEndpoint"))...)
 | 
				
			||||||
@@ -78,6 +80,21 @@ func ValidateClusterConfiguration(c *kubeadm.ClusterConfiguration) field.ErrorLi
 | 
				
			|||||||
func ValidateAPIServer(a *kubeadm.APIServer, fldPath *field.Path) field.ErrorList {
 | 
					func ValidateAPIServer(a *kubeadm.APIServer, fldPath *field.Path) field.ErrorList {
 | 
				
			||||||
	allErrs := field.ErrorList{}
 | 
						allErrs := field.ErrorList{}
 | 
				
			||||||
	allErrs = append(allErrs, ValidateCertSANs(a.CertSANs, fldPath.Child("certSANs"))...)
 | 
						allErrs = append(allErrs, ValidateCertSANs(a.CertSANs, fldPath.Child("certSANs"))...)
 | 
				
			||||||
 | 
						allErrs = append(allErrs, ValidateExtraArgs(a.ExtraArgs, fldPath.Child("extraArgs"))...)
 | 
				
			||||||
 | 
						return allErrs
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ValidateControllerManager validates the controller manager object and collects all encountered errors
 | 
				
			||||||
 | 
					func ValidateControllerManager(a *kubeadm.ControlPlaneComponent, fldPath *field.Path) field.ErrorList {
 | 
				
			||||||
 | 
						allErrs := field.ErrorList{}
 | 
				
			||||||
 | 
						allErrs = append(allErrs, ValidateExtraArgs(a.ExtraArgs, fldPath.Child("extraArgs"))...)
 | 
				
			||||||
 | 
						return allErrs
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ValidateScheduler validates the scheduler object and collects all encountered errors
 | 
				
			||||||
 | 
					func ValidateScheduler(a *kubeadm.ControlPlaneComponent, fldPath *field.Path) field.ErrorList {
 | 
				
			||||||
 | 
						allErrs := field.ErrorList{}
 | 
				
			||||||
 | 
						allErrs = append(allErrs, ValidateExtraArgs(a.ExtraArgs, fldPath.Child("extraArgs"))...)
 | 
				
			||||||
	return allErrs
 | 
						return allErrs
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -116,6 +133,7 @@ func ValidateNodeRegistrationOptions(nro *kubeadm.NodeRegistrationOptions, fldPa
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	allErrs = append(allErrs, ValidateSocketPath(nro.CRISocket, fldPath.Child("criSocket"))...)
 | 
						allErrs = append(allErrs, ValidateSocketPath(nro.CRISocket, fldPath.Child("criSocket"))...)
 | 
				
			||||||
 | 
						allErrs = append(allErrs, ValidateExtraArgs(nro.KubeletExtraArgs, fldPath.Child("kubeletExtraArgs"))...)
 | 
				
			||||||
	// TODO: Maybe validate .Taints as well in the future using something like validateNodeTaints() in pkg/apis/core/validation
 | 
						// TODO: Maybe validate .Taints as well in the future using something like validateNodeTaints() in pkg/apis/core/validation
 | 
				
			||||||
	return allErrs
 | 
						return allErrs
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -288,6 +306,7 @@ func ValidateEtcd(e *kubeadm.Etcd, fldPath *field.Path) field.ErrorList {
 | 
				
			|||||||
		if len(e.Local.ImageRepository) > 0 {
 | 
							if len(e.Local.ImageRepository) > 0 {
 | 
				
			||||||
			allErrs = append(allErrs, ValidateImageRepository(e.Local.ImageRepository, localPath.Child("imageRepository"))...)
 | 
								allErrs = append(allErrs, ValidateImageRepository(e.Local.ImageRepository, localPath.Child("imageRepository"))...)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							allErrs = append(allErrs, ValidateExtraArgs(e.Local.ExtraArgs, localPath.Child("extraArgs"))...)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if e.External != nil {
 | 
						if e.External != nil {
 | 
				
			||||||
		requireHTTPS := true
 | 
							requireHTTPS := true
 | 
				
			||||||
@@ -479,9 +498,10 @@ func getClusterNodeMask(c *kubeadm.ClusterConfiguration, isIPv6 bool) (int, erro
 | 
				
			|||||||
		maskArg = "node-cidr-mask-size-ipv4"
 | 
							maskArg = "node-cidr-mask-size-ipv4"
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if v, ok := c.ControllerManager.ExtraArgs[maskArg]; ok && v != "" {
 | 
						maskValue, _ := kubeadm.GetArgValue(c.ControllerManager.ExtraArgs, maskArg, -1)
 | 
				
			||||||
 | 
						if len(maskValue) != 0 {
 | 
				
			||||||
		// assume it is an integer, if not it will fail later
 | 
							// assume it is an integer, if not it will fail later
 | 
				
			||||||
		maskSize, err = strconv.Atoi(v)
 | 
							maskSize, err = strconv.Atoi(maskValue)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return 0, errors.Wrapf(err, "could not parse the value of the kube-controller-manager flag %s as an integer", maskArg)
 | 
								return 0, errors.Wrapf(err, "could not parse the value of the kube-controller-manager flag %s as an integer", maskArg)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -519,7 +539,8 @@ func ValidateNetworking(c *kubeadm.ClusterConfiguration, fldPath *field.Path) fi
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	if len(c.Networking.PodSubnet) != 0 {
 | 
						if len(c.Networking.PodSubnet) != 0 {
 | 
				
			||||||
		allErrs = append(allErrs, ValidateIPNetFromString(c.Networking.PodSubnet, constants.MinimumAddressesInPodSubnet, fldPath.Child("podSubnet"))...)
 | 
							allErrs = append(allErrs, ValidateIPNetFromString(c.Networking.PodSubnet, constants.MinimumAddressesInPodSubnet, fldPath.Child("podSubnet"))...)
 | 
				
			||||||
		if c.ControllerManager.ExtraArgs["allocate-node-cidrs"] != "false" {
 | 
							val, _ := kubeadm.GetArgValue(c.ControllerManager.ExtraArgs, "allocate-node-cidrs", -1)
 | 
				
			||||||
 | 
							if val != "false" {
 | 
				
			||||||
			// Pod subnet was already validated, we need to validate now against the node-mask
 | 
								// Pod subnet was already validated, we need to validate now against the node-mask
 | 
				
			||||||
			allErrs = append(allErrs, ValidatePodSubnetNodeMask(c.Networking.PodSubnet, c, fldPath.Child("podSubnet"))...)
 | 
								allErrs = append(allErrs, ValidatePodSubnetNodeMask(c.Networking.PodSubnet, c, fldPath.Child("podSubnet"))...)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -676,3 +697,16 @@ func ValidateResetConfiguration(c *kubeadm.ResetConfiguration) field.ErrorList {
 | 
				
			|||||||
	allErrs = append(allErrs, ValidateAbsolutePath(c.CertificatesDir, field.NewPath("certificatesDir"))...)
 | 
						allErrs = append(allErrs, ValidateAbsolutePath(c.CertificatesDir, field.NewPath("certificatesDir"))...)
 | 
				
			||||||
	return allErrs
 | 
						return allErrs
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ValidateExtraArgs validates a set of arguments and collects all encountered errors
 | 
				
			||||||
 | 
					func ValidateExtraArgs(args []kubeadm.Arg, fldPath *field.Path) field.ErrorList {
 | 
				
			||||||
 | 
						allErrs := field.ErrorList{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for idx, arg := range args {
 | 
				
			||||||
 | 
							if len(arg.Name) == 0 {
 | 
				
			||||||
 | 
								allErrs = append(allErrs, field.Invalid(fldPath, fmt.Sprintf("index %d", idx), "argument has no name"))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return allErrs
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -254,24 +254,24 @@ func TestValidatePodSubnetNodeMask(t *testing.T) {
 | 
				
			|||||||
	var tests = []struct {
 | 
						var tests = []struct {
 | 
				
			||||||
		name        string
 | 
							name        string
 | 
				
			||||||
		subnet      string
 | 
							subnet      string
 | 
				
			||||||
		cmExtraArgs map[string]string
 | 
							cmExtraArgs []kubeadmapi.Arg
 | 
				
			||||||
		expected    bool
 | 
							expected    bool
 | 
				
			||||||
	}{
 | 
						}{
 | 
				
			||||||
		// dual-stack:
 | 
							// dual-stack:
 | 
				
			||||||
		{"dual IPv4 only, but mask too small. Default node-mask", "10.0.0.16/29", nil, false},
 | 
							{"dual IPv4 only, but mask too small. Default node-mask", "10.0.0.16/29", nil, false},
 | 
				
			||||||
		{"dual IPv4 only, but mask too small. Configured node-mask", "10.0.0.16/24", map[string]string{"node-cidr-mask-size-ipv4": "23"}, false},
 | 
							{"dual IPv4 only, but mask too small. Configured node-mask", "10.0.0.16/24", []kubeadmapi.Arg{{Name: "node-cidr-mask-size-ipv4", Value: "23"}}, false},
 | 
				
			||||||
		{"dual IPv6 only, but mask too small. Default node-mask", "2001:db8::1/112", nil, false},
 | 
							{"dual IPv6 only, but mask too small. Default node-mask", "2001:db8::1/112", nil, false},
 | 
				
			||||||
		{"dual IPv6 only, but mask too small. Configured node-mask", "2001:db8::1/64", map[string]string{"node-cidr-mask-size-ipv6": "24"}, false},
 | 
							{"dual IPv6 only, but mask too small. Configured node-mask", "2001:db8::1/64", []kubeadmapi.Arg{{Name: "node-cidr-mask-size-ipv6", Value: "24"}}, false},
 | 
				
			||||||
		{"dual IPv6 only, but mask difference greater than 16. Default node-mask", "2001:db8::1/12", nil, false},
 | 
							{"dual IPv6 only, but mask difference greater than 16. Default node-mask", "2001:db8::1/12", nil, false},
 | 
				
			||||||
		{"dual IPv6 only, but mask difference greater than 16. Configured node-mask", "2001:db8::1/64", map[string]string{"node-cidr-mask-size-ipv6": "120"}, false},
 | 
							{"dual IPv6 only, but mask difference greater than 16. Configured node-mask", "2001:db8::1/64", []kubeadmapi.Arg{{Name: "node-cidr-mask-size-ipv6", Value: "120"}}, false},
 | 
				
			||||||
		{"dual IPv4 only CIDR", "10.0.0.16/12", nil, true},
 | 
							{"dual IPv4 only CIDR", "10.0.0.16/12", nil, true},
 | 
				
			||||||
		{"dual IPv6 only CIDR", "2001:db8::/48", nil, true},
 | 
							{"dual IPv6 only CIDR", "2001:db8::/48", nil, true},
 | 
				
			||||||
		{"dual, but IPv4 mask too small. Default node-mask", "10.0.0.16/29,2001:db8::/48", nil, false},
 | 
							{"dual, but IPv4 mask too small. Default node-mask", "10.0.0.16/29,2001:db8::/48", nil, false},
 | 
				
			||||||
		{"dual, but IPv4 mask too small. Configured node-mask", "10.0.0.16/24,2001:db8::/48", map[string]string{"node-cidr-mask-size-ipv4": "23"}, false},
 | 
							{"dual, but IPv4 mask too small. Configured node-mask", "10.0.0.16/24,2001:db8::/48", []kubeadmapi.Arg{{Name: "node-cidr-mask-size-ipv4", Value: "23"}}, false},
 | 
				
			||||||
		{"dual, but IPv6 mask too small. Default node-mask", "2001:db8::1/112,10.0.0.16/16", nil, false},
 | 
							{"dual, but IPv6 mask too small. Default node-mask", "2001:db8::1/112,10.0.0.16/16", nil, false},
 | 
				
			||||||
		{"dual, but IPv6 mask too small. Configured node-mask", "10.0.0.16/16,2001:db8::1/64", map[string]string{"node-cidr-mask-size-ipv6": "24"}, false},
 | 
							{"dual, but IPv6 mask too small. Configured node-mask", "10.0.0.16/16,2001:db8::1/64", []kubeadmapi.Arg{{Name: "node-cidr-mask-size-ipv6", Value: "24"}}, false},
 | 
				
			||||||
		{"dual, but mask difference greater than 16. Default node-mask", "2001:db8::1/12,10.0.0.16/16", nil, false},
 | 
							{"dual, but mask difference greater than 16. Default node-mask", "2001:db8::1/12,10.0.0.16/16", nil, false},
 | 
				
			||||||
		{"dual, but mask difference greater than 16. Configured node-mask", "10.0.0.16/16,2001:db8::1/64", map[string]string{"node-cidr-mask-size-ipv6": "120"}, false},
 | 
							{"dual, but mask difference greater than 16. Configured node-mask", "10.0.0.16/16,2001:db8::1/64", []kubeadmapi.Arg{{Name: "node-cidr-mask-size-ipv6", Value: "120"}}, false},
 | 
				
			||||||
		{"dual IPv4 IPv6", "2001:db8::/48,10.0.0.16/12", nil, true},
 | 
							{"dual IPv4 IPv6", "2001:db8::/48,10.0.0.16/12", nil, true},
 | 
				
			||||||
		{"dual IPv6 IPv4", "2001:db8::/48,10.0.0.16/12", nil, true},
 | 
							{"dual IPv6 IPv4", "2001:db8::/48,10.0.0.16/12", nil, true},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -1205,7 +1205,10 @@ func TestGetClusterNodeMask(t *testing.T) {
 | 
				
			|||||||
			name: "dual ipv4 custom mask",
 | 
								name: "dual ipv4 custom mask",
 | 
				
			||||||
			cfg: &kubeadmapi.ClusterConfiguration{
 | 
								cfg: &kubeadmapi.ClusterConfiguration{
 | 
				
			||||||
				ControllerManager: kubeadmapi.ControlPlaneComponent{
 | 
									ControllerManager: kubeadmapi.ControlPlaneComponent{
 | 
				
			||||||
					ExtraArgs: map[string]string{"node-cidr-mask-size": "21", "node-cidr-mask-size-ipv4": "23"},
 | 
										ExtraArgs: []kubeadmapi.Arg{
 | 
				
			||||||
 | 
											{Name: "node-cidr-mask-size", Value: "21"},
 | 
				
			||||||
 | 
											{Name: "node-cidr-mask-size-ipv4", Value: "23"},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			isIPv6:       false,
 | 
								isIPv6:       false,
 | 
				
			||||||
@@ -1221,7 +1224,9 @@ func TestGetClusterNodeMask(t *testing.T) {
 | 
				
			|||||||
			name: "dual ipv6 custom mask",
 | 
								name: "dual ipv6 custom mask",
 | 
				
			||||||
			cfg: &kubeadmapi.ClusterConfiguration{
 | 
								cfg: &kubeadmapi.ClusterConfiguration{
 | 
				
			||||||
				ControllerManager: kubeadmapi.ControlPlaneComponent{
 | 
									ControllerManager: kubeadmapi.ControlPlaneComponent{
 | 
				
			||||||
					ExtraArgs: map[string]string{"node-cidr-mask-size-ipv6": "83"},
 | 
										ExtraArgs: []kubeadmapi.Arg{
 | 
				
			||||||
 | 
											{Name: "node-cidr-mask-size-ipv6", Value: "83"},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			isIPv6:       true,
 | 
								isIPv6:       true,
 | 
				
			||||||
@@ -1231,7 +1236,9 @@ func TestGetClusterNodeMask(t *testing.T) {
 | 
				
			|||||||
			name: "dual ipv4 custom mask",
 | 
								name: "dual ipv4 custom mask",
 | 
				
			||||||
			cfg: &kubeadmapi.ClusterConfiguration{
 | 
								cfg: &kubeadmapi.ClusterConfiguration{
 | 
				
			||||||
				ControllerManager: kubeadmapi.ControlPlaneComponent{
 | 
									ControllerManager: kubeadmapi.ControlPlaneComponent{
 | 
				
			||||||
					ExtraArgs: map[string]string{"node-cidr-mask-size-ipv4": "23"},
 | 
										ExtraArgs: []kubeadmapi.Arg{
 | 
				
			||||||
 | 
											{Name: "node-cidr-mask-size-ipv4", Value: "23"},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			isIPv6:       false,
 | 
								isIPv6:       false,
 | 
				
			||||||
@@ -1241,7 +1248,9 @@ func TestGetClusterNodeMask(t *testing.T) {
 | 
				
			|||||||
			name: "dual ipv4 wrong mask",
 | 
								name: "dual ipv4 wrong mask",
 | 
				
			||||||
			cfg: &kubeadmapi.ClusterConfiguration{
 | 
								cfg: &kubeadmapi.ClusterConfiguration{
 | 
				
			||||||
				ControllerManager: kubeadmapi.ControlPlaneComponent{
 | 
									ControllerManager: kubeadmapi.ControlPlaneComponent{
 | 
				
			||||||
					ExtraArgs: map[string]string{"node-cidr-mask-size-ipv4": "aa"},
 | 
										ExtraArgs: []kubeadmapi.Arg{
 | 
				
			||||||
 | 
											{Name: "node-cidr-mask-size-ipv4", Value: "aa"},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			isIPv6:        false,
 | 
								isIPv6:        false,
 | 
				
			||||||
@@ -1251,7 +1260,9 @@ func TestGetClusterNodeMask(t *testing.T) {
 | 
				
			|||||||
			name: "dual ipv6 default mask and legacy flag",
 | 
								name: "dual ipv6 default mask and legacy flag",
 | 
				
			||||||
			cfg: &kubeadmapi.ClusterConfiguration{
 | 
								cfg: &kubeadmapi.ClusterConfiguration{
 | 
				
			||||||
				ControllerManager: kubeadmapi.ControlPlaneComponent{
 | 
									ControllerManager: kubeadmapi.ControlPlaneComponent{
 | 
				
			||||||
					ExtraArgs: map[string]string{"node-cidr-mask-size": "23"},
 | 
										ExtraArgs: []kubeadmapi.Arg{
 | 
				
			||||||
 | 
											{Name: "node-cidr-mask-size", Value: "23"},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			isIPv6:       true,
 | 
								isIPv6:       true,
 | 
				
			||||||
@@ -1261,7 +1272,10 @@ func TestGetClusterNodeMask(t *testing.T) {
 | 
				
			|||||||
			name: "dual ipv6 custom mask and legacy flag",
 | 
								name: "dual ipv6 custom mask and legacy flag",
 | 
				
			||||||
			cfg: &kubeadmapi.ClusterConfiguration{
 | 
								cfg: &kubeadmapi.ClusterConfiguration{
 | 
				
			||||||
				ControllerManager: kubeadmapi.ControlPlaneComponent{
 | 
									ControllerManager: kubeadmapi.ControlPlaneComponent{
 | 
				
			||||||
					ExtraArgs: map[string]string{"node-cidr-mask-size": "23", "node-cidr-mask-size-ipv6": "83"},
 | 
										ExtraArgs: []kubeadmapi.Arg{
 | 
				
			||||||
 | 
											{Name: "node-cidr-mask-size", Value: "23"},
 | 
				
			||||||
 | 
											{Name: "node-cidr-mask-size-ipv6", Value: "83"},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			isIPv6:       true,
 | 
								isIPv6:       true,
 | 
				
			||||||
@@ -1271,7 +1285,10 @@ func TestGetClusterNodeMask(t *testing.T) {
 | 
				
			|||||||
			name: "dual ipv6 custom mask and wrong flag",
 | 
								name: "dual ipv6 custom mask and wrong flag",
 | 
				
			||||||
			cfg: &kubeadmapi.ClusterConfiguration{
 | 
								cfg: &kubeadmapi.ClusterConfiguration{
 | 
				
			||||||
				ControllerManager: kubeadmapi.ControlPlaneComponent{
 | 
									ControllerManager: kubeadmapi.ControlPlaneComponent{
 | 
				
			||||||
					ExtraArgs: map[string]string{"node-cidr-mask-size": "23", "node-cidr-mask-size-ipv6": "a83"},
 | 
										ExtraArgs: []kubeadmapi.Arg{
 | 
				
			||||||
 | 
											{Name: "node-cidr-mask-size", Value: "23"},
 | 
				
			||||||
 | 
											{Name: "node-cidr-mask-size-ipv6", Value: "a83"},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			isIPv6:        true,
 | 
								isIPv6:        true,
 | 
				
			||||||
@@ -1390,3 +1407,34 @@ func TestValidateAbsolutePath(t *testing.T) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestValidateExtraArgs(t *testing.T) {
 | 
				
			||||||
 | 
						var tests = []struct {
 | 
				
			||||||
 | 
							name           string
 | 
				
			||||||
 | 
							args           []kubeadmapi.Arg
 | 
				
			||||||
 | 
							expectedErrors int
 | 
				
			||||||
 | 
						}{
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name:           "valid argument",
 | 
				
			||||||
 | 
								args:           []kubeadmapi.Arg{{Name: "foo", Value: "bar"}},
 | 
				
			||||||
 | 
								expectedErrors: 0,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name:           "invalid one argument",
 | 
				
			||||||
 | 
								args:           []kubeadmapi.Arg{{Name: "", Value: "bar"}},
 | 
				
			||||||
 | 
								expectedErrors: 1,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name:           "invalid two arguments",
 | 
				
			||||||
 | 
								args:           []kubeadmapi.Arg{{Name: "", Value: "foo"}, {Name: "", Value: "bar"}},
 | 
				
			||||||
 | 
								expectedErrors: 2,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, tc := range tests {
 | 
				
			||||||
 | 
							actual := ValidateExtraArgs(tc.args, nil)
 | 
				
			||||||
 | 
							if len(actual) != tc.expectedErrors {
 | 
				
			||||||
 | 
								t.Errorf("case %q:\n\t expected errors: %v\n\t got: %v\n\t errors: %v", tc.name, tc.expectedErrors, len(actual), actual)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -54,6 +54,9 @@ func AddIgnorePreflightErrorsFlag(fs *pflag.FlagSet, ignorePreflightErrors *[]st
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// AddControlPlanExtraArgsFlags adds the ExtraArgs flags for control plane components
 | 
					// AddControlPlanExtraArgsFlags adds the ExtraArgs flags for control plane components
 | 
				
			||||||
func AddControlPlanExtraArgsFlags(fs *pflag.FlagSet, apiServerExtraArgs, controllerManagerExtraArgs, schedulerExtraArgs *map[string]string) {
 | 
					func AddControlPlanExtraArgsFlags(fs *pflag.FlagSet, apiServerExtraArgs, controllerManagerExtraArgs, schedulerExtraArgs *map[string]string) {
 | 
				
			||||||
 | 
						// TODO: https://github.com/kubernetes/kubeadm/issues/1601
 | 
				
			||||||
 | 
						// Either deprecate these flags or handle duplicate keys.
 | 
				
			||||||
 | 
						// Currently the map[string]string returned by NewMapStringString() doesn't allow this.
 | 
				
			||||||
	fs.Var(cliflag.NewMapStringString(apiServerExtraArgs), APIServerExtraArgs, "A set of extra flags to pass to the API Server or override default ones in form of <flagname>=<value>")
 | 
						fs.Var(cliflag.NewMapStringString(apiServerExtraArgs), APIServerExtraArgs, "A set of extra flags to pass to the API Server or override default ones in form of <flagname>=<value>")
 | 
				
			||||||
	fs.Var(cliflag.NewMapStringString(controllerManagerExtraArgs), ControllerManagerExtraArgs, "A set of extra flags to pass to the Controller Manager or override default ones in form of <flagname>=<value>")
 | 
						fs.Var(cliflag.NewMapStringString(controllerManagerExtraArgs), ControllerManagerExtraArgs, "A set of extra flags to pass to the Controller Manager or override default ones in form of <flagname>=<value>")
 | 
				
			||||||
	fs.Var(cliflag.NewMapStringString(schedulerExtraArgs), SchedulerExtraArgs, "A set of extra flags to pass to the Scheduler or override default ones in form of <flagname>=<value>")
 | 
						fs.Var(cliflag.NewMapStringString(schedulerExtraArgs), SchedulerExtraArgs, "A set of extra flags to pass to the Scheduler or override default ones in form of <flagname>=<value>")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,6 +26,7 @@ import (
 | 
				
			|||||||
	"k8s.io/client-go/tools/clientcmd"
 | 
						"k8s.io/client-go/tools/clientcmd"
 | 
				
			||||||
	"k8s.io/klog/v2"
 | 
						"k8s.io/klog/v2"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
 | 
				
			||||||
	"k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
 | 
						"k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
 | 
				
			||||||
	"k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/workflow"
 | 
						"k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/workflow"
 | 
				
			||||||
	cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util"
 | 
						cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util"
 | 
				
			||||||
@@ -78,8 +79,8 @@ func runKubeletFinalizeCertRotation(c workflow.RunData) error {
 | 
				
			|||||||
	// If yes, use that path, else use the kubeadm provided value.
 | 
						// If yes, use that path, else use the kubeadm provided value.
 | 
				
			||||||
	cfg := data.Cfg()
 | 
						cfg := data.Cfg()
 | 
				
			||||||
	pkiPath := filepath.Join(data.KubeletDir(), "pki")
 | 
						pkiPath := filepath.Join(data.KubeletDir(), "pki")
 | 
				
			||||||
	val, ok := cfg.NodeRegistration.KubeletExtraArgs["cert-dir"]
 | 
						val, idx := kubeadmapi.GetArgValue(cfg.NodeRegistration.KubeletExtraArgs, "cert-dir", -1)
 | 
				
			||||||
	if ok {
 | 
						if idx > -1 {
 | 
				
			||||||
		pkiPath = val
 | 
							pkiPath = val
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -162,46 +162,47 @@ func CreateStaticPodFiles(manifestDir, patchesDir string, cfg *kubeadmapi.Cluste
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// getAPIServerCommand builds the right API server command from the given config object and version
 | 
					// getAPIServerCommand builds the right API server command from the given config object and version
 | 
				
			||||||
func getAPIServerCommand(cfg *kubeadmapi.ClusterConfiguration, localAPIEndpoint *kubeadmapi.APIEndpoint) []string {
 | 
					func getAPIServerCommand(cfg *kubeadmapi.ClusterConfiguration, localAPIEndpoint *kubeadmapi.APIEndpoint) []string {
 | 
				
			||||||
	defaultArguments := map[string]string{
 | 
						defaultArguments := []kubeadmapi.Arg{
 | 
				
			||||||
		"advertise-address":                localAPIEndpoint.AdvertiseAddress,
 | 
							{Name: "advertise-address", Value: localAPIEndpoint.AdvertiseAddress},
 | 
				
			||||||
		"enable-admission-plugins":         "NodeRestriction",
 | 
							{Name: "enable-admission-plugins", Value: "NodeRestriction"},
 | 
				
			||||||
		"service-cluster-ip-range":         cfg.Networking.ServiceSubnet,
 | 
							{Name: "service-cluster-ip-range", Value: cfg.Networking.ServiceSubnet},
 | 
				
			||||||
		"service-account-key-file":         filepath.Join(cfg.CertificatesDir, kubeadmconstants.ServiceAccountPublicKeyName),
 | 
							{Name: "service-account-key-file", Value: filepath.Join(cfg.CertificatesDir, kubeadmconstants.ServiceAccountPublicKeyName)},
 | 
				
			||||||
		"service-account-signing-key-file": filepath.Join(cfg.CertificatesDir, kubeadmconstants.ServiceAccountPrivateKeyName),
 | 
							{Name: "service-account-signing-key-file", Value: filepath.Join(cfg.CertificatesDir, kubeadmconstants.ServiceAccountPrivateKeyName)},
 | 
				
			||||||
		"service-account-issuer":           fmt.Sprintf("https://kubernetes.default.svc.%s", cfg.Networking.DNSDomain),
 | 
							{Name: "service-account-issuer", Value: fmt.Sprintf("https://kubernetes.default.svc.%s", cfg.Networking.DNSDomain)},
 | 
				
			||||||
		"client-ca-file":                   filepath.Join(cfg.CertificatesDir, kubeadmconstants.CACertName),
 | 
							{Name: "client-ca-file", Value: filepath.Join(cfg.CertificatesDir, kubeadmconstants.CACertName)},
 | 
				
			||||||
		"tls-cert-file":                    filepath.Join(cfg.CertificatesDir, kubeadmconstants.APIServerCertName),
 | 
							{Name: "tls-cert-file", Value: filepath.Join(cfg.CertificatesDir, kubeadmconstants.APIServerCertName)},
 | 
				
			||||||
		"tls-private-key-file":             filepath.Join(cfg.CertificatesDir, kubeadmconstants.APIServerKeyName),
 | 
							{Name: "tls-private-key-file", Value: filepath.Join(cfg.CertificatesDir, kubeadmconstants.APIServerKeyName)},
 | 
				
			||||||
		"kubelet-client-certificate":       filepath.Join(cfg.CertificatesDir, kubeadmconstants.APIServerKubeletClientCertName),
 | 
							{Name: "kubelet-client-certificate", Value: filepath.Join(cfg.CertificatesDir, kubeadmconstants.APIServerKubeletClientCertName)},
 | 
				
			||||||
		"kubelet-client-key":               filepath.Join(cfg.CertificatesDir, kubeadmconstants.APIServerKubeletClientKeyName),
 | 
							{Name: "kubelet-client-key", Value: filepath.Join(cfg.CertificatesDir, kubeadmconstants.APIServerKubeletClientKeyName)},
 | 
				
			||||||
		"enable-bootstrap-token-auth":      "true",
 | 
							{Name: "enable-bootstrap-token-auth", Value: "true"},
 | 
				
			||||||
		"secure-port":                      fmt.Sprintf("%d", localAPIEndpoint.BindPort),
 | 
							{Name: "secure-port", Value: fmt.Sprintf("%d", localAPIEndpoint.BindPort)},
 | 
				
			||||||
		"allow-privileged":                 "true",
 | 
							{Name: "allow-privileged", Value: "true"},
 | 
				
			||||||
		"kubelet-preferred-address-types":  "InternalIP,ExternalIP,Hostname",
 | 
							{Name: "kubelet-preferred-address-types", Value: "InternalIP,ExternalIP,Hostname"},
 | 
				
			||||||
		// add options to configure the front proxy.  Without the generated client cert, this will never be useable
 | 
							// add options to configure the front proxy.  Without the generated client cert, this will never be useable
 | 
				
			||||||
		// so add it unconditionally with recommended values
 | 
							// so add it unconditionally with recommended values
 | 
				
			||||||
		"requestheader-username-headers":     "X-Remote-User",
 | 
							{Name: "requestheader-username-headers", Value: "X-Remote-User"},
 | 
				
			||||||
		"requestheader-group-headers":        "X-Remote-Group",
 | 
							{Name: "requestheader-group-headers", Value: "X-Remote-Group"},
 | 
				
			||||||
		"requestheader-extra-headers-prefix": "X-Remote-Extra-",
 | 
							{Name: "requestheader-extra-headers-prefix", Value: "X-Remote-Extra-"},
 | 
				
			||||||
		"requestheader-client-ca-file":       filepath.Join(cfg.CertificatesDir, kubeadmconstants.FrontProxyCACertName),
 | 
							{Name: "requestheader-client-ca-file", Value: filepath.Join(cfg.CertificatesDir, kubeadmconstants.FrontProxyCACertName)},
 | 
				
			||||||
		"requestheader-allowed-names":        "front-proxy-client",
 | 
							{Name: "requestheader-allowed-names", Value: "front-proxy-client"},
 | 
				
			||||||
		"proxy-client-cert-file":             filepath.Join(cfg.CertificatesDir, kubeadmconstants.FrontProxyClientCertName),
 | 
							{Name: "proxy-client-cert-file", Value: filepath.Join(cfg.CertificatesDir, kubeadmconstants.FrontProxyClientCertName)},
 | 
				
			||||||
		"proxy-client-key-file":              filepath.Join(cfg.CertificatesDir, kubeadmconstants.FrontProxyClientKeyName),
 | 
							{Name: "proxy-client-key-file", Value: filepath.Join(cfg.CertificatesDir, kubeadmconstants.FrontProxyClientKeyName)},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	command := []string{"kube-apiserver"}
 | 
						command := []string{"kube-apiserver"}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// If the user set endpoints for an external etcd cluster
 | 
						// If the user set endpoints for an external etcd cluster
 | 
				
			||||||
	if cfg.Etcd.External != nil {
 | 
						if cfg.Etcd.External != nil {
 | 
				
			||||||
		defaultArguments["etcd-servers"] = strings.Join(cfg.Etcd.External.Endpoints, ",")
 | 
							defaultArguments = kubeadmapi.SetArgValues(defaultArguments, "etcd-servers", strings.Join(cfg.Etcd.External.Endpoints, ","), 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Use any user supplied etcd certificates
 | 
							// Use any user supplied etcd certificates
 | 
				
			||||||
		if cfg.Etcd.External.CAFile != "" {
 | 
							if cfg.Etcd.External.CAFile != "" {
 | 
				
			||||||
			defaultArguments["etcd-cafile"] = cfg.Etcd.External.CAFile
 | 
								defaultArguments = kubeadmapi.SetArgValues(defaultArguments, "etcd-cafile", cfg.Etcd.External.CAFile, 1)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if cfg.Etcd.External.CertFile != "" && cfg.Etcd.External.KeyFile != "" {
 | 
							if cfg.Etcd.External.CertFile != "" && cfg.Etcd.External.KeyFile != "" {
 | 
				
			||||||
			defaultArguments["etcd-certfile"] = cfg.Etcd.External.CertFile
 | 
								defaultArguments = kubeadmapi.SetArgValues(defaultArguments, "etcd-certfile", cfg.Etcd.External.CertFile, 1)
 | 
				
			||||||
			defaultArguments["etcd-keyfile"] = cfg.Etcd.External.KeyFile
 | 
								defaultArguments = kubeadmapi.SetArgValues(defaultArguments, "etcd-keyfile", cfg.Etcd.External.KeyFile, 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		// Default to etcd static pod on localhost
 | 
							// Default to etcd static pod on localhost
 | 
				
			||||||
@@ -210,24 +211,25 @@ func getAPIServerCommand(cfg *kubeadmapi.ClusterConfiguration, localAPIEndpoint
 | 
				
			|||||||
		if utilsnet.IsIPv6String(localAPIEndpoint.AdvertiseAddress) {
 | 
							if utilsnet.IsIPv6String(localAPIEndpoint.AdvertiseAddress) {
 | 
				
			||||||
			etcdLocalhostAddress = "::1"
 | 
								etcdLocalhostAddress = "::1"
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		defaultArguments["etcd-servers"] = fmt.Sprintf("https://%s", net.JoinHostPort(etcdLocalhostAddress, strconv.Itoa(kubeadmconstants.EtcdListenClientPort)))
 | 
							defaultArguments = kubeadmapi.SetArgValues(defaultArguments, "etcd-servers", fmt.Sprintf("https://%s", net.JoinHostPort(etcdLocalhostAddress, strconv.Itoa(kubeadmconstants.EtcdListenClientPort))), 1)
 | 
				
			||||||
		defaultArguments["etcd-cafile"] = filepath.Join(cfg.CertificatesDir, kubeadmconstants.EtcdCACertName)
 | 
							defaultArguments = kubeadmapi.SetArgValues(defaultArguments, "etcd-cafile", filepath.Join(cfg.CertificatesDir, kubeadmconstants.EtcdCACertName), 1)
 | 
				
			||||||
		defaultArguments["etcd-certfile"] = filepath.Join(cfg.CertificatesDir, kubeadmconstants.APIServerEtcdClientCertName)
 | 
							defaultArguments = kubeadmapi.SetArgValues(defaultArguments, "etcd-certfile", filepath.Join(cfg.CertificatesDir, kubeadmconstants.APIServerEtcdClientCertName), 1)
 | 
				
			||||||
		defaultArguments["etcd-keyfile"] = filepath.Join(cfg.CertificatesDir, kubeadmconstants.APIServerEtcdClientKeyName)
 | 
							defaultArguments = kubeadmapi.SetArgValues(defaultArguments, "etcd-keyfile", filepath.Join(cfg.CertificatesDir, kubeadmconstants.APIServerEtcdClientKeyName), 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Apply user configurations for local etcd
 | 
							// Apply user configurations for local etcd
 | 
				
			||||||
		if cfg.Etcd.Local != nil {
 | 
							if cfg.Etcd.Local != nil {
 | 
				
			||||||
			if value, ok := cfg.Etcd.Local.ExtraArgs["advertise-client-urls"]; ok {
 | 
								if value, idx := kubeadmapi.GetArgValue(cfg.Etcd.Local.ExtraArgs, "advertise-client-urls", -1); idx > -1 {
 | 
				
			||||||
				defaultArguments["etcd-servers"] = value
 | 
									defaultArguments = kubeadmapi.SetArgValues(defaultArguments, "etcd-servers", value, 1)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if cfg.APIServer.ExtraArgs == nil {
 | 
						if cfg.APIServer.ExtraArgs == nil {
 | 
				
			||||||
		cfg.APIServer.ExtraArgs = map[string]string{}
 | 
							cfg.APIServer.ExtraArgs = []kubeadmapi.Arg{}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	cfg.APIServer.ExtraArgs["authorization-mode"] = getAuthzModes(cfg.APIServer.ExtraArgs["authorization-mode"])
 | 
						authzVal, _ := kubeadmapi.GetArgValue(cfg.APIServer.ExtraArgs, "authorization-mode", -1)
 | 
				
			||||||
	command = append(command, kubeadmutil.BuildArgumentListFromMap(defaultArguments, cfg.APIServer.ExtraArgs)...)
 | 
						cfg.APIServer.ExtraArgs = kubeadmapi.SetArgValues(cfg.APIServer.ExtraArgs, "authorization-mode", getAuthzModes(authzVal), 1)
 | 
				
			||||||
 | 
						command = append(command, kubeadmutil.ArgumentsToCommand(defaultArguments, cfg.APIServer.ExtraArgs)...)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return command
 | 
						return command
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -302,46 +304,46 @@ func getControllerManagerCommand(cfg *kubeadmapi.ClusterConfiguration) []string
 | 
				
			|||||||
	kubeconfigFile := filepath.Join(kubeadmconstants.KubernetesDir, kubeadmconstants.ControllerManagerKubeConfigFileName)
 | 
						kubeconfigFile := filepath.Join(kubeadmconstants.KubernetesDir, kubeadmconstants.ControllerManagerKubeConfigFileName)
 | 
				
			||||||
	caFile := filepath.Join(cfg.CertificatesDir, kubeadmconstants.CACertName)
 | 
						caFile := filepath.Join(cfg.CertificatesDir, kubeadmconstants.CACertName)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	defaultArguments := map[string]string{
 | 
						defaultArguments := []kubeadmapi.Arg{
 | 
				
			||||||
		"bind-address":                     "127.0.0.1",
 | 
							{Name: "bind-address", Value: "127.0.0.1"},
 | 
				
			||||||
		"leader-elect":                     "true",
 | 
							{Name: "leader-elect", Value: "true"},
 | 
				
			||||||
		"kubeconfig":                       kubeconfigFile,
 | 
							{Name: "kubeconfig", Value: kubeconfigFile},
 | 
				
			||||||
		"authentication-kubeconfig":        kubeconfigFile,
 | 
							{Name: "authentication-kubeconfig", Value: kubeconfigFile},
 | 
				
			||||||
		"authorization-kubeconfig":         kubeconfigFile,
 | 
							{Name: "authorization-kubeconfig", Value: kubeconfigFile},
 | 
				
			||||||
		"client-ca-file":                   caFile,
 | 
							{Name: "client-ca-file", Value: caFile},
 | 
				
			||||||
		"requestheader-client-ca-file":     filepath.Join(cfg.CertificatesDir, kubeadmconstants.FrontProxyCACertName),
 | 
							{Name: "requestheader-client-ca-file", Value: filepath.Join(cfg.CertificatesDir, kubeadmconstants.FrontProxyCACertName)},
 | 
				
			||||||
		"root-ca-file":                     caFile,
 | 
							{Name: "root-ca-file", Value: caFile},
 | 
				
			||||||
		"service-account-private-key-file": filepath.Join(cfg.CertificatesDir, kubeadmconstants.ServiceAccountPrivateKeyName),
 | 
							{Name: "service-account-private-key-file", Value: filepath.Join(cfg.CertificatesDir, kubeadmconstants.ServiceAccountPrivateKeyName)},
 | 
				
			||||||
		"cluster-signing-cert-file":        caFile,
 | 
							{Name: "cluster-signing-cert-file", Value: caFile},
 | 
				
			||||||
		"cluster-signing-key-file":         filepath.Join(cfg.CertificatesDir, kubeadmconstants.CAKeyName),
 | 
							{Name: "cluster-signing-key-file", Value: filepath.Join(cfg.CertificatesDir, kubeadmconstants.CAKeyName)},
 | 
				
			||||||
		"use-service-account-credentials":  "true",
 | 
							{Name: "use-service-account-credentials", Value: "true"},
 | 
				
			||||||
		"controllers":                      "*,bootstrapsigner,tokencleaner",
 | 
							{Name: "controllers", Value: "*,bootstrapsigner,tokencleaner"},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// If using external CA, pass empty string to controller manager instead of ca.key/ca.crt path,
 | 
						// If using external CA, pass empty string to controller manager instead of ca.key/ca.crt path,
 | 
				
			||||||
	// so that the csrsigning controller fails to start
 | 
						// so that the csrsigning controller fails to start
 | 
				
			||||||
	if res, _ := certphase.UsingExternalCA(cfg); res {
 | 
						if res, _ := certphase.UsingExternalCA(cfg); res {
 | 
				
			||||||
		defaultArguments["cluster-signing-key-file"] = ""
 | 
							defaultArguments = kubeadmapi.SetArgValues(defaultArguments, "cluster-signing-key-file", "", 1)
 | 
				
			||||||
		defaultArguments["cluster-signing-cert-file"] = ""
 | 
							defaultArguments = kubeadmapi.SetArgValues(defaultArguments, "cluster-signing-cert-file", "", 1)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Let the controller-manager allocate Node CIDRs for the Pod network.
 | 
						// Let the controller-manager allocate Node CIDRs for the Pod network.
 | 
				
			||||||
	// Each node will get a subspace of the address CIDR provided with --pod-network-cidr.
 | 
						// Each node will get a subspace of the address CIDR provided with --pod-network-cidr.
 | 
				
			||||||
	if cfg.Networking.PodSubnet != "" {
 | 
						if cfg.Networking.PodSubnet != "" {
 | 
				
			||||||
		defaultArguments["allocate-node-cidrs"] = "true"
 | 
							defaultArguments = kubeadmapi.SetArgValues(defaultArguments, "allocate-node-cidrs", "true", 1)
 | 
				
			||||||
		defaultArguments["cluster-cidr"] = cfg.Networking.PodSubnet
 | 
							defaultArguments = kubeadmapi.SetArgValues(defaultArguments, "cluster-cidr", cfg.Networking.PodSubnet, 1)
 | 
				
			||||||
		if cfg.Networking.ServiceSubnet != "" {
 | 
							if cfg.Networking.ServiceSubnet != "" {
 | 
				
			||||||
			defaultArguments["service-cluster-ip-range"] = cfg.Networking.ServiceSubnet
 | 
								defaultArguments = kubeadmapi.SetArgValues(defaultArguments, "service-cluster-ip-range", cfg.Networking.ServiceSubnet, 1)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Set cluster name
 | 
						// Set cluster name
 | 
				
			||||||
	if cfg.ClusterName != "" {
 | 
						if cfg.ClusterName != "" {
 | 
				
			||||||
		defaultArguments["cluster-name"] = cfg.ClusterName
 | 
							defaultArguments = kubeadmapi.SetArgValues(defaultArguments, "cluster-name", cfg.ClusterName, 1)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	command := []string{"kube-controller-manager"}
 | 
						command := []string{"kube-controller-manager"}
 | 
				
			||||||
	command = append(command, kubeadmutil.BuildArgumentListFromMap(defaultArguments, cfg.ControllerManager.ExtraArgs)...)
 | 
						command = append(command, kubeadmutil.ArgumentsToCommand(defaultArguments, cfg.ControllerManager.ExtraArgs)...)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return command
 | 
						return command
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -349,15 +351,15 @@ func getControllerManagerCommand(cfg *kubeadmapi.ClusterConfiguration) []string
 | 
				
			|||||||
// getSchedulerCommand builds the right scheduler command from the given config object and version
 | 
					// getSchedulerCommand builds the right scheduler command from the given config object and version
 | 
				
			||||||
func getSchedulerCommand(cfg *kubeadmapi.ClusterConfiguration) []string {
 | 
					func getSchedulerCommand(cfg *kubeadmapi.ClusterConfiguration) []string {
 | 
				
			||||||
	kubeconfigFile := filepath.Join(kubeadmconstants.KubernetesDir, kubeadmconstants.SchedulerKubeConfigFileName)
 | 
						kubeconfigFile := filepath.Join(kubeadmconstants.KubernetesDir, kubeadmconstants.SchedulerKubeConfigFileName)
 | 
				
			||||||
	defaultArguments := map[string]string{
 | 
						defaultArguments := []kubeadmapi.Arg{
 | 
				
			||||||
		"bind-address":              "127.0.0.1",
 | 
							{Name: "bind-address", Value: "127.0.0.1"},
 | 
				
			||||||
		"leader-elect":              "true",
 | 
							{Name: "leader-elect", Value: "true"},
 | 
				
			||||||
		"kubeconfig":                kubeconfigFile,
 | 
							{Name: "kubeconfig", Value: kubeconfigFile},
 | 
				
			||||||
		"authentication-kubeconfig": kubeconfigFile,
 | 
							{Name: "authentication-kubeconfig", Value: kubeconfigFile},
 | 
				
			||||||
		"authorization-kubeconfig":  kubeconfigFile,
 | 
							{Name: "authorization-kubeconfig", Value: kubeconfigFile},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	command := []string{"kube-scheduler"}
 | 
						command := []string{"kube-scheduler"}
 | 
				
			||||||
	command = append(command, kubeadmutil.BuildArgumentListFromMap(defaultArguments, cfg.Scheduler.ExtraArgs)...)
 | 
						command = append(command, kubeadmutil.ArgumentsToCommand(defaultArguments, cfg.Scheduler.ExtraArgs)...)
 | 
				
			||||||
	return command
 | 
						return command
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -375,11 +375,11 @@ func TestGetAPIServerCommand(t *testing.T) {
 | 
				
			|||||||
				CertificatesDir: testCertsDir,
 | 
									CertificatesDir: testCertsDir,
 | 
				
			||||||
				APIServer: kubeadmapi.APIServer{
 | 
									APIServer: kubeadmapi.APIServer{
 | 
				
			||||||
					ControlPlaneComponent: kubeadmapi.ControlPlaneComponent{
 | 
										ControlPlaneComponent: kubeadmapi.ControlPlaneComponent{
 | 
				
			||||||
						ExtraArgs: map[string]string{
 | 
											ExtraArgs: []kubeadmapi.Arg{
 | 
				
			||||||
							"service-cluster-ip-range": "baz",
 | 
												{Name: "service-cluster-ip-range", Value: "baz"},
 | 
				
			||||||
							"advertise-address":        "9.9.9.9",
 | 
												{Name: "advertise-address", Value: "9.9.9.9"},
 | 
				
			||||||
							"audit-policy-file":        "/etc/config/audit.yaml",
 | 
												{Name: "audit-policy-file", Value: "/etc/config/audit.yaml"},
 | 
				
			||||||
							"audit-log-path":           "/var/log/kubernetes",
 | 
												{Name: "audit-log-path", Value: "/var/log/kubernetes"},
 | 
				
			||||||
						},
 | 
											},
 | 
				
			||||||
					},
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
@@ -425,8 +425,8 @@ func TestGetAPIServerCommand(t *testing.T) {
 | 
				
			|||||||
				CertificatesDir: testCertsDir,
 | 
									CertificatesDir: testCertsDir,
 | 
				
			||||||
				APIServer: kubeadmapi.APIServer{
 | 
									APIServer: kubeadmapi.APIServer{
 | 
				
			||||||
					ControlPlaneComponent: kubeadmapi.ControlPlaneComponent{
 | 
										ControlPlaneComponent: kubeadmapi.ControlPlaneComponent{
 | 
				
			||||||
						ExtraArgs: map[string]string{
 | 
											ExtraArgs: []kubeadmapi.Arg{
 | 
				
			||||||
							"authorization-mode": kubeadmconstants.ModeABAC,
 | 
												{Name: "authorization-mode", Value: kubeadmconstants.ModeABAC},
 | 
				
			||||||
						},
 | 
											},
 | 
				
			||||||
					},
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
@@ -470,12 +470,12 @@ func TestGetAPIServerCommand(t *testing.T) {
 | 
				
			|||||||
				CertificatesDir: testCertsDir,
 | 
									CertificatesDir: testCertsDir,
 | 
				
			||||||
				APIServer: kubeadmapi.APIServer{
 | 
									APIServer: kubeadmapi.APIServer{
 | 
				
			||||||
					ControlPlaneComponent: kubeadmapi.ControlPlaneComponent{
 | 
										ControlPlaneComponent: kubeadmapi.ControlPlaneComponent{
 | 
				
			||||||
						ExtraArgs: map[string]string{
 | 
											ExtraArgs: []kubeadmapi.Arg{
 | 
				
			||||||
							"authorization-mode": strings.Join([]string{
 | 
												{Name: "authorization-mode", Value: strings.Join([]string{
 | 
				
			||||||
								kubeadmconstants.ModeNode,
 | 
													kubeadmconstants.ModeNode,
 | 
				
			||||||
								kubeadmconstants.ModeRBAC,
 | 
													kubeadmconstants.ModeRBAC,
 | 
				
			||||||
								kubeadmconstants.ModeWebhook,
 | 
													kubeadmconstants.ModeWebhook,
 | 
				
			||||||
							}, ","),
 | 
												}, ",")},
 | 
				
			||||||
						},
 | 
											},
 | 
				
			||||||
					},
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
@@ -660,7 +660,7 @@ func TestGetControllerManagerCommand(t *testing.T) {
 | 
				
			|||||||
			cfg: &kubeadmapi.ClusterConfiguration{
 | 
								cfg: &kubeadmapi.ClusterConfiguration{
 | 
				
			||||||
				Networking: kubeadmapi.Networking{PodSubnet: "10.0.1.15/16", DNSDomain: "cluster.local"},
 | 
									Networking: kubeadmapi.Networking{PodSubnet: "10.0.1.15/16", DNSDomain: "cluster.local"},
 | 
				
			||||||
				ControllerManager: kubeadmapi.ControlPlaneComponent{
 | 
									ControllerManager: kubeadmapi.ControlPlaneComponent{
 | 
				
			||||||
					ExtraArgs: map[string]string{"node-cidr-mask-size": "20"},
 | 
										ExtraArgs: []kubeadmapi.Arg{{Name: "node-cidr-mask-size", Value: "20"}},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
				CertificatesDir:   testCertsDir,
 | 
									CertificatesDir:   testCertsDir,
 | 
				
			||||||
				KubernetesVersion: cpVersion,
 | 
									KubernetesVersion: cpVersion,
 | 
				
			||||||
@@ -726,7 +726,7 @@ func TestGetControllerManagerCommand(t *testing.T) {
 | 
				
			|||||||
					DNSDomain:     "cluster.local",
 | 
										DNSDomain:     "cluster.local",
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
				ControllerManager: kubeadmapi.ControlPlaneComponent{
 | 
									ControllerManager: kubeadmapi.ControlPlaneComponent{
 | 
				
			||||||
					ExtraArgs: map[string]string{"allocate-node-cidrs": "false"},
 | 
										ExtraArgs: []kubeadmapi.Arg{{Name: "allocate-node-cidrs", Value: "false"}},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
				CertificatesDir:   testCertsDir,
 | 
									CertificatesDir:   testCertsDir,
 | 
				
			||||||
				KubernetesVersion: cpVersion,
 | 
									KubernetesVersion: cpVersion,
 | 
				
			||||||
@@ -790,7 +790,10 @@ func TestGetControllerManagerCommand(t *testing.T) {
 | 
				
			|||||||
					DNSDomain: "cluster.local",
 | 
										DNSDomain: "cluster.local",
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
				ControllerManager: kubeadmapi.ControlPlaneComponent{
 | 
									ControllerManager: kubeadmapi.ControlPlaneComponent{
 | 
				
			||||||
					ExtraArgs: map[string]string{"node-cidr-mask-size-ipv4": "20", "node-cidr-mask-size-ipv6": "80"},
 | 
										ExtraArgs: []kubeadmapi.Arg{
 | 
				
			||||||
 | 
											{Name: "node-cidr-mask-size-ipv4", Value: "20"},
 | 
				
			||||||
 | 
											{Name: "node-cidr-mask-size-ipv6", Value: "80"},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
				CertificatesDir:   testCertsDir,
 | 
									CertificatesDir:   testCertsDir,
 | 
				
			||||||
				KubernetesVersion: cpVersion,
 | 
									KubernetesVersion: cpVersion,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -72,8 +72,8 @@ func getHostPathVolumesForTheControlPlane(cfg *kubeadmapi.ClusterConfiguration)
 | 
				
			|||||||
	mounts.NewHostPathMount(kubeadmconstants.KubeControllerManager, kubeadmconstants.KubeConfigVolumeName, controllerManagerKubeConfigFile, controllerManagerKubeConfigFile, true, &hostPathFileOrCreate)
 | 
						mounts.NewHostPathMount(kubeadmconstants.KubeControllerManager, kubeadmconstants.KubeConfigVolumeName, controllerManagerKubeConfigFile, controllerManagerKubeConfigFile, true, &hostPathFileOrCreate)
 | 
				
			||||||
	// Mount for the flexvolume directory (/usr/libexec/kubernetes/kubelet-plugins/volume/exec by default)
 | 
						// Mount for the flexvolume directory (/usr/libexec/kubernetes/kubelet-plugins/volume/exec by default)
 | 
				
			||||||
	// Flexvolume dir must NOT be readonly as it is used for third-party plugins to integrate with their storage backends via unix domain socket.
 | 
						// Flexvolume dir must NOT be readonly as it is used for third-party plugins to integrate with their storage backends via unix domain socket.
 | 
				
			||||||
	flexvolumeDirVolumePath, ok := cfg.ControllerManager.ExtraArgs["flex-volume-plugin-dir"]
 | 
						flexvolumeDirVolumePath, idx := kubeadmapi.GetArgValue(cfg.ControllerManager.ExtraArgs, "flex-volume-plugin-dir", -1)
 | 
				
			||||||
	if !ok {
 | 
						if idx == -1 {
 | 
				
			||||||
		flexvolumeDirVolumePath = defaultFlexvolumeDirVolumePath
 | 
							flexvolumeDirVolumePath = defaultFlexvolumeDirVolumePath
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	mounts.NewHostPathMount(kubeadmconstants.KubeControllerManager, flexvolumeDirVolumeName, flexvolumeDirVolumePath, flexvolumeDirVolumePath, false, &hostPathDirectoryOrCreate)
 | 
						mounts.NewHostPathMount(kubeadmconstants.KubeControllerManager, flexvolumeDirVolumeName, flexvolumeDirVolumePath, flexvolumeDirVolumePath, false, &hostPathDirectoryOrCreate)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -239,31 +239,31 @@ func getEtcdCommand(cfg *kubeadmapi.ClusterConfiguration, endpoint *kubeadmapi.A
 | 
				
			|||||||
	if utilsnet.IsIPv6String(endpoint.AdvertiseAddress) {
 | 
						if utilsnet.IsIPv6String(endpoint.AdvertiseAddress) {
 | 
				
			||||||
		etcdLocalhostAddress = "::1"
 | 
							etcdLocalhostAddress = "::1"
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	defaultArguments := map[string]string{
 | 
						defaultArguments := []kubeadmapi.Arg{
 | 
				
			||||||
		"name": nodeName,
 | 
							{Name: "name", Value: nodeName},
 | 
				
			||||||
		// TODO: start using --initial-corrupt-check once the graduated flag is available:
 | 
							// TODO: start using --initial-corrupt-check once the graduated flag is available,
 | 
				
			||||||
		// https://github.com/kubernetes/kubeadm/issues/2676
 | 
							// https://github.com/kubernetes/kubeadm/issues/2676
 | 
				
			||||||
		"experimental-initial-corrupt-check": "true",
 | 
							{Name: "experimental-initial-corrupt-check", Value: "true"},
 | 
				
			||||||
		"listen-client-urls":                 fmt.Sprintf("%s,%s", etcdutil.GetClientURLByIP(etcdLocalhostAddress), etcdutil.GetClientURL(endpoint)),
 | 
							{Name: "listen-client-urls", Value: fmt.Sprintf("%s,%s", etcdutil.GetClientURLByIP(etcdLocalhostAddress), etcdutil.GetClientURL(endpoint))},
 | 
				
			||||||
		"advertise-client-urls":              etcdutil.GetClientURL(endpoint),
 | 
							{Name: "advertise-client-urls", Value: etcdutil.GetClientURL(endpoint)},
 | 
				
			||||||
		"listen-peer-urls":                   etcdutil.GetPeerURL(endpoint),
 | 
							{Name: "listen-peer-urls", Value: etcdutil.GetPeerURL(endpoint)},
 | 
				
			||||||
		"initial-advertise-peer-urls":        etcdutil.GetPeerURL(endpoint),
 | 
							{Name: "initial-advertise-peer-urls", Value: etcdutil.GetPeerURL(endpoint)},
 | 
				
			||||||
		"data-dir":                           cfg.Etcd.Local.DataDir,
 | 
							{Name: "data-dir", Value: cfg.Etcd.Local.DataDir},
 | 
				
			||||||
		"cert-file":                          filepath.Join(cfg.CertificatesDir, kubeadmconstants.EtcdServerCertName),
 | 
							{Name: "cert-file", Value: filepath.Join(cfg.CertificatesDir, kubeadmconstants.EtcdServerCertName)},
 | 
				
			||||||
		"key-file":                           filepath.Join(cfg.CertificatesDir, kubeadmconstants.EtcdServerKeyName),
 | 
							{Name: "key-file", Value: filepath.Join(cfg.CertificatesDir, kubeadmconstants.EtcdServerKeyName)},
 | 
				
			||||||
		"trusted-ca-file":                    filepath.Join(cfg.CertificatesDir, kubeadmconstants.EtcdCACertName),
 | 
							{Name: "trusted-ca-file", Value: filepath.Join(cfg.CertificatesDir, kubeadmconstants.EtcdCACertName)},
 | 
				
			||||||
		"client-cert-auth":                   "true",
 | 
							{Name: "client-cert-auth", Value: "true"},
 | 
				
			||||||
		"peer-cert-file":                     filepath.Join(cfg.CertificatesDir, kubeadmconstants.EtcdPeerCertName),
 | 
							{Name: "peer-cert-file", Value: filepath.Join(cfg.CertificatesDir, kubeadmconstants.EtcdPeerCertName)},
 | 
				
			||||||
		"peer-key-file":                      filepath.Join(cfg.CertificatesDir, kubeadmconstants.EtcdPeerKeyName),
 | 
							{Name: "peer-key-file", Value: filepath.Join(cfg.CertificatesDir, kubeadmconstants.EtcdPeerKeyName)},
 | 
				
			||||||
		"peer-trusted-ca-file":               filepath.Join(cfg.CertificatesDir, kubeadmconstants.EtcdCACertName),
 | 
							{Name: "peer-trusted-ca-file", Value: filepath.Join(cfg.CertificatesDir, kubeadmconstants.EtcdCACertName)},
 | 
				
			||||||
		"peer-client-cert-auth":              "true",
 | 
							{Name: "peer-client-cert-auth", Value: "true"},
 | 
				
			||||||
		"snapshot-count":                     "10000",
 | 
							{Name: "snapshot-count", Value: "10000"},
 | 
				
			||||||
		"listen-metrics-urls":                fmt.Sprintf("http://%s", net.JoinHostPort(etcdLocalhostAddress, strconv.Itoa(kubeadmconstants.EtcdMetricsPort))),
 | 
							{Name: "listen-metrics-urls", Value: fmt.Sprintf("http://%s", net.JoinHostPort(etcdLocalhostAddress, strconv.Itoa(kubeadmconstants.EtcdMetricsPort)))},
 | 
				
			||||||
		"experimental-watch-progress-notify-interval": "5s",
 | 
							{Name: "experimental-watch-progress-notify-interval", Value: "5s"},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if len(initialCluster) == 0 {
 | 
						if len(initialCluster) == 0 {
 | 
				
			||||||
		defaultArguments["initial-cluster"] = fmt.Sprintf("%s=%s", nodeName, etcdutil.GetPeerURL(endpoint))
 | 
							defaultArguments = kubeadmapi.SetArgValues(defaultArguments, "initial-cluster", fmt.Sprintf("%s=%s", nodeName, etcdutil.GetPeerURL(endpoint)), 1)
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		// NB. the joining etcd member should be part of the initialCluster list
 | 
							// NB. the joining etcd member should be part of the initialCluster list
 | 
				
			||||||
		endpoints := []string{}
 | 
							endpoints := []string{}
 | 
				
			||||||
@@ -271,12 +271,12 @@ func getEtcdCommand(cfg *kubeadmapi.ClusterConfiguration, endpoint *kubeadmapi.A
 | 
				
			|||||||
			endpoints = append(endpoints, fmt.Sprintf("%s=%s", member.Name, member.PeerURL))
 | 
								endpoints = append(endpoints, fmt.Sprintf("%s=%s", member.Name, member.PeerURL))
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		defaultArguments["initial-cluster"] = strings.Join(endpoints, ",")
 | 
							defaultArguments = kubeadmapi.SetArgValues(defaultArguments, "initial-cluster", strings.Join(endpoints, ","), 1)
 | 
				
			||||||
		defaultArguments["initial-cluster-state"] = "existing"
 | 
							defaultArguments = kubeadmapi.SetArgValues(defaultArguments, "initial-cluster-state", "existing", 1)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	command := []string{"etcd"}
 | 
						command := []string{"etcd"}
 | 
				
			||||||
	command = append(command, kubeadmutil.BuildArgumentListFromMap(defaultArguments, cfg.Etcd.Local.ExtraArgs)...)
 | 
						command = append(command, kubeadmutil.ArgumentsToCommand(defaultArguments, cfg.Etcd.Local.ExtraArgs)...)
 | 
				
			||||||
	return command
 | 
						return command
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -176,7 +176,7 @@ func TestGetEtcdCommand(t *testing.T) {
 | 
				
			|||||||
		name             string
 | 
							name             string
 | 
				
			||||||
		advertiseAddress string
 | 
							advertiseAddress string
 | 
				
			||||||
		nodeName         string
 | 
							nodeName         string
 | 
				
			||||||
		extraArgs        map[string]string
 | 
							extraArgs        []kubeadmapi.Arg
 | 
				
			||||||
		initialCluster   []etcdutil.Member
 | 
							initialCluster   []etcdutil.Member
 | 
				
			||||||
		expected         []string
 | 
							expected         []string
 | 
				
			||||||
	}{
 | 
						}{
 | 
				
			||||||
@@ -243,9 +243,9 @@ func TestGetEtcdCommand(t *testing.T) {
 | 
				
			|||||||
			name:             "Extra args",
 | 
								name:             "Extra args",
 | 
				
			||||||
			advertiseAddress: "1.2.3.4",
 | 
								advertiseAddress: "1.2.3.4",
 | 
				
			||||||
			nodeName:         "bar",
 | 
								nodeName:         "bar",
 | 
				
			||||||
			extraArgs: map[string]string{
 | 
								extraArgs: []kubeadmapi.Arg{
 | 
				
			||||||
				"listen-client-urls":    "https://10.0.1.10:2379",
 | 
									{Name: "listen-client-urls", Value: "https://10.0.1.10:2379"},
 | 
				
			||||||
				"advertise-client-urls": "https://10.0.1.10:2379",
 | 
									{Name: "advertise-client-urls", Value: "https://10.0.1.10:2379"},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			expected: []string{
 | 
								expected: []string{
 | 
				
			||||||
				"etcd",
 | 
									"etcd",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -51,7 +51,7 @@ func GetNodeNameAndHostname(cfg *kubeadmapi.NodeRegistrationOptions) (string, st
 | 
				
			|||||||
	if cfg.Name != "" {
 | 
						if cfg.Name != "" {
 | 
				
			||||||
		nodeName = cfg.Name
 | 
							nodeName = cfg.Name
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if name, ok := cfg.KubeletExtraArgs["hostname-override"]; ok {
 | 
						if name, idx := kubeadmapi.GetArgValue(cfg.KubeletExtraArgs, "hostname-override", -1); idx > -1 {
 | 
				
			||||||
		nodeName = name
 | 
							nodeName = name
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return nodeName, hostname, err
 | 
						return nodeName, hostname, err
 | 
				
			||||||
@@ -65,23 +65,23 @@ func WriteKubeletDynamicEnvFile(cfg *kubeadmapi.ClusterConfiguration, nodeReg *k
 | 
				
			|||||||
		pauseImage:               images.GetPauseImage(cfg),
 | 
							pauseImage:               images.GetPauseImage(cfg),
 | 
				
			||||||
		registerTaintsUsingFlags: registerTaintsUsingFlags,
 | 
							registerTaintsUsingFlags: registerTaintsUsingFlags,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	stringMap := buildKubeletArgMap(flagOpts)
 | 
						stringMap := buildKubeletArgs(flagOpts)
 | 
				
			||||||
	argList := kubeadmutil.BuildArgumentListFromMap(stringMap, nodeReg.KubeletExtraArgs)
 | 
						argList := kubeadmutil.ArgumentsToCommand(stringMap, nodeReg.KubeletExtraArgs)
 | 
				
			||||||
	envFileContent := fmt.Sprintf("%s=%q\n", constants.KubeletEnvFileVariableName, strings.Join(argList, " "))
 | 
						envFileContent := fmt.Sprintf("%s=%q\n", constants.KubeletEnvFileVariableName, strings.Join(argList, " "))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return writeKubeletFlagBytesToDisk([]byte(envFileContent), kubeletDir)
 | 
						return writeKubeletFlagBytesToDisk([]byte(envFileContent), kubeletDir)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// buildKubeletArgMapCommon takes a kubeletFlagsOpts object and builds based on that a string-string map with flags
 | 
					// buildKubeletArgsCommon takes a kubeletFlagsOpts object and builds based on that a slice of arguments
 | 
				
			||||||
// that are common to both Linux and Windows
 | 
					// that are common to both Linux and Windows
 | 
				
			||||||
func buildKubeletArgMapCommon(opts kubeletFlagsOpts) map[string]string {
 | 
					func buildKubeletArgsCommon(opts kubeletFlagsOpts) []kubeadmapi.Arg {
 | 
				
			||||||
	kubeletFlags := map[string]string{}
 | 
						kubeletFlags := []kubeadmapi.Arg{}
 | 
				
			||||||
	kubeletFlags["container-runtime-endpoint"] = opts.nodeRegOpts.CRISocket
 | 
						kubeletFlags = append(kubeletFlags, kubeadmapi.Arg{Name: "container-runtime-endpoint", Value: opts.nodeRegOpts.CRISocket})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// This flag passes the pod infra container image (e.g. "pause" image) to the kubelet
 | 
						// This flag passes the pod infra container image (e.g. "pause" image) to the kubelet
 | 
				
			||||||
	// and prevents its garbage collection
 | 
						// and prevents its garbage collection
 | 
				
			||||||
	if opts.pauseImage != "" {
 | 
						if opts.pauseImage != "" {
 | 
				
			||||||
		kubeletFlags["pod-infra-container-image"] = opts.pauseImage
 | 
							kubeletFlags = append(kubeletFlags, kubeadmapi.Arg{Name: "pod-infra-container-image", Value: opts.pauseImage})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if opts.registerTaintsUsingFlags && opts.nodeRegOpts.Taints != nil && len(opts.nodeRegOpts.Taints) > 0 {
 | 
						if opts.registerTaintsUsingFlags && opts.nodeRegOpts.Taints != nil && len(opts.nodeRegOpts.Taints) > 0 {
 | 
				
			||||||
@@ -89,8 +89,7 @@ func buildKubeletArgMapCommon(opts kubeletFlagsOpts) map[string]string {
 | 
				
			|||||||
		for _, taint := range opts.nodeRegOpts.Taints {
 | 
							for _, taint := range opts.nodeRegOpts.Taints {
 | 
				
			||||||
			taintStrs = append(taintStrs, taint.ToString())
 | 
								taintStrs = append(taintStrs, taint.ToString())
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							kubeletFlags = append(kubeletFlags, kubeadmapi.Arg{Name: "register-with-taints", Value: strings.Join(taintStrs, ",")})
 | 
				
			||||||
		kubeletFlags["register-with-taints"] = strings.Join(taintStrs, ",")
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Pass the "--hostname-override" flag to the kubelet only if it's different from the hostname
 | 
						// Pass the "--hostname-override" flag to the kubelet only if it's different from the hostname
 | 
				
			||||||
@@ -100,7 +99,7 @@ func buildKubeletArgMapCommon(opts kubeletFlagsOpts) map[string]string {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	if nodeName != hostname {
 | 
						if nodeName != hostname {
 | 
				
			||||||
		klog.V(1).Infof("setting kubelet hostname-override to %q", nodeName)
 | 
							klog.V(1).Infof("setting kubelet hostname-override to %q", nodeName)
 | 
				
			||||||
		kubeletFlags["hostname-override"] = nodeName
 | 
							kubeletFlags = append(kubeletFlags, kubeadmapi.Arg{Name: "hostname-override", Value: nodeName})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return kubeletFlags
 | 
						return kubeletFlags
 | 
				
			||||||
@@ -121,8 +120,8 @@ func writeKubeletFlagBytesToDisk(b []byte, kubeletDir string) error {
 | 
				
			|||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// buildKubeletArgMap takes a kubeletFlagsOpts object and builds based on that a string-string map with flags
 | 
					// buildKubeletArgs takes a kubeletFlagsOpts object and builds based on that a slice of arguments
 | 
				
			||||||
// that should be given to the local kubelet daemon.
 | 
					// that should be given to the local kubelet daemon.
 | 
				
			||||||
func buildKubeletArgMap(opts kubeletFlagsOpts) map[string]string {
 | 
					func buildKubeletArgs(opts kubeletFlagsOpts) []kubeadmapi.Arg {
 | 
				
			||||||
	return buildKubeletArgMapCommon(opts)
 | 
						return buildKubeletArgsCommon(opts)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,23 +27,25 @@ import (
 | 
				
			|||||||
	kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
 | 
						kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestBuildKubeletArgMap(t *testing.T) {
 | 
					func TestBuildKubeletArgs(t *testing.T) {
 | 
				
			||||||
	tests := []struct {
 | 
						tests := []struct {
 | 
				
			||||||
		name     string
 | 
							name     string
 | 
				
			||||||
		opts     kubeletFlagsOpts
 | 
							opts     kubeletFlagsOpts
 | 
				
			||||||
		expected map[string]string
 | 
							expected []kubeadmapi.Arg
 | 
				
			||||||
	}{
 | 
						}{
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			name: "hostname override",
 | 
								name: "hostname override",
 | 
				
			||||||
			opts: kubeletFlagsOpts{
 | 
								opts: kubeletFlagsOpts{
 | 
				
			||||||
				nodeRegOpts: &kubeadmapi.NodeRegistrationOptions{
 | 
									nodeRegOpts: &kubeadmapi.NodeRegistrationOptions{
 | 
				
			||||||
					CRISocket:        "unix:///var/run/containerd/containerd.sock",
 | 
										CRISocket: "unix:///var/run/containerd/containerd.sock",
 | 
				
			||||||
					KubeletExtraArgs: map[string]string{"hostname-override": "override-name"},
 | 
										KubeletExtraArgs: []kubeadmapi.Arg{
 | 
				
			||||||
 | 
											{Name: "hostname-override", Value: "override-name"},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			expected: map[string]string{
 | 
								expected: []kubeadmapi.Arg{
 | 
				
			||||||
				"container-runtime-endpoint": "unix:///var/run/containerd/containerd.sock",
 | 
									{Name: "container-runtime-endpoint", Value: "unix:///var/run/containerd/containerd.sock"},
 | 
				
			||||||
				"hostname-override":          "override-name",
 | 
									{Name: "hostname-override", Value: "override-name"},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
@@ -66,9 +68,9 @@ func TestBuildKubeletArgMap(t *testing.T) {
 | 
				
			|||||||
				},
 | 
									},
 | 
				
			||||||
				registerTaintsUsingFlags: true,
 | 
									registerTaintsUsingFlags: true,
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			expected: map[string]string{
 | 
								expected: []kubeadmapi.Arg{
 | 
				
			||||||
				"container-runtime-endpoint": "unix:///var/run/containerd/containerd.sock",
 | 
									{Name: "container-runtime-endpoint", Value: "unix:///var/run/containerd/containerd.sock"},
 | 
				
			||||||
				"register-with-taints":       "foo=bar:baz,key=val:eff",
 | 
									{Name: "register-with-taints", Value: "foo=bar:baz,key=val:eff"},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
@@ -79,19 +81,19 @@ func TestBuildKubeletArgMap(t *testing.T) {
 | 
				
			|||||||
				},
 | 
									},
 | 
				
			||||||
				pauseImage: "registry.k8s.io/pause:3.9",
 | 
									pauseImage: "registry.k8s.io/pause:3.9",
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			expected: map[string]string{
 | 
								expected: []kubeadmapi.Arg{
 | 
				
			||||||
				"container-runtime-endpoint": "unix:///var/run/containerd/containerd.sock",
 | 
									{Name: "container-runtime-endpoint", Value: "unix:///var/run/containerd/containerd.sock"},
 | 
				
			||||||
				"pod-infra-container-image":  "registry.k8s.io/pause:3.9",
 | 
									{Name: "pod-infra-container-image", Value: "registry.k8s.io/pause:3.9"},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, test := range tests {
 | 
						for _, test := range tests {
 | 
				
			||||||
		t.Run(test.name, func(t *testing.T) {
 | 
							t.Run(test.name, func(t *testing.T) {
 | 
				
			||||||
			actual := buildKubeletArgMap(test.opts)
 | 
								actual := buildKubeletArgs(test.opts)
 | 
				
			||||||
			if !reflect.DeepEqual(actual, test.expected) {
 | 
								if !reflect.DeepEqual(actual, test.expected) {
 | 
				
			||||||
				t.Errorf(
 | 
									t.Errorf(
 | 
				
			||||||
					"failed buildKubeletArgMap:\n\texpected: %v\n\t  actual: %v",
 | 
										"failed buildKubeletArgs:\n\texpected: %v\n\t  actual: %v",
 | 
				
			||||||
					test.expected,
 | 
										test.expected,
 | 
				
			||||||
					actual,
 | 
										actual,
 | 
				
			||||||
				)
 | 
									)
 | 
				
			||||||
@@ -116,7 +118,9 @@ func TestGetNodeNameAndHostname(t *testing.T) {
 | 
				
			|||||||
			name: "overridden hostname",
 | 
								name: "overridden hostname",
 | 
				
			||||||
			opts: kubeletFlagsOpts{
 | 
								opts: kubeletFlagsOpts{
 | 
				
			||||||
				nodeRegOpts: &kubeadmapi.NodeRegistrationOptions{
 | 
									nodeRegOpts: &kubeadmapi.NodeRegistrationOptions{
 | 
				
			||||||
					KubeletExtraArgs: map[string]string{"hostname-override": "override-name"},
 | 
										KubeletExtraArgs: []kubeadmapi.Arg{
 | 
				
			||||||
 | 
											{Name: "hostname-override", Value: "override-name"},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			expectedNodeName: "override-name",
 | 
								expectedNodeName: "override-name",
 | 
				
			||||||
@@ -126,7 +130,9 @@ func TestGetNodeNameAndHostname(t *testing.T) {
 | 
				
			|||||||
			name: "overridden hostname uppercase",
 | 
								name: "overridden hostname uppercase",
 | 
				
			||||||
			opts: kubeletFlagsOpts{
 | 
								opts: kubeletFlagsOpts{
 | 
				
			||||||
				nodeRegOpts: &kubeadmapi.NodeRegistrationOptions{
 | 
									nodeRegOpts: &kubeadmapi.NodeRegistrationOptions{
 | 
				
			||||||
					KubeletExtraArgs: map[string]string{"hostname-override": "OVERRIDE-NAME"},
 | 
										KubeletExtraArgs: []kubeadmapi.Arg{
 | 
				
			||||||
 | 
											{Name: "hostname-override", Value: "OVERRIDE-NAME"},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			expectedNodeName: "OVERRIDE-NAME",
 | 
								expectedNodeName: "OVERRIDE-NAME",
 | 
				
			||||||
@@ -136,7 +142,9 @@ func TestGetNodeNameAndHostname(t *testing.T) {
 | 
				
			|||||||
			name: "hostname contains only spaces",
 | 
								name: "hostname contains only spaces",
 | 
				
			||||||
			opts: kubeletFlagsOpts{
 | 
								opts: kubeletFlagsOpts{
 | 
				
			||||||
				nodeRegOpts: &kubeadmapi.NodeRegistrationOptions{
 | 
									nodeRegOpts: &kubeadmapi.NodeRegistrationOptions{
 | 
				
			||||||
					KubeletExtraArgs: map[string]string{"hostname-override": " "},
 | 
										KubeletExtraArgs: []kubeadmapi.Arg{
 | 
				
			||||||
 | 
											{Name: "hostname-override", Value: " "},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			expectedNodeName: " ",
 | 
								expectedNodeName: " ",
 | 
				
			||||||
@@ -146,7 +154,9 @@ func TestGetNodeNameAndHostname(t *testing.T) {
 | 
				
			|||||||
			name: "empty parameter",
 | 
								name: "empty parameter",
 | 
				
			||||||
			opts: kubeletFlagsOpts{
 | 
								opts: kubeletFlagsOpts{
 | 
				
			||||||
				nodeRegOpts: &kubeadmapi.NodeRegistrationOptions{
 | 
									nodeRegOpts: &kubeadmapi.NodeRegistrationOptions{
 | 
				
			||||||
					KubeletExtraArgs: map[string]string{"hostname-override": ""},
 | 
										KubeletExtraArgs: []kubeadmapi.Arg{
 | 
				
			||||||
 | 
											{Name: "hostname-override", Value: ""},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			expectedNodeName: "",
 | 
								expectedNodeName: "",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,41 +24,54 @@ import (
 | 
				
			|||||||
	"github.com/pkg/errors"
 | 
						"github.com/pkg/errors"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"k8s.io/klog/v2"
 | 
						"k8s.io/klog/v2"
 | 
				
			||||||
 | 
						kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// BuildArgumentListFromMap takes two string-string maps, one with the base arguments and one
 | 
					// ArgumentsToCommand takes two Arg slices, one with the base arguments and one
 | 
				
			||||||
// with optional override arguments. In the return list override arguments will precede base
 | 
					// with optional override arguments. In the return list override arguments will precede base
 | 
				
			||||||
// arguments
 | 
					// arguments. If an argument is present in the overrides, it will cause
 | 
				
			||||||
func BuildArgumentListFromMap(baseArguments map[string]string, overrideArguments map[string]string) []string {
 | 
					// all instances of the same argument in the base list to be discarded, leaving
 | 
				
			||||||
 | 
					// only the instances of this argument in the overrides to be applied.
 | 
				
			||||||
 | 
					func ArgumentsToCommand(base []kubeadmapi.Arg, overrides []kubeadmapi.Arg) []string {
 | 
				
			||||||
	var command []string
 | 
						var command []string
 | 
				
			||||||
	var keys []string
 | 
						// Copy the base arguments into a new slice.
 | 
				
			||||||
 | 
						args := make([]kubeadmapi.Arg, len(base))
 | 
				
			||||||
 | 
						copy(args, base)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	argsMap := make(map[string]string)
 | 
						// Go trough the override arguments and delete all instances of arguments with the same name
 | 
				
			||||||
 | 
						// in the base list of arguments.
 | 
				
			||||||
	for k, v := range baseArguments {
 | 
						for i := 0; i < len(overrides); i++ {
 | 
				
			||||||
		argsMap[k] = v
 | 
						repeat:
 | 
				
			||||||
 | 
							for j := 0; j < len(args); j++ {
 | 
				
			||||||
 | 
								if overrides[i].Name == args[j].Name {
 | 
				
			||||||
 | 
									// Remove this existing argument and search for another argument
 | 
				
			||||||
 | 
									// with the same name in base.
 | 
				
			||||||
 | 
									args = append(args[:j], args[j+1:]...)
 | 
				
			||||||
 | 
									goto repeat
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for k, v := range overrideArguments {
 | 
						// Concatenate the overrides and the base arguments and then sort them.
 | 
				
			||||||
		argsMap[k] = v
 | 
						args = append(args, overrides...)
 | 
				
			||||||
	}
 | 
						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
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for k := range argsMap {
 | 
						for _, arg := range args {
 | 
				
			||||||
		keys = append(keys, k)
 | 
							command = append(command, fmt.Sprintf("--%s=%s", arg.Name, arg.Value))
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	sort.Strings(keys)
 | 
					 | 
				
			||||||
	for _, k := range keys {
 | 
					 | 
				
			||||||
		command = append(command, fmt.Sprintf("--%s=%s", k, argsMap[k]))
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return command
 | 
						return command
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ParseArgumentListToMap parses a CLI argument list in the form "--foo=bar" to a string-string map
 | 
					// ArgumentsFromCommand parses a CLI command in the form "--foo=bar" to an Arg slice
 | 
				
			||||||
func ParseArgumentListToMap(arguments []string) map[string]string {
 | 
					func ArgumentsFromCommand(command []string) []kubeadmapi.Arg {
 | 
				
			||||||
	resultingMap := map[string]string{}
 | 
						args := []kubeadmapi.Arg{}
 | 
				
			||||||
	for i, arg := range arguments {
 | 
						for i, arg := range command {
 | 
				
			||||||
		key, val, err := parseArgument(arg)
 | 
							key, val, err := parseArgument(arg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Ignore if the first argument doesn't satisfy the criteria, it's most often the binary name
 | 
							// Ignore if the first argument doesn't satisfy the criteria, it's most often the binary name
 | 
				
			||||||
@@ -70,24 +83,16 @@ func ParseArgumentListToMap(arguments []string) map[string]string {
 | 
				
			|||||||
			continue
 | 
								continue
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		resultingMap[key] = val
 | 
							args = append(args, kubeadmapi.Arg{Name: key, Value: val})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return resultingMap
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ReplaceArgument gets a command list; converts it to a map for easier modification, runs the provided function that
 | 
						sort.Slice(args, func(i, j int) bool {
 | 
				
			||||||
// returns a new modified map, and then converts the map back to a command string slice
 | 
							if args[i].Name == args[j].Name {
 | 
				
			||||||
func ReplaceArgument(command []string, argMutateFunc func(map[string]string) map[string]string) []string {
 | 
								return args[i].Value < args[j].Value
 | 
				
			||||||
	argMap := ParseArgumentListToMap(command)
 | 
							}
 | 
				
			||||||
 | 
							return args[i].Name < args[j].Name
 | 
				
			||||||
	// Save the first command (the executable) if we're sure it's not an argument (i.e. no --)
 | 
						})
 | 
				
			||||||
	var newCommand []string
 | 
						return args
 | 
				
			||||||
	if len(command) > 0 && !strings.HasPrefix(command[0], "--") {
 | 
					 | 
				
			||||||
		newCommand = append(newCommand, command[0])
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	newArgMap := argMutateFunc(argMap)
 | 
					 | 
				
			||||||
	newCommand = append(newCommand, BuildArgumentListFromMap(newArgMap, map[string]string{})...)
 | 
					 | 
				
			||||||
	return newCommand
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// parseArgument parses the argument "--foo=bar" to "foo" and "bar"
 | 
					// parseArgument parses the argument "--foo=bar" to "foo" and "bar"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,23 +20,25 @@ import (
 | 
				
			|||||||
	"reflect"
 | 
						"reflect"
 | 
				
			||||||
	"sort"
 | 
						"sort"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestBuildArgumentListFromMap(t *testing.T) {
 | 
					func TestArgumentsToCommand(t *testing.T) {
 | 
				
			||||||
	var tests = []struct {
 | 
						var tests = []struct {
 | 
				
			||||||
		name      string
 | 
							name      string
 | 
				
			||||||
		base      map[string]string
 | 
							base      []kubeadmapi.Arg
 | 
				
			||||||
		overrides map[string]string
 | 
							overrides []kubeadmapi.Arg
 | 
				
			||||||
		expected  []string
 | 
							expected  []string
 | 
				
			||||||
	}{
 | 
						}{
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			name: "override an argument from the base",
 | 
								name: "override an argument from the base",
 | 
				
			||||||
			base: map[string]string{
 | 
								base: []kubeadmapi.Arg{
 | 
				
			||||||
				"admission-control": "NamespaceLifecycle",
 | 
									{Name: "admission-control", Value: "NamespaceLifecycle"},
 | 
				
			||||||
				"allow-privileged":  "true",
 | 
									{Name: "allow-privileged", Value: "true"},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			overrides: map[string]string{
 | 
								overrides: []kubeadmapi.Arg{
 | 
				
			||||||
				"admission-control": "NamespaceLifecycle,LimitRanger",
 | 
									{Name: "admission-control", Value: "NamespaceLifecycle,LimitRanger"},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			expected: []string{
 | 
								expected: []string{
 | 
				
			||||||
				"--admission-control=NamespaceLifecycle,LimitRanger",
 | 
									"--admission-control=NamespaceLifecycle,LimitRanger",
 | 
				
			||||||
@@ -44,12 +46,43 @@ func TestBuildArgumentListFromMap(t *testing.T) {
 | 
				
			|||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			name: "add an argument that is not in base",
 | 
								name: "override an argument from the base and add duplicate",
 | 
				
			||||||
			base: map[string]string{
 | 
								base: []kubeadmapi.Arg{
 | 
				
			||||||
				"allow-privileged": "true",
 | 
									{Name: "token-auth-file", Value: "/token"},
 | 
				
			||||||
 | 
									{Name: "tls-sni-cert-key", Value: "/some/path/"},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			overrides: map[string]string{
 | 
								overrides: []kubeadmapi.Arg{
 | 
				
			||||||
				"admission-control": "NamespaceLifecycle,LimitRanger",
 | 
									{Name: "tls-sni-cert-key", Value: "/some/new/path"},
 | 
				
			||||||
 | 
									{Name: "tls-sni-cert-key", Value: "/some/new/path/subpath"},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								expected: []string{
 | 
				
			||||||
 | 
									"--tls-sni-cert-key=/some/new/path",
 | 
				
			||||||
 | 
									"--tls-sni-cert-key=/some/new/path/subpath",
 | 
				
			||||||
 | 
									"--token-auth-file=/token",
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name: "override all duplicate arguments from base",
 | 
				
			||||||
 | 
								base: []kubeadmapi.Arg{
 | 
				
			||||||
 | 
									{Name: "token-auth-file", Value: "/token"},
 | 
				
			||||||
 | 
									{Name: "tls-sni-cert-key", Value: "foo"},
 | 
				
			||||||
 | 
									{Name: "tls-sni-cert-key", Value: "bar"},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								overrides: []kubeadmapi.Arg{
 | 
				
			||||||
 | 
									{Name: "tls-sni-cert-key", Value: "/some/new/path"},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								expected: []string{
 | 
				
			||||||
 | 
									"--tls-sni-cert-key=/some/new/path",
 | 
				
			||||||
 | 
									"--token-auth-file=/token",
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name: "add an argument that is not in base",
 | 
				
			||||||
 | 
								base: []kubeadmapi.Arg{
 | 
				
			||||||
 | 
									{Name: "allow-privileged", Value: "true"},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								overrides: []kubeadmapi.Arg{
 | 
				
			||||||
 | 
									{Name: "admission-control", Value: "NamespaceLifecycle,LimitRanger"},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			expected: []string{
 | 
								expected: []string{
 | 
				
			||||||
				"--admission-control=NamespaceLifecycle,LimitRanger",
 | 
									"--admission-control=NamespaceLifecycle,LimitRanger",
 | 
				
			||||||
@@ -58,12 +91,12 @@ func TestBuildArgumentListFromMap(t *testing.T) {
 | 
				
			|||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			name: "allow empty strings in base",
 | 
								name: "allow empty strings in base",
 | 
				
			||||||
			base: map[string]string{
 | 
								base: []kubeadmapi.Arg{
 | 
				
			||||||
				"allow-privileged":                   "true",
 | 
									{Name: "allow-privileged", Value: "true"},
 | 
				
			||||||
				"something-that-allows-empty-string": "",
 | 
									{Name: "something-that-allows-empty-string", Value: ""},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			overrides: map[string]string{
 | 
								overrides: []kubeadmapi.Arg{
 | 
				
			||||||
				"admission-control": "NamespaceLifecycle,LimitRanger",
 | 
									{Name: "admission-control", Value: "NamespaceLifecycle,LimitRanger"},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			expected: []string{
 | 
								expected: []string{
 | 
				
			||||||
				"--admission-control=NamespaceLifecycle,LimitRanger",
 | 
									"--admission-control=NamespaceLifecycle,LimitRanger",
 | 
				
			||||||
@@ -73,13 +106,13 @@ func TestBuildArgumentListFromMap(t *testing.T) {
 | 
				
			|||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			name: "allow empty strings in overrides",
 | 
								name: "allow empty strings in overrides",
 | 
				
			||||||
			base: map[string]string{
 | 
								base: []kubeadmapi.Arg{
 | 
				
			||||||
				"allow-privileged":                   "true",
 | 
									{Name: "allow-privileged", Value: "true"},
 | 
				
			||||||
				"something-that-allows-empty-string": "foo",
 | 
									{Name: "something-that-allows-empty-string", Value: "foo"},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			overrides: map[string]string{
 | 
								overrides: []kubeadmapi.Arg{
 | 
				
			||||||
				"admission-control":                  "NamespaceLifecycle,LimitRanger",
 | 
									{Name: "admission-control", Value: "NamespaceLifecycle,LimitRanger"},
 | 
				
			||||||
				"something-that-allows-empty-string": "",
 | 
									{Name: "something-that-allows-empty-string", Value: ""},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			expected: []string{
 | 
								expected: []string{
 | 
				
			||||||
				"--admission-control=NamespaceLifecycle,LimitRanger",
 | 
									"--admission-control=NamespaceLifecycle,LimitRanger",
 | 
				
			||||||
@@ -91,19 +124,19 @@ func TestBuildArgumentListFromMap(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	for _, rt := range tests {
 | 
						for _, rt := range tests {
 | 
				
			||||||
		t.Run(rt.name, func(t *testing.T) {
 | 
							t.Run(rt.name, func(t *testing.T) {
 | 
				
			||||||
			actual := BuildArgumentListFromMap(rt.base, rt.overrides)
 | 
								actual := ArgumentsToCommand(rt.base, rt.overrides)
 | 
				
			||||||
			if !reflect.DeepEqual(actual, rt.expected) {
 | 
								if !reflect.DeepEqual(actual, rt.expected) {
 | 
				
			||||||
				t.Errorf("failed BuildArgumentListFromMap:\nexpected:\n%v\nsaw:\n%v", rt.expected, actual)
 | 
									t.Errorf("failed ArgumentsToCommand:\nexpected:\n%v\nsaw:\n%v", rt.expected, actual)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestParseArgumentListToMap(t *testing.T) {
 | 
					func TestArgumentsFromCommand(t *testing.T) {
 | 
				
			||||||
	var tests = []struct {
 | 
						var tests = []struct {
 | 
				
			||||||
		name        string
 | 
							name     string
 | 
				
			||||||
		args        []string
 | 
							args     []string
 | 
				
			||||||
		expectedMap map[string]string
 | 
							expected []kubeadmapi.Arg
 | 
				
			||||||
	}{
 | 
						}{
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			name: "normal case",
 | 
								name: "normal case",
 | 
				
			||||||
@@ -111,9 +144,9 @@ func TestParseArgumentListToMap(t *testing.T) {
 | 
				
			|||||||
				"--admission-control=NamespaceLifecycle,LimitRanger",
 | 
									"--admission-control=NamespaceLifecycle,LimitRanger",
 | 
				
			||||||
				"--allow-privileged=true",
 | 
									"--allow-privileged=true",
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			expectedMap: map[string]string{
 | 
								expected: []kubeadmapi.Arg{
 | 
				
			||||||
				"admission-control": "NamespaceLifecycle,LimitRanger",
 | 
									{Name: "admission-control", Value: "NamespaceLifecycle,LimitRanger"},
 | 
				
			||||||
				"allow-privileged":  "true",
 | 
									{Name: "allow-privileged", Value: "true"},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
@@ -123,10 +156,10 @@ func TestParseArgumentListToMap(t *testing.T) {
 | 
				
			|||||||
				"--allow-privileged=true",
 | 
									"--allow-privileged=true",
 | 
				
			||||||
				"--feature-gates=EnableFoo=true,EnableBar=false",
 | 
									"--feature-gates=EnableFoo=true,EnableBar=false",
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			expectedMap: map[string]string{
 | 
								expected: []kubeadmapi.Arg{
 | 
				
			||||||
				"admission-control": "NamespaceLifecycle,LimitRanger",
 | 
									{Name: "admission-control", Value: "NamespaceLifecycle,LimitRanger"},
 | 
				
			||||||
				"allow-privileged":  "true",
 | 
									{Name: "allow-privileged", Value: "true"},
 | 
				
			||||||
				"feature-gates":     "EnableFoo=true,EnableBar=false",
 | 
									{Name: "feature-gates", Value: "EnableFoo=true,EnableBar=false"},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
@@ -137,75 +170,32 @@ func TestParseArgumentListToMap(t *testing.T) {
 | 
				
			|||||||
				"--allow-privileged=true",
 | 
									"--allow-privileged=true",
 | 
				
			||||||
				"--feature-gates=EnableFoo=true,EnableBar=false",
 | 
									"--feature-gates=EnableFoo=true,EnableBar=false",
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			expectedMap: map[string]string{
 | 
								expected: []kubeadmapi.Arg{
 | 
				
			||||||
				"admission-control": "NamespaceLifecycle,LimitRanger",
 | 
									{Name: "admission-control", Value: "NamespaceLifecycle,LimitRanger"},
 | 
				
			||||||
				"allow-privileged":  "true",
 | 
									{Name: "allow-privileged", Value: "true"},
 | 
				
			||||||
				"feature-gates":     "EnableFoo=true,EnableBar=false",
 | 
									{Name: "feature-gates", Value: "EnableFoo=true,EnableBar=false"},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name: "allow duplicate args",
 | 
				
			||||||
 | 
								args: []string{
 | 
				
			||||||
 | 
									"--admission-control=NamespaceLifecycle,LimitRanger",
 | 
				
			||||||
 | 
									"--tls-sni-cert-key=/some/path",
 | 
				
			||||||
 | 
									"--tls-sni-cert-key=/some/path/subpath",
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								expected: []kubeadmapi.Arg{
 | 
				
			||||||
 | 
									{Name: "admission-control", Value: "NamespaceLifecycle,LimitRanger"},
 | 
				
			||||||
 | 
									{Name: "tls-sni-cert-key", Value: "/some/path"},
 | 
				
			||||||
 | 
									{Name: "tls-sni-cert-key", Value: "/some/path/subpath"},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, rt := range tests {
 | 
						for _, rt := range tests {
 | 
				
			||||||
		t.Run(rt.name, func(t *testing.T) {
 | 
							t.Run(rt.name, func(t *testing.T) {
 | 
				
			||||||
			actualMap := ParseArgumentListToMap(rt.args)
 | 
								actual := ArgumentsFromCommand(rt.args)
 | 
				
			||||||
			if !reflect.DeepEqual(actualMap, rt.expectedMap) {
 | 
								if !reflect.DeepEqual(actual, rt.expected) {
 | 
				
			||||||
				t.Errorf("failed ParseArgumentListToMap:\nexpected:\n%v\nsaw:\n%v", rt.expectedMap, actualMap)
 | 
									t.Errorf("failed ArgumentsFromCommand:\nexpected:\n%v\nsaw:\n%v", rt.expected, actual)
 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		})
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestReplaceArgument(t *testing.T) {
 | 
					 | 
				
			||||||
	var tests = []struct {
 | 
					 | 
				
			||||||
		name         string
 | 
					 | 
				
			||||||
		args         []string
 | 
					 | 
				
			||||||
		mutateFunc   func(map[string]string) map[string]string
 | 
					 | 
				
			||||||
		expectedArgs []string
 | 
					 | 
				
			||||||
	}{
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			name: "normal case",
 | 
					 | 
				
			||||||
			args: []string{
 | 
					 | 
				
			||||||
				"kube-apiserver",
 | 
					 | 
				
			||||||
				"--admission-control=NamespaceLifecycle,LimitRanger",
 | 
					 | 
				
			||||||
				"--allow-privileged=true",
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			mutateFunc: func(argMap map[string]string) map[string]string {
 | 
					 | 
				
			||||||
				argMap["admission-control"] = "NamespaceLifecycle,LimitRanger,ResourceQuota"
 | 
					 | 
				
			||||||
				return argMap
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			expectedArgs: []string{
 | 
					 | 
				
			||||||
				"kube-apiserver",
 | 
					 | 
				
			||||||
				"--admission-control=NamespaceLifecycle,LimitRanger,ResourceQuota",
 | 
					 | 
				
			||||||
				"--allow-privileged=true",
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			name: "another normal case",
 | 
					 | 
				
			||||||
			args: []string{
 | 
					 | 
				
			||||||
				"kube-apiserver",
 | 
					 | 
				
			||||||
				"--admission-control=NamespaceLifecycle,LimitRanger",
 | 
					 | 
				
			||||||
				"--allow-privileged=true",
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			mutateFunc: func(argMap map[string]string) map[string]string {
 | 
					 | 
				
			||||||
				argMap["new-arg-here"] = "foo"
 | 
					 | 
				
			||||||
				return argMap
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			expectedArgs: []string{
 | 
					 | 
				
			||||||
				"kube-apiserver",
 | 
					 | 
				
			||||||
				"--admission-control=NamespaceLifecycle,LimitRanger",
 | 
					 | 
				
			||||||
				"--allow-privileged=true",
 | 
					 | 
				
			||||||
				"--new-arg-here=foo",
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for _, rt := range tests {
 | 
					 | 
				
			||||||
		t.Run(rt.name, func(t *testing.T) {
 | 
					 | 
				
			||||||
			actualArgs := ReplaceArgument(rt.args, rt.mutateFunc)
 | 
					 | 
				
			||||||
			sort.Strings(actualArgs)
 | 
					 | 
				
			||||||
			sort.Strings(rt.expectedArgs)
 | 
					 | 
				
			||||||
			if !reflect.DeepEqual(actualArgs, rt.expectedArgs) {
 | 
					 | 
				
			||||||
				t.Errorf("failed ReplaceArgument:\nexpected:\n%v\nsaw:\n%v", rt.expectedArgs, actualArgs)
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -236,7 +226,7 @@ func TestRoundtrip(t *testing.T) {
 | 
				
			|||||||
	for _, rt := range tests {
 | 
						for _, rt := range tests {
 | 
				
			||||||
		t.Run(rt.name, func(t *testing.T) {
 | 
							t.Run(rt.name, func(t *testing.T) {
 | 
				
			||||||
			// These two methods should be each other's opposite functions, test that by chaining the methods and see if you get the same result back
 | 
								// These two methods should be each other's opposite functions, test that by chaining the methods and see if you get the same result back
 | 
				
			||||||
			actual := BuildArgumentListFromMap(ParseArgumentListToMap(rt.args), map[string]string{})
 | 
								actual := ArgumentsToCommand(ArgumentsFromCommand(rt.args), []kubeadmapi.Arg{})
 | 
				
			||||||
			sort.Strings(actual)
 | 
								sort.Strings(actual)
 | 
				
			||||||
			sort.Strings(rt.args)
 | 
								sort.Strings(rt.args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -295,7 +295,7 @@ func GetAPIServerProbeAddress(endpoint *kubeadmapi.APIEndpoint) string {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// GetControllerManagerProbeAddress returns the kubernetes controller manager probe address
 | 
					// GetControllerManagerProbeAddress returns the kubernetes controller manager probe address
 | 
				
			||||||
func GetControllerManagerProbeAddress(cfg *kubeadmapi.ClusterConfiguration) string {
 | 
					func GetControllerManagerProbeAddress(cfg *kubeadmapi.ClusterConfiguration) string {
 | 
				
			||||||
	if addr, exists := cfg.ControllerManager.ExtraArgs[kubeControllerManagerBindAddressArg]; exists {
 | 
						if addr, idx := kubeadmapi.GetArgValue(cfg.ControllerManager.ExtraArgs, kubeControllerManagerBindAddressArg, -1); idx > -1 {
 | 
				
			||||||
		return getProbeAddress(addr)
 | 
							return getProbeAddress(addr)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return "127.0.0.1"
 | 
						return "127.0.0.1"
 | 
				
			||||||
@@ -303,7 +303,7 @@ func GetControllerManagerProbeAddress(cfg *kubeadmapi.ClusterConfiguration) stri
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// GetSchedulerProbeAddress returns the kubernetes scheduler probe address
 | 
					// GetSchedulerProbeAddress returns the kubernetes scheduler probe address
 | 
				
			||||||
func GetSchedulerProbeAddress(cfg *kubeadmapi.ClusterConfiguration) string {
 | 
					func GetSchedulerProbeAddress(cfg *kubeadmapi.ClusterConfiguration) string {
 | 
				
			||||||
	if addr, exists := cfg.Scheduler.ExtraArgs[kubeSchedulerBindAddressArg]; exists {
 | 
						if addr, idx := kubeadmapi.GetArgValue(cfg.Scheduler.ExtraArgs, kubeSchedulerBindAddressArg, -1); idx > -1 {
 | 
				
			||||||
		return getProbeAddress(addr)
 | 
							return getProbeAddress(addr)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return "127.0.0.1"
 | 
						return "127.0.0.1"
 | 
				
			||||||
@@ -320,7 +320,7 @@ func GetEtcdProbeEndpoint(cfg *kubeadmapi.Etcd, isIPv6 bool) (string, int32, v1.
 | 
				
			|||||||
	if cfg.Local == nil || cfg.Local.ExtraArgs == nil {
 | 
						if cfg.Local == nil || cfg.Local.ExtraArgs == nil {
 | 
				
			||||||
		return localhost, kubeadmconstants.EtcdMetricsPort, v1.URISchemeHTTP
 | 
							return localhost, kubeadmconstants.EtcdMetricsPort, v1.URISchemeHTTP
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if arg, exists := cfg.Local.ExtraArgs["listen-metrics-urls"]; exists {
 | 
						if arg, idx := kubeadmapi.GetArgValue(cfg.Local.ExtraArgs, "listen-metrics-urls", -1); idx > -1 {
 | 
				
			||||||
		// Use the first url in the listen-metrics-urls if multiple URL's are specified.
 | 
							// Use the first url in the listen-metrics-urls if multiple URL's are specified.
 | 
				
			||||||
		arg = strings.Split(arg, ",")[0]
 | 
							arg = strings.Split(arg, ",")[0]
 | 
				
			||||||
		parsedURL, err := url.Parse(arg)
 | 
							parsedURL, err := url.Parse(arg)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -107,7 +107,7 @@ func TestGetControllerManagerProbeAddress(t *testing.T) {
 | 
				
			|||||||
			desc: "no controller manager extra args leads to 127.0.0.1 being used",
 | 
								desc: "no controller manager extra args leads to 127.0.0.1 being used",
 | 
				
			||||||
			cfg: &kubeadmapi.ClusterConfiguration{
 | 
								cfg: &kubeadmapi.ClusterConfiguration{
 | 
				
			||||||
				ControllerManager: kubeadmapi.ControlPlaneComponent{
 | 
									ControllerManager: kubeadmapi.ControlPlaneComponent{
 | 
				
			||||||
					ExtraArgs: map[string]string{},
 | 
										ExtraArgs: []kubeadmapi.Arg{},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			expected: "127.0.0.1",
 | 
								expected: "127.0.0.1",
 | 
				
			||||||
@@ -116,8 +116,8 @@ func TestGetControllerManagerProbeAddress(t *testing.T) {
 | 
				
			|||||||
			desc: "setting controller manager extra address arg to something acknowledges it",
 | 
								desc: "setting controller manager extra address arg to something acknowledges it",
 | 
				
			||||||
			cfg: &kubeadmapi.ClusterConfiguration{
 | 
								cfg: &kubeadmapi.ClusterConfiguration{
 | 
				
			||||||
				ControllerManager: kubeadmapi.ControlPlaneComponent{
 | 
									ControllerManager: kubeadmapi.ControlPlaneComponent{
 | 
				
			||||||
					ExtraArgs: map[string]string{
 | 
										ExtraArgs: []kubeadmapi.Arg{
 | 
				
			||||||
						kubeControllerManagerBindAddressArg: "10.10.10.10",
 | 
											{Name: kubeControllerManagerBindAddressArg, Value: "10.10.10.10"},
 | 
				
			||||||
					},
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
@@ -127,8 +127,8 @@ func TestGetControllerManagerProbeAddress(t *testing.T) {
 | 
				
			|||||||
			desc: "setting controller manager extra ipv6 address arg to something acknowledges it",
 | 
								desc: "setting controller manager extra ipv6 address arg to something acknowledges it",
 | 
				
			||||||
			cfg: &kubeadmapi.ClusterConfiguration{
 | 
								cfg: &kubeadmapi.ClusterConfiguration{
 | 
				
			||||||
				ControllerManager: kubeadmapi.ControlPlaneComponent{
 | 
									ControllerManager: kubeadmapi.ControlPlaneComponent{
 | 
				
			||||||
					ExtraArgs: map[string]string{
 | 
										ExtraArgs: []kubeadmapi.Arg{
 | 
				
			||||||
						kubeControllerManagerBindAddressArg: "2001:abcd:bcda::1",
 | 
											{Name: kubeControllerManagerBindAddressArg, Value: "2001:abcd:bcda::1"},
 | 
				
			||||||
					},
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
@@ -138,8 +138,8 @@ func TestGetControllerManagerProbeAddress(t *testing.T) {
 | 
				
			|||||||
			desc: "setting controller manager extra address arg to 0.0.0.0 returns empty",
 | 
								desc: "setting controller manager extra address arg to 0.0.0.0 returns empty",
 | 
				
			||||||
			cfg: &kubeadmapi.ClusterConfiguration{
 | 
								cfg: &kubeadmapi.ClusterConfiguration{
 | 
				
			||||||
				ControllerManager: kubeadmapi.ControlPlaneComponent{
 | 
									ControllerManager: kubeadmapi.ControlPlaneComponent{
 | 
				
			||||||
					ExtraArgs: map[string]string{
 | 
										ExtraArgs: []kubeadmapi.Arg{
 | 
				
			||||||
						kubeControllerManagerBindAddressArg: "0.0.0.0",
 | 
											{Name: kubeControllerManagerBindAddressArg, Value: "0.0.0.0"},
 | 
				
			||||||
					},
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
@@ -149,8 +149,8 @@ func TestGetControllerManagerProbeAddress(t *testing.T) {
 | 
				
			|||||||
			desc: "setting controller manager extra ipv6 address arg to :: returns empty",
 | 
								desc: "setting controller manager extra ipv6 address arg to :: returns empty",
 | 
				
			||||||
			cfg: &kubeadmapi.ClusterConfiguration{
 | 
								cfg: &kubeadmapi.ClusterConfiguration{
 | 
				
			||||||
				ControllerManager: kubeadmapi.ControlPlaneComponent{
 | 
									ControllerManager: kubeadmapi.ControlPlaneComponent{
 | 
				
			||||||
					ExtraArgs: map[string]string{
 | 
										ExtraArgs: []kubeadmapi.Arg{
 | 
				
			||||||
						kubeControllerManagerBindAddressArg: "::",
 | 
											{Name: kubeControllerManagerBindAddressArg, Value: "::"},
 | 
				
			||||||
					},
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
@@ -178,7 +178,7 @@ func TestGetSchedulerProbeAddress(t *testing.T) {
 | 
				
			|||||||
			desc: "no scheduler extra args leads to 127.0.0.1 being used",
 | 
								desc: "no scheduler extra args leads to 127.0.0.1 being used",
 | 
				
			||||||
			cfg: &kubeadmapi.ClusterConfiguration{
 | 
								cfg: &kubeadmapi.ClusterConfiguration{
 | 
				
			||||||
				Scheduler: kubeadmapi.ControlPlaneComponent{
 | 
									Scheduler: kubeadmapi.ControlPlaneComponent{
 | 
				
			||||||
					ExtraArgs: map[string]string{},
 | 
										ExtraArgs: []kubeadmapi.Arg{},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			expected: "127.0.0.1",
 | 
								expected: "127.0.0.1",
 | 
				
			||||||
@@ -187,8 +187,8 @@ func TestGetSchedulerProbeAddress(t *testing.T) {
 | 
				
			|||||||
			desc: "setting scheduler extra address arg to something acknowledges it",
 | 
								desc: "setting scheduler extra address arg to something acknowledges it",
 | 
				
			||||||
			cfg: &kubeadmapi.ClusterConfiguration{
 | 
								cfg: &kubeadmapi.ClusterConfiguration{
 | 
				
			||||||
				Scheduler: kubeadmapi.ControlPlaneComponent{
 | 
									Scheduler: kubeadmapi.ControlPlaneComponent{
 | 
				
			||||||
					ExtraArgs: map[string]string{
 | 
										ExtraArgs: []kubeadmapi.Arg{
 | 
				
			||||||
						kubeSchedulerBindAddressArg: "10.10.10.10",
 | 
											{Name: kubeSchedulerBindAddressArg, Value: "10.10.10.10"},
 | 
				
			||||||
					},
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
@@ -198,8 +198,8 @@ func TestGetSchedulerProbeAddress(t *testing.T) {
 | 
				
			|||||||
			desc: "setting scheduler extra ipv6 address arg to something acknowledges it",
 | 
								desc: "setting scheduler extra ipv6 address arg to something acknowledges it",
 | 
				
			||||||
			cfg: &kubeadmapi.ClusterConfiguration{
 | 
								cfg: &kubeadmapi.ClusterConfiguration{
 | 
				
			||||||
				Scheduler: kubeadmapi.ControlPlaneComponent{
 | 
									Scheduler: kubeadmapi.ControlPlaneComponent{
 | 
				
			||||||
					ExtraArgs: map[string]string{
 | 
										ExtraArgs: []kubeadmapi.Arg{
 | 
				
			||||||
						kubeSchedulerBindAddressArg: "2001:abcd:bcda::1",
 | 
											{Name: kubeSchedulerBindAddressArg, Value: "2001:abcd:bcda::1"},
 | 
				
			||||||
					},
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
@@ -209,8 +209,8 @@ func TestGetSchedulerProbeAddress(t *testing.T) {
 | 
				
			|||||||
			desc: "setting scheduler extra ipv6 address arg to 0.0.0.0 returns empty",
 | 
								desc: "setting scheduler extra ipv6 address arg to 0.0.0.0 returns empty",
 | 
				
			||||||
			cfg: &kubeadmapi.ClusterConfiguration{
 | 
								cfg: &kubeadmapi.ClusterConfiguration{
 | 
				
			||||||
				Scheduler: kubeadmapi.ControlPlaneComponent{
 | 
									Scheduler: kubeadmapi.ControlPlaneComponent{
 | 
				
			||||||
					ExtraArgs: map[string]string{
 | 
										ExtraArgs: []kubeadmapi.Arg{
 | 
				
			||||||
						kubeSchedulerBindAddressArg: "0.0.0.0",
 | 
											{Name: kubeSchedulerBindAddressArg, Value: "0.0.0.0"},
 | 
				
			||||||
					},
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
@@ -220,8 +220,8 @@ func TestGetSchedulerProbeAddress(t *testing.T) {
 | 
				
			|||||||
			desc: "setting scheduler extra ipv6 address arg to :: returns empty",
 | 
								desc: "setting scheduler extra ipv6 address arg to :: returns empty",
 | 
				
			||||||
			cfg: &kubeadmapi.ClusterConfiguration{
 | 
								cfg: &kubeadmapi.ClusterConfiguration{
 | 
				
			||||||
				Scheduler: kubeadmapi.ControlPlaneComponent{
 | 
									Scheduler: kubeadmapi.ControlPlaneComponent{
 | 
				
			||||||
					ExtraArgs: map[string]string{
 | 
										ExtraArgs: []kubeadmapi.Arg{
 | 
				
			||||||
						kubeSchedulerBindAddressArg: "::",
 | 
											{Name: kubeSchedulerBindAddressArg, Value: "::"},
 | 
				
			||||||
					},
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
@@ -251,8 +251,9 @@ func TestGetEtcdProbeEndpoint(t *testing.T) {
 | 
				
			|||||||
			name: "etcd probe URL from two URLs",
 | 
								name: "etcd probe URL from two URLs",
 | 
				
			||||||
			cfg: &kubeadmapi.Etcd{
 | 
								cfg: &kubeadmapi.Etcd{
 | 
				
			||||||
				Local: &kubeadmapi.LocalEtcd{
 | 
									Local: &kubeadmapi.LocalEtcd{
 | 
				
			||||||
					ExtraArgs: map[string]string{
 | 
										ExtraArgs: []kubeadmapi.Arg{
 | 
				
			||||||
						"listen-metrics-urls": "https://1.2.3.4:1234,https://4.3.2.1:2381"},
 | 
											{Name: "listen-metrics-urls", Value: "https://1.2.3.4:1234,https://4.3.2.1:2381"},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			isIPv6:           false,
 | 
								isIPv6:           false,
 | 
				
			||||||
@@ -264,8 +265,9 @@ func TestGetEtcdProbeEndpoint(t *testing.T) {
 | 
				
			|||||||
			name: "etcd probe URL with HTTP scheme",
 | 
								name: "etcd probe URL with HTTP scheme",
 | 
				
			||||||
			cfg: &kubeadmapi.Etcd{
 | 
								cfg: &kubeadmapi.Etcd{
 | 
				
			||||||
				Local: &kubeadmapi.LocalEtcd{
 | 
									Local: &kubeadmapi.LocalEtcd{
 | 
				
			||||||
					ExtraArgs: map[string]string{
 | 
										ExtraArgs: []kubeadmapi.Arg{
 | 
				
			||||||
						"listen-metrics-urls": "http://1.2.3.4:1234"},
 | 
											{Name: "listen-metrics-urls", Value: "http://1.2.3.4:1234"},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			isIPv6:           false,
 | 
								isIPv6:           false,
 | 
				
			||||||
@@ -277,8 +279,9 @@ func TestGetEtcdProbeEndpoint(t *testing.T) {
 | 
				
			|||||||
			name: "etcd probe URL without scheme should result in defaults",
 | 
								name: "etcd probe URL without scheme should result in defaults",
 | 
				
			||||||
			cfg: &kubeadmapi.Etcd{
 | 
								cfg: &kubeadmapi.Etcd{
 | 
				
			||||||
				Local: &kubeadmapi.LocalEtcd{
 | 
									Local: &kubeadmapi.LocalEtcd{
 | 
				
			||||||
					ExtraArgs: map[string]string{
 | 
										ExtraArgs: []kubeadmapi.Arg{
 | 
				
			||||||
						"listen-metrics-urls": "1.2.3.4"},
 | 
											{Name: "listen-metrics-urls", Value: "1.2.3.4"},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			isIPv6:           false,
 | 
								isIPv6:           false,
 | 
				
			||||||
@@ -290,8 +293,9 @@ func TestGetEtcdProbeEndpoint(t *testing.T) {
 | 
				
			|||||||
			name: "etcd probe URL without port",
 | 
								name: "etcd probe URL without port",
 | 
				
			||||||
			cfg: &kubeadmapi.Etcd{
 | 
								cfg: &kubeadmapi.Etcd{
 | 
				
			||||||
				Local: &kubeadmapi.LocalEtcd{
 | 
									Local: &kubeadmapi.LocalEtcd{
 | 
				
			||||||
					ExtraArgs: map[string]string{
 | 
										ExtraArgs: []kubeadmapi.Arg{
 | 
				
			||||||
						"listen-metrics-urls": "https://1.2.3.4"},
 | 
											{Name: "listen-metrics-urls", Value: "https://1.2.3.4"},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			isIPv6:           false,
 | 
								isIPv6:           false,
 | 
				
			||||||
@@ -303,8 +307,9 @@ func TestGetEtcdProbeEndpoint(t *testing.T) {
 | 
				
			|||||||
			name: "etcd probe URL from two IPv6 URLs",
 | 
								name: "etcd probe URL from two IPv6 URLs",
 | 
				
			||||||
			cfg: &kubeadmapi.Etcd{
 | 
								cfg: &kubeadmapi.Etcd{
 | 
				
			||||||
				Local: &kubeadmapi.LocalEtcd{
 | 
									Local: &kubeadmapi.LocalEtcd{
 | 
				
			||||||
					ExtraArgs: map[string]string{
 | 
										ExtraArgs: []kubeadmapi.Arg{
 | 
				
			||||||
						"listen-metrics-urls": "https://[2001:abcd:bcda::1]:1234,https://[2001:abcd:bcda::2]:2381"},
 | 
											{Name: "listen-metrics-urls", Value: "https://[2001:abcd:bcda::1]:1234,https://[2001:abcd:bcda::2]:2381"},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			isIPv6:           true,
 | 
								isIPv6:           true,
 | 
				
			||||||
@@ -316,8 +321,9 @@ func TestGetEtcdProbeEndpoint(t *testing.T) {
 | 
				
			|||||||
			name: "etcd probe localhost IPv6 URL with HTTP scheme",
 | 
								name: "etcd probe localhost IPv6 URL with HTTP scheme",
 | 
				
			||||||
			cfg: &kubeadmapi.Etcd{
 | 
								cfg: &kubeadmapi.Etcd{
 | 
				
			||||||
				Local: &kubeadmapi.LocalEtcd{
 | 
									Local: &kubeadmapi.LocalEtcd{
 | 
				
			||||||
					ExtraArgs: map[string]string{
 | 
										ExtraArgs: []kubeadmapi.Arg{
 | 
				
			||||||
						"listen-metrics-urls": "http://[::1]:1234"},
 | 
											{Name: "listen-metrics-urls", Value: "http://[::1]:1234"},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			isIPv6:           true,
 | 
								isIPv6:           true,
 | 
				
			||||||
@@ -329,8 +335,9 @@ func TestGetEtcdProbeEndpoint(t *testing.T) {
 | 
				
			|||||||
			name: "etcd probe IPv6 URL with HTTP scheme",
 | 
								name: "etcd probe IPv6 URL with HTTP scheme",
 | 
				
			||||||
			cfg: &kubeadmapi.Etcd{
 | 
								cfg: &kubeadmapi.Etcd{
 | 
				
			||||||
				Local: &kubeadmapi.LocalEtcd{
 | 
									Local: &kubeadmapi.LocalEtcd{
 | 
				
			||||||
					ExtraArgs: map[string]string{
 | 
										ExtraArgs: []kubeadmapi.Arg{
 | 
				
			||||||
						"listen-metrics-urls": "http://[2001:abcd:bcda::1]:1234"},
 | 
											{Name: "listen-metrics-urls", Value: "http://[2001:abcd:bcda::1]:1234"},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			isIPv6:           true,
 | 
								isIPv6:           true,
 | 
				
			||||||
@@ -342,8 +349,9 @@ func TestGetEtcdProbeEndpoint(t *testing.T) {
 | 
				
			|||||||
			name: "etcd probe IPv6 URL without port",
 | 
								name: "etcd probe IPv6 URL without port",
 | 
				
			||||||
			cfg: &kubeadmapi.Etcd{
 | 
								cfg: &kubeadmapi.Etcd{
 | 
				
			||||||
				Local: &kubeadmapi.LocalEtcd{
 | 
									Local: &kubeadmapi.LocalEtcd{
 | 
				
			||||||
					ExtraArgs: map[string]string{
 | 
										ExtraArgs: []kubeadmapi.Arg{
 | 
				
			||||||
						"listen-metrics-urls": "https://[2001:abcd:bcda::1]"},
 | 
											{Name: "listen-metrics-urls", Value: "https://[2001:abcd:bcda::1]"},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			isIPv6:           true,
 | 
								isIPv6:           true,
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user