kubeadm: implementation of API types
Signed-off-by: calvin <wen.chen@daocloud.io> Co-authored-by: Dave Chen <dave.chen@arm.com>
This commit is contained in:
		@@ -41,6 +41,7 @@ func Funcs(codecs runtimeserializer.CodecFactory) []interface{} {
 | 
			
		||||
		fuzzJoinConfiguration,
 | 
			
		||||
		fuzzJoinControlPlane,
 | 
			
		||||
		fuzzResetConfiguration,
 | 
			
		||||
		fuzzUpgradeConfiguration,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -152,3 +153,13 @@ func fuzzResetConfiguration(obj *kubeadm.ResetConfiguration, c fuzz.Continue) {
 | 
			
		||||
	obj.CertificatesDir = "/tmp"
 | 
			
		||||
	kubeadm.SetDefaultTimeouts(&obj.Timeouts)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func fuzzUpgradeConfiguration(obj *kubeadm.UpgradeConfiguration, c fuzz.Continue) {
 | 
			
		||||
	c.FuzzNoCustom(obj)
 | 
			
		||||
 | 
			
		||||
	// Pinning values for fields that get defaults if fuzz value is empty string or nil (thus making the round trip test fail)
 | 
			
		||||
	obj.Node.EtcdUpgrade = ptr.To(true)
 | 
			
		||||
	obj.Apply.EtcdUpgrade = ptr.To(true)
 | 
			
		||||
	obj.Apply.CertificateRenewal = ptr.To(false)
 | 
			
		||||
	obj.Node.CertificateRenewal = ptr.To(false)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -40,6 +40,7 @@ func addKnownTypes(scheme *runtime.Scheme) error {
 | 
			
		||||
		&ClusterConfiguration{},
 | 
			
		||||
		&JoinConfiguration{},
 | 
			
		||||
		&ResetConfiguration{},
 | 
			
		||||
		&UpgradeConfiguration{},
 | 
			
		||||
	)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -39,7 +39,7 @@ type InitConfiguration struct {
 | 
			
		||||
	// the `json:"-"` tag in the external variant of these API types.
 | 
			
		||||
	ClusterConfiguration `json:"-"`
 | 
			
		||||
 | 
			
		||||
	// BootstrapTokens is respected at `kubeadm init` time and describes a set of Bootstrap Tokens to create.
 | 
			
		||||
	// BootstrapTokens is respected at "kubeadm init" time and describes a set of Bootstrap Tokens to create.
 | 
			
		||||
	BootstrapTokens []bootstraptokenv1.BootstrapToken
 | 
			
		||||
 | 
			
		||||
	// DryRun tells if the dry run mode is enabled, don't apply any change if it is and just output what would be done.
 | 
			
		||||
@@ -221,7 +221,7 @@ type APIEndpoint struct {
 | 
			
		||||
// NodeRegistrationOptions holds fields that relate to registering a new control-plane or node to the cluster, either via "kubeadm init" or "kubeadm join"
 | 
			
		||||
type NodeRegistrationOptions struct {
 | 
			
		||||
 | 
			
		||||
	// Name is the `.Metadata.Name` field of the Node API object that will be created in this `kubeadm init` or `kubeadm join` operation.
 | 
			
		||||
	// Name is the `.Metadata.Name` field of the Node API object that will be created in this "kubeadm init" or "kubeadm join" operation.
 | 
			
		||||
	// This field is also used in the CommonName field of the kubelet's client certificate to the API server.
 | 
			
		||||
	// Defaults to the hostname of the node if not provided.
 | 
			
		||||
	Name string
 | 
			
		||||
@@ -541,6 +541,125 @@ type ResetConfiguration struct {
 | 
			
		||||
	Timeouts *Timeouts
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UpgradeApplyConfiguration contains a list of configurable options which are specific to the "kubeadm upgrade apply" command.
 | 
			
		||||
type UpgradeApplyConfiguration struct {
 | 
			
		||||
	// KubernetesVersion is the target version of the control plane.
 | 
			
		||||
	KubernetesVersion string
 | 
			
		||||
 | 
			
		||||
	// AllowExperimentalUpgrades instructs kubeadm to show unstable versions of Kubernetes as an upgrade
 | 
			
		||||
	// alternative and allows upgrading to an alpha/beta/release candidate version of Kubernetes.
 | 
			
		||||
	// Default: false
 | 
			
		||||
	AllowExperimentalUpgrades *bool
 | 
			
		||||
 | 
			
		||||
	// Enable AllowRCUpgrades will show release candidate versions of Kubernetes as an upgrade alternative and
 | 
			
		||||
	// allows upgrading to a release candidate version of Kubernetes.
 | 
			
		||||
	AllowRCUpgrades *bool
 | 
			
		||||
 | 
			
		||||
	// CertificateRenewal instructs kubeadm to execute certificate renewal during upgrades.
 | 
			
		||||
	CertificateRenewal *bool
 | 
			
		||||
 | 
			
		||||
	// DryRun tells if the dry run mode is enabled, don't apply any change if it is and just output what would be done.
 | 
			
		||||
	DryRun *bool
 | 
			
		||||
 | 
			
		||||
	// EtcdUpgrade instructs kubeadm to execute etcd upgrade during upgrades.
 | 
			
		||||
	EtcdUpgrade *bool
 | 
			
		||||
 | 
			
		||||
	// ForceUpgrade flag instructs kubeadm to upgrade the cluster without prompting for confirmation.
 | 
			
		||||
	ForceUpgrade *bool
 | 
			
		||||
 | 
			
		||||
	// IgnorePreflightErrors provides a slice of pre-flight errors to be ignored during the upgrade process, e.g. 'IsPrivilegedUser,Swap'.
 | 
			
		||||
	// Value 'all' ignores errors from all checks.
 | 
			
		||||
	IgnorePreflightErrors []string
 | 
			
		||||
 | 
			
		||||
	// Patches contains options related to applying patches to components deployed by kubeadm during "kubeadm upgrade".
 | 
			
		||||
	Patches *Patches
 | 
			
		||||
 | 
			
		||||
	// PrintConfig specifies whether the configuration file that will be used in the upgrade should be printed or not.
 | 
			
		||||
	PrintConfig *bool
 | 
			
		||||
 | 
			
		||||
	// SkipPhases is a list of phases to skip during command execution.
 | 
			
		||||
	// NOTE: This field is currently ignored for "kubeadm upgrade apply", but in the future it will be supported.
 | 
			
		||||
	SkipPhases []string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UpgradeDiffConfiguration contains a list of configurable options which are specific to the "kubeadm upgrade diff" command.
 | 
			
		||||
type UpgradeDiffConfiguration struct {
 | 
			
		||||
	// KubernetesVersion is the target version of the control plane.
 | 
			
		||||
	KubernetesVersion string
 | 
			
		||||
 | 
			
		||||
	// DiffContextLines is the number of lines of context in the diff.
 | 
			
		||||
	DiffContextLines int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UpgradeNodeConfiguration contains a list of configurable options which are specific to the "kubeadm upgrade node" command.
 | 
			
		||||
type UpgradeNodeConfiguration struct {
 | 
			
		||||
	// CertificateRenewal instructs kubeadm to execute certificate renewal during upgrades.
 | 
			
		||||
	CertificateRenewal *bool
 | 
			
		||||
 | 
			
		||||
	// DryRun tells if the dry run mode is enabled, don't apply any change if it is and just output what would be done.
 | 
			
		||||
	DryRun *bool
 | 
			
		||||
 | 
			
		||||
	// EtcdUpgrade instructs kubeadm to execute etcd upgrade during upgrades.
 | 
			
		||||
	EtcdUpgrade *bool
 | 
			
		||||
 | 
			
		||||
	// IgnorePreflightErrors provides a slice of pre-flight errors to be ignored during the upgrade process, e.g. 'IsPrivilegedUser,Swap'.
 | 
			
		||||
	// Value 'all' ignores errors from all checks.
 | 
			
		||||
	IgnorePreflightErrors []string
 | 
			
		||||
 | 
			
		||||
	// SkipPhases is a list of phases to skip during command execution.
 | 
			
		||||
	// The list of phases can be obtained with the "kubeadm upgrade node phase --help" command.
 | 
			
		||||
	SkipPhases []string
 | 
			
		||||
 | 
			
		||||
	// Patches contains options related to applying patches to components deployed by kubeadm during "kubeadm upgrade".
 | 
			
		||||
	Patches *Patches
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UpgradePlanConfiguration contains a list of configurable options which are specific to the "kubeadm upgrade plan" command.
 | 
			
		||||
type UpgradePlanConfiguration struct {
 | 
			
		||||
	// KubernetesVersion is the target version of the control plane.
 | 
			
		||||
	// +optional
 | 
			
		||||
	KubernetesVersion string
 | 
			
		||||
 | 
			
		||||
	// AllowExperimentalUpgrades instructs kubeadm to show unstable versions of Kubernetes as an upgrade
 | 
			
		||||
	// alternative and allows upgrading to an alpha/beta/release candidate version of Kubernetes.
 | 
			
		||||
	// Default: false
 | 
			
		||||
	// +optional
 | 
			
		||||
	AllowExperimentalUpgrades *bool
 | 
			
		||||
 | 
			
		||||
	// Enable AllowRCUpgrades will show release candidate versions of Kubernetes as an upgrade alternative and
 | 
			
		||||
	// allows upgrading to a release candidate version of Kubernetes.
 | 
			
		||||
	AllowRCUpgrades *bool
 | 
			
		||||
 | 
			
		||||
	// DryRun tells if the dry run mode is enabled, don't apply any change if it is and just output what would be done.
 | 
			
		||||
	DryRun *bool
 | 
			
		||||
 | 
			
		||||
	// IgnorePreflightErrors provides a slice of pre-flight errors to be ignored during the upgrade process, e.g. 'IsPrivilegedUser,Swap'.
 | 
			
		||||
	// Value 'all' ignores errors from all checks.
 | 
			
		||||
	IgnorePreflightErrors []string
 | 
			
		||||
 | 
			
		||||
	// PrintConfig specifies whether the configuration file that will be used in the upgrade should be printed or not.
 | 
			
		||||
	PrintConfig *bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
 | 
			
		||||
 | 
			
		||||
// UpgradeConfiguration contains a list of options that are specific to "kubeadm upgrade" subcommands.
 | 
			
		||||
type UpgradeConfiguration struct {
 | 
			
		||||
	metav1.TypeMeta
 | 
			
		||||
 | 
			
		||||
	// Apply holds a list of options that are specific to the "kubeadm upgrade apply" command.
 | 
			
		||||
	Apply UpgradeApplyConfiguration
 | 
			
		||||
 | 
			
		||||
	// Diff holds a list of options that are specific to the "kubeadm upgrade diff" command.
 | 
			
		||||
	Diff UpgradeDiffConfiguration
 | 
			
		||||
 | 
			
		||||
	// Node holds a list of options that are specific to the "kubeadm upgrade node" command.
 | 
			
		||||
	Node UpgradeNodeConfiguration
 | 
			
		||||
 | 
			
		||||
	// Plan holds a list of options that are specific to the "kubeadm upgrade plan" command.
 | 
			
		||||
	Plan UpgradePlanConfiguration
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	// UnmountFlagMNTForce represents the flag "MNT_FORCE"
 | 
			
		||||
	UnmountFlagMNTForce = "MNT_FORCE"
 | 
			
		||||
 
 | 
			
		||||
@@ -256,3 +256,22 @@ func SetDefaults_Timeouts(obj *Timeouts) {
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetDefaults_UpgradeConfiguration assigns default values for the UpgradeConfiguration
 | 
			
		||||
func SetDefaults_UpgradeConfiguration(obj *UpgradeConfiguration) {
 | 
			
		||||
	if obj.Node.EtcdUpgrade == nil {
 | 
			
		||||
		obj.Node.EtcdUpgrade = ptr.To(true)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if obj.Node.CertificateRenewal == nil {
 | 
			
		||||
		obj.Node.CertificateRenewal = ptr.To(true)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if obj.Apply.EtcdUpgrade == nil {
 | 
			
		||||
		obj.Apply.EtcdUpgrade = ptr.To(true)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if obj.Apply.CertificateRenewal == nil {
 | 
			
		||||
		obj.Apply.CertificateRenewal = ptr.To(true)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -41,6 +41,9 @@ limitations under the License.
 | 
			
		||||
//     that can be used to configure various timeouts.
 | 
			
		||||
//   - Add the `NodeRegistration.ImagePullSerial` field in 'InitConfiguration` and `JoinConfiguration`, which
 | 
			
		||||
//     can be used to control if kubeadm pulls images serially or in parallel.
 | 
			
		||||
//   - The UpgradeConfiguration kubeadm API is now supported in v1beta4 when passing --config to "kubeadm upgrade" subcommands.
 | 
			
		||||
//     Usage of component configuration for kubelet and kube-proxy, InitConfiguration and ClusterConfiguration is deprecated
 | 
			
		||||
//     and will be ignored when passing --config to upgrade subcommands.
 | 
			
		||||
//
 | 
			
		||||
// Migration from old kubeadm config versions
 | 
			
		||||
//
 | 
			
		||||
 
 | 
			
		||||
@@ -49,6 +49,7 @@ func addKnownTypes(scheme *runtime.Scheme) error {
 | 
			
		||||
		&ClusterConfiguration{},
 | 
			
		||||
		&JoinConfiguration{},
 | 
			
		||||
		&ResetConfiguration{},
 | 
			
		||||
		&UpgradeConfiguration{},
 | 
			
		||||
	)
 | 
			
		||||
	metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
 | 
			
		||||
	return nil
 | 
			
		||||
 
 | 
			
		||||
@@ -597,3 +597,151 @@ type Timeouts struct {
 | 
			
		||||
	// +optional
 | 
			
		||||
	Discovery *metav1.Duration `json:"discovery,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UpgradeApplyConfiguration contains a list of configurable options which are specific to the  "kubeadm upgrade apply" command.
 | 
			
		||||
type UpgradeApplyConfiguration struct {
 | 
			
		||||
	// KubernetesVersion is the target version of the control plane.
 | 
			
		||||
	// +optional
 | 
			
		||||
	KubernetesVersion string `json:"kubernetesVersion,omitempty"`
 | 
			
		||||
 | 
			
		||||
	// AllowExperimentalUpgrades instructs kubeadm to show unstable versions of Kubernetes as an upgrade
 | 
			
		||||
	// alternative and allows upgrading to an alpha/beta/release candidate version of Kubernetes.
 | 
			
		||||
	// Default: false
 | 
			
		||||
	// +optional
 | 
			
		||||
	AllowExperimentalUpgrades *bool `json:"allowExperimentalUpgrades,omitempty"`
 | 
			
		||||
 | 
			
		||||
	// Enable AllowRCUpgrades will show release candidate versions of Kubernetes as an upgrade alternative and
 | 
			
		||||
	// allows upgrading to a release candidate version of Kubernetes.
 | 
			
		||||
	// +optional
 | 
			
		||||
	AllowRCUpgrades *bool `json:"allowRCUpgrades,omitempty"`
 | 
			
		||||
 | 
			
		||||
	// CertificateRenewal instructs kubeadm to execute certificate renewal during upgrades.
 | 
			
		||||
	// Defaults to true.
 | 
			
		||||
	// +optional
 | 
			
		||||
	CertificateRenewal *bool `json:"certificateRenewal,omitempty"`
 | 
			
		||||
 | 
			
		||||
	// DryRun tells if the dry run mode is enabled, don't apply any change if it is and just output what would be done.
 | 
			
		||||
	// +optional
 | 
			
		||||
	DryRun *bool `json:"dryRun,omitempty"`
 | 
			
		||||
 | 
			
		||||
	// EtcdUpgrade instructs kubeadm to execute etcd upgrade during upgrades.
 | 
			
		||||
	// Defaults to true.
 | 
			
		||||
	// +optional
 | 
			
		||||
	EtcdUpgrade *bool `json:"etcdUpgrade,omitempty"`
 | 
			
		||||
 | 
			
		||||
	// ForceUpgrade flag instructs kubeadm to upgrade the cluster without prompting for confirmation.
 | 
			
		||||
	// +optional
 | 
			
		||||
	ForceUpgrade *bool `json:"forceUpgrade,omitempty"`
 | 
			
		||||
 | 
			
		||||
	// IgnorePreflightErrors provides a slice of pre-flight errors to be ignored during the upgrade process, e.g. 'IsPrivilegedUser,Swap'.
 | 
			
		||||
	// Value 'all' ignores errors from all checks.
 | 
			
		||||
	// +optional
 | 
			
		||||
	IgnorePreflightErrors []string `json:"ignorePreflightErrors,omitempty"`
 | 
			
		||||
 | 
			
		||||
	// Patches contains options related to applying patches to components deployed by kubeadm during "kubeadm upgrade".
 | 
			
		||||
	// +optional
 | 
			
		||||
	Patches *Patches `json:"patches,omitempty"`
 | 
			
		||||
 | 
			
		||||
	// PrintConfig specifies whether the configuration file that will be used in the upgrade should be printed or not.
 | 
			
		||||
	// +optional
 | 
			
		||||
	PrintConfig *bool `json:"printConfig,omitempty"`
 | 
			
		||||
 | 
			
		||||
	// SkipPhases is a list of phases to skip during command execution.
 | 
			
		||||
	// NOTE: This field is currently ignored for "kubeadm upgrade apply", but in the future it will be supported.
 | 
			
		||||
	SkipPhases []string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UpgradeDiffConfiguration contains a list of configurable options which are specific to the "kubeadm upgrade diff" command.
 | 
			
		||||
type UpgradeDiffConfiguration struct {
 | 
			
		||||
	// KubernetesVersion is the target version of the control plane.
 | 
			
		||||
	// +optional
 | 
			
		||||
	KubernetesVersion string `json:"kubernetesVersion,omitempty"`
 | 
			
		||||
 | 
			
		||||
	// DiffContextLines is the number of lines of context in the diff.
 | 
			
		||||
	// +optional
 | 
			
		||||
	DiffContextLines int `json:"contextLines,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UpgradeNodeConfiguration contains a list of configurable options which are specific to the "kubeadm upgrade node" command.
 | 
			
		||||
type UpgradeNodeConfiguration struct {
 | 
			
		||||
	// CertificateRenewal instructs kubeadm to execute certificate renewal during upgrades.
 | 
			
		||||
	// Defaults to true.
 | 
			
		||||
	// +optional
 | 
			
		||||
	CertificateRenewal *bool `json:"certificateRenewal,omitempty"`
 | 
			
		||||
 | 
			
		||||
	// DryRun tells if the dry run mode is enabled, don't apply any change if it is and just output what would be done.
 | 
			
		||||
	// +optional
 | 
			
		||||
	DryRun *bool `json:"dryRun,omitempty"`
 | 
			
		||||
 | 
			
		||||
	// EtcdUpgrade instructs kubeadm to execute etcd upgrade during upgrades.
 | 
			
		||||
	// Defaults to true.
 | 
			
		||||
	// +optional
 | 
			
		||||
	EtcdUpgrade *bool `json:"etcdUpgrade,omitempty"`
 | 
			
		||||
 | 
			
		||||
	// IgnorePreflightErrors provides a slice of pre-flight errors to be ignored during the upgrade process, e.g. 'IsPrivilegedUser,Swap'.
 | 
			
		||||
	// Value 'all' ignores errors from all checks.
 | 
			
		||||
	// +optional
 | 
			
		||||
	IgnorePreflightErrors []string `json:"ignorePreflightErrors,omitempty"`
 | 
			
		||||
 | 
			
		||||
	// SkipPhases is a list of phases to skip during command execution.
 | 
			
		||||
	// The list of phases can be obtained with the "kubeadm upgrade node phase --help" command.
 | 
			
		||||
	// +optional
 | 
			
		||||
	SkipPhases []string `json:"skipPhases,omitempty"`
 | 
			
		||||
 | 
			
		||||
	// Patches contains options related to applying patches to components deployed by kubeadm during "kubeadm upgrade".
 | 
			
		||||
	// +optional
 | 
			
		||||
	Patches *Patches `json:"patches,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UpgradePlanConfiguration contains a list of configurable options which are specific to the "kubeadm upgrade plan" command.
 | 
			
		||||
type UpgradePlanConfiguration struct {
 | 
			
		||||
	// KubernetesVersion is the target version of the control plane.
 | 
			
		||||
	KubernetesVersion string `json:"kubernetesVersion,omitempty"`
 | 
			
		||||
 | 
			
		||||
	// AllowExperimentalUpgrades instructs kubeadm to show unstable versions of Kubernetes as an upgrade
 | 
			
		||||
	// alternative and allows upgrading to an alpha/beta/release candidate version of Kubernetes.
 | 
			
		||||
	// Default: false
 | 
			
		||||
	// +optional
 | 
			
		||||
	AllowExperimentalUpgrades *bool `json:"allowExperimentalUpgrades,omitempty"`
 | 
			
		||||
 | 
			
		||||
	// Enable AllowRCUpgrades will show release candidate versions of Kubernetes as an upgrade alternative and
 | 
			
		||||
	// allows upgrading to a release candidate version of Kubernetes.
 | 
			
		||||
	// +optional
 | 
			
		||||
	AllowRCUpgrades *bool `json:"allowRCUpgrades,omitempty"`
 | 
			
		||||
 | 
			
		||||
	// DryRun tells if the dry run mode is enabled, don't apply any change if it is and just output what would be done.
 | 
			
		||||
	// +optional
 | 
			
		||||
	DryRun *bool `json:"dryRun,omitempty"`
 | 
			
		||||
 | 
			
		||||
	// IgnorePreflightErrors provides a slice of pre-flight errors to be ignored during the upgrade process, e.g. 'IsPrivilegedUser,Swap'.
 | 
			
		||||
	// Value 'all' ignores errors from all checks.
 | 
			
		||||
	// +optional
 | 
			
		||||
	IgnorePreflightErrors []string `json:"ignorePreflightErrors,omitempty"`
 | 
			
		||||
 | 
			
		||||
	// PrintConfig specifies whether the configuration file that will be used in the upgrade should be printed or not.
 | 
			
		||||
	// +optional
 | 
			
		||||
	PrintConfig *bool `json:"printConfig,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
 | 
			
		||||
 | 
			
		||||
// UpgradeConfiguration contains a list of options that are specific to "kubeadm upgrade" subcommands.
 | 
			
		||||
type UpgradeConfiguration struct {
 | 
			
		||||
	metav1.TypeMeta `json:",inline"`
 | 
			
		||||
 | 
			
		||||
	// Apply holds a list of options that are specific to the "kubeadm upgrade apply" command.
 | 
			
		||||
	// +optional
 | 
			
		||||
	Apply UpgradeApplyConfiguration `json:"apply,omitempty"`
 | 
			
		||||
 | 
			
		||||
	// Diff holds a list of options that are specific to the "kubeadm upgrade diff" command.
 | 
			
		||||
	// +optional
 | 
			
		||||
	Diff UpgradeDiffConfiguration `json:"diff,omitempty"`
 | 
			
		||||
 | 
			
		||||
	// Node holds a list of options that are specific to the "kubeadm upgrade node" command.
 | 
			
		||||
	// +optional
 | 
			
		||||
	Node UpgradeNodeConfiguration `json:"node,omitempty"`
 | 
			
		||||
 | 
			
		||||
	// Plan holds a list of options that are specific to the "kubeadm upgrade plan" command.
 | 
			
		||||
	// +optional
 | 
			
		||||
	Plan UpgradePlanConfiguration `json:"plan,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -244,6 +244,56 @@ func RegisterConversions(s *runtime.Scheme) error {
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if err := s.AddGeneratedConversionFunc((*UpgradeApplyConfiguration)(nil), (*kubeadm.UpgradeApplyConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error {
 | 
			
		||||
		return Convert_v1beta4_UpgradeApplyConfiguration_To_kubeadm_UpgradeApplyConfiguration(a.(*UpgradeApplyConfiguration), b.(*kubeadm.UpgradeApplyConfiguration), scope)
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if err := s.AddGeneratedConversionFunc((*kubeadm.UpgradeApplyConfiguration)(nil), (*UpgradeApplyConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error {
 | 
			
		||||
		return Convert_kubeadm_UpgradeApplyConfiguration_To_v1beta4_UpgradeApplyConfiguration(a.(*kubeadm.UpgradeApplyConfiguration), b.(*UpgradeApplyConfiguration), scope)
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if err := s.AddGeneratedConversionFunc((*UpgradeConfiguration)(nil), (*kubeadm.UpgradeConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error {
 | 
			
		||||
		return Convert_v1beta4_UpgradeConfiguration_To_kubeadm_UpgradeConfiguration(a.(*UpgradeConfiguration), b.(*kubeadm.UpgradeConfiguration), scope)
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if err := s.AddGeneratedConversionFunc((*kubeadm.UpgradeConfiguration)(nil), (*UpgradeConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error {
 | 
			
		||||
		return Convert_kubeadm_UpgradeConfiguration_To_v1beta4_UpgradeConfiguration(a.(*kubeadm.UpgradeConfiguration), b.(*UpgradeConfiguration), scope)
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if err := s.AddGeneratedConversionFunc((*UpgradeDiffConfiguration)(nil), (*kubeadm.UpgradeDiffConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error {
 | 
			
		||||
		return Convert_v1beta4_UpgradeDiffConfiguration_To_kubeadm_UpgradeDiffConfiguration(a.(*UpgradeDiffConfiguration), b.(*kubeadm.UpgradeDiffConfiguration), scope)
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if err := s.AddGeneratedConversionFunc((*kubeadm.UpgradeDiffConfiguration)(nil), (*UpgradeDiffConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error {
 | 
			
		||||
		return Convert_kubeadm_UpgradeDiffConfiguration_To_v1beta4_UpgradeDiffConfiguration(a.(*kubeadm.UpgradeDiffConfiguration), b.(*UpgradeDiffConfiguration), scope)
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if err := s.AddGeneratedConversionFunc((*UpgradeNodeConfiguration)(nil), (*kubeadm.UpgradeNodeConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error {
 | 
			
		||||
		return Convert_v1beta4_UpgradeNodeConfiguration_To_kubeadm_UpgradeNodeConfiguration(a.(*UpgradeNodeConfiguration), b.(*kubeadm.UpgradeNodeConfiguration), scope)
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if err := s.AddGeneratedConversionFunc((*kubeadm.UpgradeNodeConfiguration)(nil), (*UpgradeNodeConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error {
 | 
			
		||||
		return Convert_kubeadm_UpgradeNodeConfiguration_To_v1beta4_UpgradeNodeConfiguration(a.(*kubeadm.UpgradeNodeConfiguration), b.(*UpgradeNodeConfiguration), scope)
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if err := s.AddGeneratedConversionFunc((*UpgradePlanConfiguration)(nil), (*kubeadm.UpgradePlanConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error {
 | 
			
		||||
		return Convert_v1beta4_UpgradePlanConfiguration_To_kubeadm_UpgradePlanConfiguration(a.(*UpgradePlanConfiguration), b.(*kubeadm.UpgradePlanConfiguration), scope)
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if err := s.AddGeneratedConversionFunc((*kubeadm.UpgradePlanConfiguration)(nil), (*UpgradePlanConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error {
 | 
			
		||||
		return Convert_kubeadm_UpgradePlanConfiguration_To_v1beta4_UpgradePlanConfiguration(a.(*kubeadm.UpgradePlanConfiguration), b.(*UpgradePlanConfiguration), scope)
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if err := s.AddConversionFunc((*kubeadm.APIServer)(nil), (*APIServer)(nil), func(a, b interface{}, scope conversion.Scope) error {
 | 
			
		||||
		return Convert_kubeadm_APIServer_To_v1beta4_APIServer(a.(*kubeadm.APIServer), b.(*APIServer), scope)
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
@@ -940,3 +990,167 @@ func autoConvert_kubeadm_Timeouts_To_v1beta4_Timeouts(in *kubeadm.Timeouts, out
 | 
			
		||||
func Convert_kubeadm_Timeouts_To_v1beta4_Timeouts(in *kubeadm.Timeouts, out *Timeouts, s conversion.Scope) error {
 | 
			
		||||
	return autoConvert_kubeadm_Timeouts_To_v1beta4_Timeouts(in, out, s)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func autoConvert_v1beta4_UpgradeApplyConfiguration_To_kubeadm_UpgradeApplyConfiguration(in *UpgradeApplyConfiguration, out *kubeadm.UpgradeApplyConfiguration, s conversion.Scope) error {
 | 
			
		||||
	out.KubernetesVersion = in.KubernetesVersion
 | 
			
		||||
	out.AllowExperimentalUpgrades = (*bool)(unsafe.Pointer(in.AllowExperimentalUpgrades))
 | 
			
		||||
	out.AllowRCUpgrades = (*bool)(unsafe.Pointer(in.AllowRCUpgrades))
 | 
			
		||||
	out.CertificateRenewal = (*bool)(unsafe.Pointer(in.CertificateRenewal))
 | 
			
		||||
	out.DryRun = (*bool)(unsafe.Pointer(in.DryRun))
 | 
			
		||||
	out.EtcdUpgrade = (*bool)(unsafe.Pointer(in.EtcdUpgrade))
 | 
			
		||||
	out.ForceUpgrade = (*bool)(unsafe.Pointer(in.ForceUpgrade))
 | 
			
		||||
	out.IgnorePreflightErrors = *(*[]string)(unsafe.Pointer(&in.IgnorePreflightErrors))
 | 
			
		||||
	out.Patches = (*kubeadm.Patches)(unsafe.Pointer(in.Patches))
 | 
			
		||||
	out.PrintConfig = (*bool)(unsafe.Pointer(in.PrintConfig))
 | 
			
		||||
	out.SkipPhases = *(*[]string)(unsafe.Pointer(&in.SkipPhases))
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Convert_v1beta4_UpgradeApplyConfiguration_To_kubeadm_UpgradeApplyConfiguration is an autogenerated conversion function.
 | 
			
		||||
func Convert_v1beta4_UpgradeApplyConfiguration_To_kubeadm_UpgradeApplyConfiguration(in *UpgradeApplyConfiguration, out *kubeadm.UpgradeApplyConfiguration, s conversion.Scope) error {
 | 
			
		||||
	return autoConvert_v1beta4_UpgradeApplyConfiguration_To_kubeadm_UpgradeApplyConfiguration(in, out, s)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func autoConvert_kubeadm_UpgradeApplyConfiguration_To_v1beta4_UpgradeApplyConfiguration(in *kubeadm.UpgradeApplyConfiguration, out *UpgradeApplyConfiguration, s conversion.Scope) error {
 | 
			
		||||
	out.KubernetesVersion = in.KubernetesVersion
 | 
			
		||||
	out.AllowExperimentalUpgrades = (*bool)(unsafe.Pointer(in.AllowExperimentalUpgrades))
 | 
			
		||||
	out.AllowRCUpgrades = (*bool)(unsafe.Pointer(in.AllowRCUpgrades))
 | 
			
		||||
	out.CertificateRenewal = (*bool)(unsafe.Pointer(in.CertificateRenewal))
 | 
			
		||||
	out.DryRun = (*bool)(unsafe.Pointer(in.DryRun))
 | 
			
		||||
	out.EtcdUpgrade = (*bool)(unsafe.Pointer(in.EtcdUpgrade))
 | 
			
		||||
	out.ForceUpgrade = (*bool)(unsafe.Pointer(in.ForceUpgrade))
 | 
			
		||||
	out.IgnorePreflightErrors = *(*[]string)(unsafe.Pointer(&in.IgnorePreflightErrors))
 | 
			
		||||
	out.Patches = (*Patches)(unsafe.Pointer(in.Patches))
 | 
			
		||||
	out.PrintConfig = (*bool)(unsafe.Pointer(in.PrintConfig))
 | 
			
		||||
	out.SkipPhases = *(*[]string)(unsafe.Pointer(&in.SkipPhases))
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Convert_kubeadm_UpgradeApplyConfiguration_To_v1beta4_UpgradeApplyConfiguration is an autogenerated conversion function.
 | 
			
		||||
func Convert_kubeadm_UpgradeApplyConfiguration_To_v1beta4_UpgradeApplyConfiguration(in *kubeadm.UpgradeApplyConfiguration, out *UpgradeApplyConfiguration, s conversion.Scope) error {
 | 
			
		||||
	return autoConvert_kubeadm_UpgradeApplyConfiguration_To_v1beta4_UpgradeApplyConfiguration(in, out, s)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func autoConvert_v1beta4_UpgradeConfiguration_To_kubeadm_UpgradeConfiguration(in *UpgradeConfiguration, out *kubeadm.UpgradeConfiguration, s conversion.Scope) error {
 | 
			
		||||
	if err := Convert_v1beta4_UpgradeApplyConfiguration_To_kubeadm_UpgradeApplyConfiguration(&in.Apply, &out.Apply, s); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if err := Convert_v1beta4_UpgradeDiffConfiguration_To_kubeadm_UpgradeDiffConfiguration(&in.Diff, &out.Diff, s); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if err := Convert_v1beta4_UpgradeNodeConfiguration_To_kubeadm_UpgradeNodeConfiguration(&in.Node, &out.Node, s); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if err := Convert_v1beta4_UpgradePlanConfiguration_To_kubeadm_UpgradePlanConfiguration(&in.Plan, &out.Plan, s); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Convert_v1beta4_UpgradeConfiguration_To_kubeadm_UpgradeConfiguration is an autogenerated conversion function.
 | 
			
		||||
func Convert_v1beta4_UpgradeConfiguration_To_kubeadm_UpgradeConfiguration(in *UpgradeConfiguration, out *kubeadm.UpgradeConfiguration, s conversion.Scope) error {
 | 
			
		||||
	return autoConvert_v1beta4_UpgradeConfiguration_To_kubeadm_UpgradeConfiguration(in, out, s)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func autoConvert_kubeadm_UpgradeConfiguration_To_v1beta4_UpgradeConfiguration(in *kubeadm.UpgradeConfiguration, out *UpgradeConfiguration, s conversion.Scope) error {
 | 
			
		||||
	if err := Convert_kubeadm_UpgradeApplyConfiguration_To_v1beta4_UpgradeApplyConfiguration(&in.Apply, &out.Apply, s); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if err := Convert_kubeadm_UpgradeDiffConfiguration_To_v1beta4_UpgradeDiffConfiguration(&in.Diff, &out.Diff, s); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if err := Convert_kubeadm_UpgradeNodeConfiguration_To_v1beta4_UpgradeNodeConfiguration(&in.Node, &out.Node, s); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if err := Convert_kubeadm_UpgradePlanConfiguration_To_v1beta4_UpgradePlanConfiguration(&in.Plan, &out.Plan, s); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Convert_kubeadm_UpgradeConfiguration_To_v1beta4_UpgradeConfiguration is an autogenerated conversion function.
 | 
			
		||||
func Convert_kubeadm_UpgradeConfiguration_To_v1beta4_UpgradeConfiguration(in *kubeadm.UpgradeConfiguration, out *UpgradeConfiguration, s conversion.Scope) error {
 | 
			
		||||
	return autoConvert_kubeadm_UpgradeConfiguration_To_v1beta4_UpgradeConfiguration(in, out, s)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func autoConvert_v1beta4_UpgradeDiffConfiguration_To_kubeadm_UpgradeDiffConfiguration(in *UpgradeDiffConfiguration, out *kubeadm.UpgradeDiffConfiguration, s conversion.Scope) error {
 | 
			
		||||
	out.KubernetesVersion = in.KubernetesVersion
 | 
			
		||||
	out.DiffContextLines = in.DiffContextLines
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Convert_v1beta4_UpgradeDiffConfiguration_To_kubeadm_UpgradeDiffConfiguration is an autogenerated conversion function.
 | 
			
		||||
func Convert_v1beta4_UpgradeDiffConfiguration_To_kubeadm_UpgradeDiffConfiguration(in *UpgradeDiffConfiguration, out *kubeadm.UpgradeDiffConfiguration, s conversion.Scope) error {
 | 
			
		||||
	return autoConvert_v1beta4_UpgradeDiffConfiguration_To_kubeadm_UpgradeDiffConfiguration(in, out, s)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func autoConvert_kubeadm_UpgradeDiffConfiguration_To_v1beta4_UpgradeDiffConfiguration(in *kubeadm.UpgradeDiffConfiguration, out *UpgradeDiffConfiguration, s conversion.Scope) error {
 | 
			
		||||
	out.KubernetesVersion = in.KubernetesVersion
 | 
			
		||||
	out.DiffContextLines = in.DiffContextLines
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Convert_kubeadm_UpgradeDiffConfiguration_To_v1beta4_UpgradeDiffConfiguration is an autogenerated conversion function.
 | 
			
		||||
func Convert_kubeadm_UpgradeDiffConfiguration_To_v1beta4_UpgradeDiffConfiguration(in *kubeadm.UpgradeDiffConfiguration, out *UpgradeDiffConfiguration, s conversion.Scope) error {
 | 
			
		||||
	return autoConvert_kubeadm_UpgradeDiffConfiguration_To_v1beta4_UpgradeDiffConfiguration(in, out, s)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func autoConvert_v1beta4_UpgradeNodeConfiguration_To_kubeadm_UpgradeNodeConfiguration(in *UpgradeNodeConfiguration, out *kubeadm.UpgradeNodeConfiguration, s conversion.Scope) error {
 | 
			
		||||
	out.CertificateRenewal = (*bool)(unsafe.Pointer(in.CertificateRenewal))
 | 
			
		||||
	out.DryRun = (*bool)(unsafe.Pointer(in.DryRun))
 | 
			
		||||
	out.EtcdUpgrade = (*bool)(unsafe.Pointer(in.EtcdUpgrade))
 | 
			
		||||
	out.IgnorePreflightErrors = *(*[]string)(unsafe.Pointer(&in.IgnorePreflightErrors))
 | 
			
		||||
	out.SkipPhases = *(*[]string)(unsafe.Pointer(&in.SkipPhases))
 | 
			
		||||
	out.Patches = (*kubeadm.Patches)(unsafe.Pointer(in.Patches))
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Convert_v1beta4_UpgradeNodeConfiguration_To_kubeadm_UpgradeNodeConfiguration is an autogenerated conversion function.
 | 
			
		||||
func Convert_v1beta4_UpgradeNodeConfiguration_To_kubeadm_UpgradeNodeConfiguration(in *UpgradeNodeConfiguration, out *kubeadm.UpgradeNodeConfiguration, s conversion.Scope) error {
 | 
			
		||||
	return autoConvert_v1beta4_UpgradeNodeConfiguration_To_kubeadm_UpgradeNodeConfiguration(in, out, s)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func autoConvert_kubeadm_UpgradeNodeConfiguration_To_v1beta4_UpgradeNodeConfiguration(in *kubeadm.UpgradeNodeConfiguration, out *UpgradeNodeConfiguration, s conversion.Scope) error {
 | 
			
		||||
	out.CertificateRenewal = (*bool)(unsafe.Pointer(in.CertificateRenewal))
 | 
			
		||||
	out.DryRun = (*bool)(unsafe.Pointer(in.DryRun))
 | 
			
		||||
	out.EtcdUpgrade = (*bool)(unsafe.Pointer(in.EtcdUpgrade))
 | 
			
		||||
	out.IgnorePreflightErrors = *(*[]string)(unsafe.Pointer(&in.IgnorePreflightErrors))
 | 
			
		||||
	out.SkipPhases = *(*[]string)(unsafe.Pointer(&in.SkipPhases))
 | 
			
		||||
	out.Patches = (*Patches)(unsafe.Pointer(in.Patches))
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Convert_kubeadm_UpgradeNodeConfiguration_To_v1beta4_UpgradeNodeConfiguration is an autogenerated conversion function.
 | 
			
		||||
func Convert_kubeadm_UpgradeNodeConfiguration_To_v1beta4_UpgradeNodeConfiguration(in *kubeadm.UpgradeNodeConfiguration, out *UpgradeNodeConfiguration, s conversion.Scope) error {
 | 
			
		||||
	return autoConvert_kubeadm_UpgradeNodeConfiguration_To_v1beta4_UpgradeNodeConfiguration(in, out, s)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func autoConvert_v1beta4_UpgradePlanConfiguration_To_kubeadm_UpgradePlanConfiguration(in *UpgradePlanConfiguration, out *kubeadm.UpgradePlanConfiguration, s conversion.Scope) error {
 | 
			
		||||
	out.KubernetesVersion = in.KubernetesVersion
 | 
			
		||||
	out.AllowExperimentalUpgrades = (*bool)(unsafe.Pointer(in.AllowExperimentalUpgrades))
 | 
			
		||||
	out.AllowRCUpgrades = (*bool)(unsafe.Pointer(in.AllowRCUpgrades))
 | 
			
		||||
	out.DryRun = (*bool)(unsafe.Pointer(in.DryRun))
 | 
			
		||||
	out.IgnorePreflightErrors = *(*[]string)(unsafe.Pointer(&in.IgnorePreflightErrors))
 | 
			
		||||
	out.PrintConfig = (*bool)(unsafe.Pointer(in.PrintConfig))
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Convert_v1beta4_UpgradePlanConfiguration_To_kubeadm_UpgradePlanConfiguration is an autogenerated conversion function.
 | 
			
		||||
func Convert_v1beta4_UpgradePlanConfiguration_To_kubeadm_UpgradePlanConfiguration(in *UpgradePlanConfiguration, out *kubeadm.UpgradePlanConfiguration, s conversion.Scope) error {
 | 
			
		||||
	return autoConvert_v1beta4_UpgradePlanConfiguration_To_kubeadm_UpgradePlanConfiguration(in, out, s)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func autoConvert_kubeadm_UpgradePlanConfiguration_To_v1beta4_UpgradePlanConfiguration(in *kubeadm.UpgradePlanConfiguration, out *UpgradePlanConfiguration, s conversion.Scope) error {
 | 
			
		||||
	out.KubernetesVersion = in.KubernetesVersion
 | 
			
		||||
	out.AllowExperimentalUpgrades = (*bool)(unsafe.Pointer(in.AllowExperimentalUpgrades))
 | 
			
		||||
	out.AllowRCUpgrades = (*bool)(unsafe.Pointer(in.AllowRCUpgrades))
 | 
			
		||||
	out.DryRun = (*bool)(unsafe.Pointer(in.DryRun))
 | 
			
		||||
	out.IgnorePreflightErrors = *(*[]string)(unsafe.Pointer(&in.IgnorePreflightErrors))
 | 
			
		||||
	out.PrintConfig = (*bool)(unsafe.Pointer(in.PrintConfig))
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Convert_kubeadm_UpgradePlanConfiguration_To_v1beta4_UpgradePlanConfiguration is an autogenerated conversion function.
 | 
			
		||||
func Convert_kubeadm_UpgradePlanConfiguration_To_v1beta4_UpgradePlanConfiguration(in *kubeadm.UpgradePlanConfiguration, out *UpgradePlanConfiguration, s conversion.Scope) error {
 | 
			
		||||
	return autoConvert_kubeadm_UpgradePlanConfiguration_To_v1beta4_UpgradePlanConfiguration(in, out, s)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -658,3 +658,201 @@ func (in *Timeouts) DeepCopy() *Timeouts {
 | 
			
		||||
	in.DeepCopyInto(out)
 | 
			
		||||
	return out
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | 
			
		||||
func (in *UpgradeApplyConfiguration) DeepCopyInto(out *UpgradeApplyConfiguration) {
 | 
			
		||||
	*out = *in
 | 
			
		||||
	if in.AllowExperimentalUpgrades != nil {
 | 
			
		||||
		in, out := &in.AllowExperimentalUpgrades, &out.AllowExperimentalUpgrades
 | 
			
		||||
		*out = new(bool)
 | 
			
		||||
		**out = **in
 | 
			
		||||
	}
 | 
			
		||||
	if in.AllowRCUpgrades != nil {
 | 
			
		||||
		in, out := &in.AllowRCUpgrades, &out.AllowRCUpgrades
 | 
			
		||||
		*out = new(bool)
 | 
			
		||||
		**out = **in
 | 
			
		||||
	}
 | 
			
		||||
	if in.CertificateRenewal != nil {
 | 
			
		||||
		in, out := &in.CertificateRenewal, &out.CertificateRenewal
 | 
			
		||||
		*out = new(bool)
 | 
			
		||||
		**out = **in
 | 
			
		||||
	}
 | 
			
		||||
	if in.DryRun != nil {
 | 
			
		||||
		in, out := &in.DryRun, &out.DryRun
 | 
			
		||||
		*out = new(bool)
 | 
			
		||||
		**out = **in
 | 
			
		||||
	}
 | 
			
		||||
	if in.EtcdUpgrade != nil {
 | 
			
		||||
		in, out := &in.EtcdUpgrade, &out.EtcdUpgrade
 | 
			
		||||
		*out = new(bool)
 | 
			
		||||
		**out = **in
 | 
			
		||||
	}
 | 
			
		||||
	if in.ForceUpgrade != nil {
 | 
			
		||||
		in, out := &in.ForceUpgrade, &out.ForceUpgrade
 | 
			
		||||
		*out = new(bool)
 | 
			
		||||
		**out = **in
 | 
			
		||||
	}
 | 
			
		||||
	if in.IgnorePreflightErrors != nil {
 | 
			
		||||
		in, out := &in.IgnorePreflightErrors, &out.IgnorePreflightErrors
 | 
			
		||||
		*out = make([]string, len(*in))
 | 
			
		||||
		copy(*out, *in)
 | 
			
		||||
	}
 | 
			
		||||
	if in.Patches != nil {
 | 
			
		||||
		in, out := &in.Patches, &out.Patches
 | 
			
		||||
		*out = new(Patches)
 | 
			
		||||
		**out = **in
 | 
			
		||||
	}
 | 
			
		||||
	if in.PrintConfig != nil {
 | 
			
		||||
		in, out := &in.PrintConfig, &out.PrintConfig
 | 
			
		||||
		*out = new(bool)
 | 
			
		||||
		**out = **in
 | 
			
		||||
	}
 | 
			
		||||
	if in.SkipPhases != nil {
 | 
			
		||||
		in, out := &in.SkipPhases, &out.SkipPhases
 | 
			
		||||
		*out = make([]string, len(*in))
 | 
			
		||||
		copy(*out, *in)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UpgradeApplyConfiguration.
 | 
			
		||||
func (in *UpgradeApplyConfiguration) DeepCopy() *UpgradeApplyConfiguration {
 | 
			
		||||
	if in == nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	out := new(UpgradeApplyConfiguration)
 | 
			
		||||
	in.DeepCopyInto(out)
 | 
			
		||||
	return out
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | 
			
		||||
func (in *UpgradeConfiguration) DeepCopyInto(out *UpgradeConfiguration) {
 | 
			
		||||
	*out = *in
 | 
			
		||||
	out.TypeMeta = in.TypeMeta
 | 
			
		||||
	in.Apply.DeepCopyInto(&out.Apply)
 | 
			
		||||
	out.Diff = in.Diff
 | 
			
		||||
	in.Node.DeepCopyInto(&out.Node)
 | 
			
		||||
	in.Plan.DeepCopyInto(&out.Plan)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UpgradeConfiguration.
 | 
			
		||||
func (in *UpgradeConfiguration) DeepCopy() *UpgradeConfiguration {
 | 
			
		||||
	if in == nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	out := new(UpgradeConfiguration)
 | 
			
		||||
	in.DeepCopyInto(out)
 | 
			
		||||
	return out
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
 | 
			
		||||
func (in *UpgradeConfiguration) DeepCopyObject() runtime.Object {
 | 
			
		||||
	if c := in.DeepCopy(); c != nil {
 | 
			
		||||
		return c
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | 
			
		||||
func (in *UpgradeDiffConfiguration) DeepCopyInto(out *UpgradeDiffConfiguration) {
 | 
			
		||||
	*out = *in
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UpgradeDiffConfiguration.
 | 
			
		||||
func (in *UpgradeDiffConfiguration) DeepCopy() *UpgradeDiffConfiguration {
 | 
			
		||||
	if in == nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	out := new(UpgradeDiffConfiguration)
 | 
			
		||||
	in.DeepCopyInto(out)
 | 
			
		||||
	return out
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | 
			
		||||
func (in *UpgradeNodeConfiguration) DeepCopyInto(out *UpgradeNodeConfiguration) {
 | 
			
		||||
	*out = *in
 | 
			
		||||
	if in.CertificateRenewal != nil {
 | 
			
		||||
		in, out := &in.CertificateRenewal, &out.CertificateRenewal
 | 
			
		||||
		*out = new(bool)
 | 
			
		||||
		**out = **in
 | 
			
		||||
	}
 | 
			
		||||
	if in.DryRun != nil {
 | 
			
		||||
		in, out := &in.DryRun, &out.DryRun
 | 
			
		||||
		*out = new(bool)
 | 
			
		||||
		**out = **in
 | 
			
		||||
	}
 | 
			
		||||
	if in.EtcdUpgrade != nil {
 | 
			
		||||
		in, out := &in.EtcdUpgrade, &out.EtcdUpgrade
 | 
			
		||||
		*out = new(bool)
 | 
			
		||||
		**out = **in
 | 
			
		||||
	}
 | 
			
		||||
	if in.IgnorePreflightErrors != nil {
 | 
			
		||||
		in, out := &in.IgnorePreflightErrors, &out.IgnorePreflightErrors
 | 
			
		||||
		*out = make([]string, len(*in))
 | 
			
		||||
		copy(*out, *in)
 | 
			
		||||
	}
 | 
			
		||||
	if in.SkipPhases != nil {
 | 
			
		||||
		in, out := &in.SkipPhases, &out.SkipPhases
 | 
			
		||||
		*out = make([]string, len(*in))
 | 
			
		||||
		copy(*out, *in)
 | 
			
		||||
	}
 | 
			
		||||
	if in.Patches != nil {
 | 
			
		||||
		in, out := &in.Patches, &out.Patches
 | 
			
		||||
		*out = new(Patches)
 | 
			
		||||
		**out = **in
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UpgradeNodeConfiguration.
 | 
			
		||||
func (in *UpgradeNodeConfiguration) DeepCopy() *UpgradeNodeConfiguration {
 | 
			
		||||
	if in == nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	out := new(UpgradeNodeConfiguration)
 | 
			
		||||
	in.DeepCopyInto(out)
 | 
			
		||||
	return out
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | 
			
		||||
func (in *UpgradePlanConfiguration) DeepCopyInto(out *UpgradePlanConfiguration) {
 | 
			
		||||
	*out = *in
 | 
			
		||||
	if in.AllowExperimentalUpgrades != nil {
 | 
			
		||||
		in, out := &in.AllowExperimentalUpgrades, &out.AllowExperimentalUpgrades
 | 
			
		||||
		*out = new(bool)
 | 
			
		||||
		**out = **in
 | 
			
		||||
	}
 | 
			
		||||
	if in.AllowRCUpgrades != nil {
 | 
			
		||||
		in, out := &in.AllowRCUpgrades, &out.AllowRCUpgrades
 | 
			
		||||
		*out = new(bool)
 | 
			
		||||
		**out = **in
 | 
			
		||||
	}
 | 
			
		||||
	if in.DryRun != nil {
 | 
			
		||||
		in, out := &in.DryRun, &out.DryRun
 | 
			
		||||
		*out = new(bool)
 | 
			
		||||
		**out = **in
 | 
			
		||||
	}
 | 
			
		||||
	if in.IgnorePreflightErrors != nil {
 | 
			
		||||
		in, out := &in.IgnorePreflightErrors, &out.IgnorePreflightErrors
 | 
			
		||||
		*out = make([]string, len(*in))
 | 
			
		||||
		copy(*out, *in)
 | 
			
		||||
	}
 | 
			
		||||
	if in.PrintConfig != nil {
 | 
			
		||||
		in, out := &in.PrintConfig, &out.PrintConfig
 | 
			
		||||
		*out = new(bool)
 | 
			
		||||
		**out = **in
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UpgradePlanConfiguration.
 | 
			
		||||
func (in *UpgradePlanConfiguration) DeepCopy() *UpgradePlanConfiguration {
 | 
			
		||||
	if in == nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	out := new(UpgradePlanConfiguration)
 | 
			
		||||
	in.DeepCopyInto(out)
 | 
			
		||||
	return out
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -33,6 +33,7 @@ func RegisterDefaults(scheme *runtime.Scheme) error {
 | 
			
		||||
	scheme.AddTypeDefaultingFunc(&InitConfiguration{}, func(obj interface{}) { SetObjectDefaults_InitConfiguration(obj.(*InitConfiguration)) })
 | 
			
		||||
	scheme.AddTypeDefaultingFunc(&JoinConfiguration{}, func(obj interface{}) { SetObjectDefaults_JoinConfiguration(obj.(*JoinConfiguration)) })
 | 
			
		||||
	scheme.AddTypeDefaultingFunc(&ResetConfiguration{}, func(obj interface{}) { SetObjectDefaults_ResetConfiguration(obj.(*ResetConfiguration)) })
 | 
			
		||||
	scheme.AddTypeDefaultingFunc(&UpgradeConfiguration{}, func(obj interface{}) { SetObjectDefaults_UpgradeConfiguration(obj.(*UpgradeConfiguration)) })
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -87,3 +88,7 @@ func SetObjectDefaults_ResetConfiguration(in *ResetConfiguration) {
 | 
			
		||||
		SetDefaults_Timeouts(in.Timeouts)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func SetObjectDefaults_UpgradeConfiguration(in *UpgradeConfiguration) {
 | 
			
		||||
	SetDefaults_UpgradeConfiguration(in)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -758,3 +758,12 @@ func ValidateImagePullPolicy(policy corev1.PullPolicy, fldPath *field.Path) fiel
 | 
			
		||||
		return allErrs
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ValidateUpgradeConfiguration validates a UpgradeConfiguration object and collects all encountered errors
 | 
			
		||||
func ValidateUpgradeConfiguration(c *kubeadm.UpgradeConfiguration) field.ErrorList {
 | 
			
		||||
	allErrs := field.ErrorList{}
 | 
			
		||||
	if c.Apply.Patches != nil {
 | 
			
		||||
		allErrs = append(allErrs, ValidateAbsolutePath(c.Apply.Patches.Directory, field.NewPath("patches").Child("directory"))...)
 | 
			
		||||
	}
 | 
			
		||||
	return allErrs
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -744,11 +744,14 @@ func TestValidateMixedArguments(t *testing.T) {
 | 
			
		||||
		{[]string{"--foo=bar"}, true},
 | 
			
		||||
		{[]string{"--config=hello"}, true},
 | 
			
		||||
		{[]string{"--config=hello", "--ignore-preflight-errors=all"}, true},
 | 
			
		||||
		// Expected to succeed, --config is mixed with skip-* flags only or no other flags
 | 
			
		||||
		{[]string{"--config=hello", "--skip-token-print=true"}, true},
 | 
			
		||||
		{[]string{"--config=hello", "--ignore-preflight-errors=baz", "--skip-token-print"}, true},
 | 
			
		||||
		// Expected to fail, --config is mixed with the --foo flag
 | 
			
		||||
		{[]string{"--config=hello", "--ignore-preflight-errors=baz", "--foo=bar"}, false},
 | 
			
		||||
		{[]string{"--config=hello", "--foo=bar"}, false},
 | 
			
		||||
		// Expected to fail, --config is mixed with the upgrade related flag
 | 
			
		||||
		{[]string{"--config=hello", "--allow-experimental-upgrades"}, false},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var cfgPath string
 | 
			
		||||
@@ -760,6 +763,7 @@ func TestValidateMixedArguments(t *testing.T) {
 | 
			
		||||
		}
 | 
			
		||||
		f.String("foo", "", "flag bound to config object")
 | 
			
		||||
		f.StringSliceVar(&ignorePreflightErrors, "ignore-preflight-errors", ignorePreflightErrors, "flag not bound to config object")
 | 
			
		||||
		f.Bool("allow-experimental-upgrades", true, "upgrade flags for plan and apply command")
 | 
			
		||||
		f.Bool("skip-token-print", false, "flag not bound to config object")
 | 
			
		||||
		f.StringVar(&cfgPath, "config", cfgPath, "Path to kubeadm config file")
 | 
			
		||||
		if err := f.Parse(rt.args); err != nil {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										198
									
								
								cmd/kubeadm/app/apis/kubeadm/zz_generated.deepcopy.go
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										198
									
								
								cmd/kubeadm/app/apis/kubeadm/zz_generated.deepcopy.go
									
									
									
										generated
									
									
									
								
							@@ -698,3 +698,201 @@ func (in *Timeouts) DeepCopy() *Timeouts {
 | 
			
		||||
	in.DeepCopyInto(out)
 | 
			
		||||
	return out
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | 
			
		||||
func (in *UpgradeApplyConfiguration) DeepCopyInto(out *UpgradeApplyConfiguration) {
 | 
			
		||||
	*out = *in
 | 
			
		||||
	if in.AllowExperimentalUpgrades != nil {
 | 
			
		||||
		in, out := &in.AllowExperimentalUpgrades, &out.AllowExperimentalUpgrades
 | 
			
		||||
		*out = new(bool)
 | 
			
		||||
		**out = **in
 | 
			
		||||
	}
 | 
			
		||||
	if in.AllowRCUpgrades != nil {
 | 
			
		||||
		in, out := &in.AllowRCUpgrades, &out.AllowRCUpgrades
 | 
			
		||||
		*out = new(bool)
 | 
			
		||||
		**out = **in
 | 
			
		||||
	}
 | 
			
		||||
	if in.CertificateRenewal != nil {
 | 
			
		||||
		in, out := &in.CertificateRenewal, &out.CertificateRenewal
 | 
			
		||||
		*out = new(bool)
 | 
			
		||||
		**out = **in
 | 
			
		||||
	}
 | 
			
		||||
	if in.DryRun != nil {
 | 
			
		||||
		in, out := &in.DryRun, &out.DryRun
 | 
			
		||||
		*out = new(bool)
 | 
			
		||||
		**out = **in
 | 
			
		||||
	}
 | 
			
		||||
	if in.EtcdUpgrade != nil {
 | 
			
		||||
		in, out := &in.EtcdUpgrade, &out.EtcdUpgrade
 | 
			
		||||
		*out = new(bool)
 | 
			
		||||
		**out = **in
 | 
			
		||||
	}
 | 
			
		||||
	if in.ForceUpgrade != nil {
 | 
			
		||||
		in, out := &in.ForceUpgrade, &out.ForceUpgrade
 | 
			
		||||
		*out = new(bool)
 | 
			
		||||
		**out = **in
 | 
			
		||||
	}
 | 
			
		||||
	if in.IgnorePreflightErrors != nil {
 | 
			
		||||
		in, out := &in.IgnorePreflightErrors, &out.IgnorePreflightErrors
 | 
			
		||||
		*out = make([]string, len(*in))
 | 
			
		||||
		copy(*out, *in)
 | 
			
		||||
	}
 | 
			
		||||
	if in.Patches != nil {
 | 
			
		||||
		in, out := &in.Patches, &out.Patches
 | 
			
		||||
		*out = new(Patches)
 | 
			
		||||
		**out = **in
 | 
			
		||||
	}
 | 
			
		||||
	if in.PrintConfig != nil {
 | 
			
		||||
		in, out := &in.PrintConfig, &out.PrintConfig
 | 
			
		||||
		*out = new(bool)
 | 
			
		||||
		**out = **in
 | 
			
		||||
	}
 | 
			
		||||
	if in.SkipPhases != nil {
 | 
			
		||||
		in, out := &in.SkipPhases, &out.SkipPhases
 | 
			
		||||
		*out = make([]string, len(*in))
 | 
			
		||||
		copy(*out, *in)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UpgradeApplyConfiguration.
 | 
			
		||||
func (in *UpgradeApplyConfiguration) DeepCopy() *UpgradeApplyConfiguration {
 | 
			
		||||
	if in == nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	out := new(UpgradeApplyConfiguration)
 | 
			
		||||
	in.DeepCopyInto(out)
 | 
			
		||||
	return out
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | 
			
		||||
func (in *UpgradeConfiguration) DeepCopyInto(out *UpgradeConfiguration) {
 | 
			
		||||
	*out = *in
 | 
			
		||||
	out.TypeMeta = in.TypeMeta
 | 
			
		||||
	in.Apply.DeepCopyInto(&out.Apply)
 | 
			
		||||
	out.Diff = in.Diff
 | 
			
		||||
	in.Node.DeepCopyInto(&out.Node)
 | 
			
		||||
	in.Plan.DeepCopyInto(&out.Plan)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UpgradeConfiguration.
 | 
			
		||||
func (in *UpgradeConfiguration) DeepCopy() *UpgradeConfiguration {
 | 
			
		||||
	if in == nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	out := new(UpgradeConfiguration)
 | 
			
		||||
	in.DeepCopyInto(out)
 | 
			
		||||
	return out
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
 | 
			
		||||
func (in *UpgradeConfiguration) DeepCopyObject() runtime.Object {
 | 
			
		||||
	if c := in.DeepCopy(); c != nil {
 | 
			
		||||
		return c
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | 
			
		||||
func (in *UpgradeDiffConfiguration) DeepCopyInto(out *UpgradeDiffConfiguration) {
 | 
			
		||||
	*out = *in
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UpgradeDiffConfiguration.
 | 
			
		||||
func (in *UpgradeDiffConfiguration) DeepCopy() *UpgradeDiffConfiguration {
 | 
			
		||||
	if in == nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	out := new(UpgradeDiffConfiguration)
 | 
			
		||||
	in.DeepCopyInto(out)
 | 
			
		||||
	return out
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | 
			
		||||
func (in *UpgradeNodeConfiguration) DeepCopyInto(out *UpgradeNodeConfiguration) {
 | 
			
		||||
	*out = *in
 | 
			
		||||
	if in.CertificateRenewal != nil {
 | 
			
		||||
		in, out := &in.CertificateRenewal, &out.CertificateRenewal
 | 
			
		||||
		*out = new(bool)
 | 
			
		||||
		**out = **in
 | 
			
		||||
	}
 | 
			
		||||
	if in.DryRun != nil {
 | 
			
		||||
		in, out := &in.DryRun, &out.DryRun
 | 
			
		||||
		*out = new(bool)
 | 
			
		||||
		**out = **in
 | 
			
		||||
	}
 | 
			
		||||
	if in.EtcdUpgrade != nil {
 | 
			
		||||
		in, out := &in.EtcdUpgrade, &out.EtcdUpgrade
 | 
			
		||||
		*out = new(bool)
 | 
			
		||||
		**out = **in
 | 
			
		||||
	}
 | 
			
		||||
	if in.IgnorePreflightErrors != nil {
 | 
			
		||||
		in, out := &in.IgnorePreflightErrors, &out.IgnorePreflightErrors
 | 
			
		||||
		*out = make([]string, len(*in))
 | 
			
		||||
		copy(*out, *in)
 | 
			
		||||
	}
 | 
			
		||||
	if in.SkipPhases != nil {
 | 
			
		||||
		in, out := &in.SkipPhases, &out.SkipPhases
 | 
			
		||||
		*out = make([]string, len(*in))
 | 
			
		||||
		copy(*out, *in)
 | 
			
		||||
	}
 | 
			
		||||
	if in.Patches != nil {
 | 
			
		||||
		in, out := &in.Patches, &out.Patches
 | 
			
		||||
		*out = new(Patches)
 | 
			
		||||
		**out = **in
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UpgradeNodeConfiguration.
 | 
			
		||||
func (in *UpgradeNodeConfiguration) DeepCopy() *UpgradeNodeConfiguration {
 | 
			
		||||
	if in == nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	out := new(UpgradeNodeConfiguration)
 | 
			
		||||
	in.DeepCopyInto(out)
 | 
			
		||||
	return out
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | 
			
		||||
func (in *UpgradePlanConfiguration) DeepCopyInto(out *UpgradePlanConfiguration) {
 | 
			
		||||
	*out = *in
 | 
			
		||||
	if in.AllowExperimentalUpgrades != nil {
 | 
			
		||||
		in, out := &in.AllowExperimentalUpgrades, &out.AllowExperimentalUpgrades
 | 
			
		||||
		*out = new(bool)
 | 
			
		||||
		**out = **in
 | 
			
		||||
	}
 | 
			
		||||
	if in.AllowRCUpgrades != nil {
 | 
			
		||||
		in, out := &in.AllowRCUpgrades, &out.AllowRCUpgrades
 | 
			
		||||
		*out = new(bool)
 | 
			
		||||
		**out = **in
 | 
			
		||||
	}
 | 
			
		||||
	if in.DryRun != nil {
 | 
			
		||||
		in, out := &in.DryRun, &out.DryRun
 | 
			
		||||
		*out = new(bool)
 | 
			
		||||
		**out = **in
 | 
			
		||||
	}
 | 
			
		||||
	if in.IgnorePreflightErrors != nil {
 | 
			
		||||
		in, out := &in.IgnorePreflightErrors, &out.IgnorePreflightErrors
 | 
			
		||||
		*out = make([]string, len(*in))
 | 
			
		||||
		copy(*out, *in)
 | 
			
		||||
	}
 | 
			
		||||
	if in.PrintConfig != nil {
 | 
			
		||||
		in, out := &in.PrintConfig, &out.PrintConfig
 | 
			
		||||
		*out = new(bool)
 | 
			
		||||
		**out = **in
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UpgradePlanConfiguration.
 | 
			
		||||
func (in *UpgradePlanConfiguration) DeepCopy() *UpgradePlanConfiguration {
 | 
			
		||||
	if in == nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	out := new(UpgradePlanConfiguration)
 | 
			
		||||
	in.DeepCopyInto(out)
 | 
			
		||||
	return out
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -145,4 +145,13 @@ const (
 | 
			
		||||
 | 
			
		||||
	// AllowExperimentalAPI flag can be used to allow experimental / work in progress APIs
 | 
			
		||||
	AllowExperimentalAPI = "allow-experimental-api"
 | 
			
		||||
 | 
			
		||||
	// AllowRCUpgrades enable this flag will allow upgrading to a release candidate version of Kubernetes.
 | 
			
		||||
	AllowRCUpgrades = "allow-release-candidate-upgrades"
 | 
			
		||||
 | 
			
		||||
	// AllowExperimentalUpgrades enable this flag will allow upgrading to an alpha/beta/release candidate version of Kubernetes.
 | 
			
		||||
	AllowExperimentalUpgrades = "allow-experimental-upgrades"
 | 
			
		||||
 | 
			
		||||
	// PrintConfig specifies whether the cluster configuration that will be used in the upgrade should be printed or not.
 | 
			
		||||
	PrintConfig = "print-config"
 | 
			
		||||
)
 | 
			
		||||
 
 | 
			
		||||
@@ -60,7 +60,7 @@ func runControlPlane() func(c workflow.RunData) error {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// otherwise, retrieve all the info required for control plane upgrade
 | 
			
		||||
		cfg := data.Cfg()
 | 
			
		||||
		cfg := data.InitCfg()
 | 
			
		||||
		client := data.Client()
 | 
			
		||||
		dryRun := data.DryRun()
 | 
			
		||||
		etcdUpgrade := data.EtcdUpgrade()
 | 
			
		||||
 
 | 
			
		||||
@@ -31,7 +31,8 @@ type Data interface {
 | 
			
		||||
	EtcdUpgrade() bool
 | 
			
		||||
	RenewCerts() bool
 | 
			
		||||
	DryRun() bool
 | 
			
		||||
	Cfg() *kubeadmapi.InitConfiguration
 | 
			
		||||
	Cfg() *kubeadmapi.UpgradeConfiguration
 | 
			
		||||
	InitCfg() *kubeadmapi.InitConfiguration
 | 
			
		||||
	IsControlPlaneNode() bool
 | 
			
		||||
	Client() clientset.Interface
 | 
			
		||||
	IgnorePreflightErrors() sets.Set[string]
 | 
			
		||||
 
 | 
			
		||||
@@ -34,7 +34,8 @@ var _ Data = &testData{}
 | 
			
		||||
func (t *testData) EtcdUpgrade() bool                       { return false }
 | 
			
		||||
func (t *testData) RenewCerts() bool                        { return false }
 | 
			
		||||
func (t *testData) DryRun() bool                            { return false }
 | 
			
		||||
func (t *testData) Cfg() *kubeadmapi.InitConfiguration      { return nil }
 | 
			
		||||
func (t *testData) Cfg() *kubeadmapi.UpgradeConfiguration   { return nil }
 | 
			
		||||
func (t *testData) InitCfg() *kubeadmapi.InitConfiguration  { return nil }
 | 
			
		||||
func (t *testData) IsControlPlaneNode() bool                { return false }
 | 
			
		||||
func (t *testData) Client() clientset.Interface             { return nil }
 | 
			
		||||
func (t *testData) IgnorePreflightErrors() sets.Set[string] { return nil }
 | 
			
		||||
 
 | 
			
		||||
@@ -57,7 +57,7 @@ func runKubeletConfigPhase() func(c workflow.RunData) error {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// otherwise, retrieve all the info required for kubelet config upgrade
 | 
			
		||||
		cfg := data.Cfg()
 | 
			
		||||
		cfg := data.InitCfg()
 | 
			
		||||
		dryRun := data.DryRun()
 | 
			
		||||
 | 
			
		||||
		// Write the configuration for the kubelet down to disk and print the generated manifests instead if dry-running.
 | 
			
		||||
 
 | 
			
		||||
@@ -60,7 +60,7 @@ func runPreflight(c workflow.RunData) error {
 | 
			
		||||
			fmt.Println("[preflight] Pulling images required for setting up a Kubernetes cluster")
 | 
			
		||||
			fmt.Println("[preflight] This might take a minute or two, depending on the speed of your internet connection")
 | 
			
		||||
			fmt.Println("[preflight] You can also perform this action in beforehand using 'kubeadm config images pull'")
 | 
			
		||||
			if err := preflight.RunPullImagesCheck(utilsexec.New(), data.Cfg(), data.IgnorePreflightErrors()); err != nil {
 | 
			
		||||
			if err := preflight.RunPullImagesCheck(utilsexec.New(), data.InitCfg(), data.IgnorePreflightErrors()); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
 
 | 
			
		||||
@@ -22,6 +22,7 @@ import (
 | 
			
		||||
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
	"github.com/spf13/cobra"
 | 
			
		||||
	"github.com/spf13/pflag"
 | 
			
		||||
 | 
			
		||||
	"k8s.io/apimachinery/pkg/util/sets"
 | 
			
		||||
	"k8s.io/apimachinery/pkg/util/version"
 | 
			
		||||
@@ -30,6 +31,7 @@ import (
 | 
			
		||||
	utilsexec "k8s.io/utils/exec"
 | 
			
		||||
 | 
			
		||||
	kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
 | 
			
		||||
	"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation"
 | 
			
		||||
	"k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
 | 
			
		||||
	cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util"
 | 
			
		||||
	"k8s.io/kubernetes/cmd/kubeadm/app/features"
 | 
			
		||||
@@ -71,7 +73,10 @@ func newCmdApply(apf *applyPlanFlags) *cobra.Command {
 | 
			
		||||
		DisableFlagsInUseLine: true,
 | 
			
		||||
		Short:                 "Upgrade your Kubernetes cluster to the specified version",
 | 
			
		||||
		RunE: func(cmd *cobra.Command, args []string) error {
 | 
			
		||||
			return runApply(flags, args)
 | 
			
		||||
			if err := validation.ValidateMixedArguments(cmd.Flags()); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			return runApply(cmd.Flags(), flags, args)
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -81,7 +86,7 @@ func newCmdApply(apf *applyPlanFlags) *cobra.Command {
 | 
			
		||||
	cmd.Flags().BoolVarP(&flags.nonInteractiveMode, "yes", "y", flags.nonInteractiveMode, "Perform the upgrade and do not prompt for confirmation (non-interactive mode).")
 | 
			
		||||
	cmd.Flags().BoolVarP(&flags.force, "force", "f", flags.force, "Force upgrading although some requirements might not be met. This also implies non-interactive mode.")
 | 
			
		||||
	cmd.Flags().BoolVar(&flags.dryRun, options.DryRun, flags.dryRun, "Do not change any state, just output what actions would be performed.")
 | 
			
		||||
	cmd.Flags().BoolVar(&flags.etcdUpgrade, "etcd-upgrade", flags.etcdUpgrade, "Perform the upgrade of etcd.")
 | 
			
		||||
	cmd.Flags().BoolVar(&flags.etcdUpgrade, options.EtcdUpgrade, flags.etcdUpgrade, "Perform the upgrade of etcd.")
 | 
			
		||||
	cmd.Flags().BoolVar(&flags.renewCerts, options.CertificateRenewal, flags.renewCerts, "Perform the renewal of certificates used by component changed during upgrades.")
 | 
			
		||||
	options.AddPatchesFlag(cmd.Flags(), &flags.patchesDir)
 | 
			
		||||
 | 
			
		||||
@@ -100,39 +105,67 @@ func newCmdApply(apf *applyPlanFlags) *cobra.Command {
 | 
			
		||||
//   - Uploads the newly used configuration to the cluster ConfigMap
 | 
			
		||||
//   - Creating the RBAC rules for the bootstrap tokens and the cluster-info ConfigMap
 | 
			
		||||
//   - Applying new CoreDNS and kube-proxy manifests
 | 
			
		||||
func runApply(flags *applyFlags, args []string) error {
 | 
			
		||||
func runApply(flagSet *pflag.FlagSet, flags *applyFlags, args []string) error {
 | 
			
		||||
 | 
			
		||||
	// Start with the basics, verify that the cluster is healthy and get the configuration from the cluster (using the ConfigMap)
 | 
			
		||||
	klog.V(1).Infoln("[upgrade/apply] verifying health of cluster")
 | 
			
		||||
	klog.V(1).Infoln("[upgrade/apply] retrieving configuration from cluster")
 | 
			
		||||
	client, versionGetter, cfg, err := enforceRequirements(flags.applyPlanFlags, args, flags.dryRun, true, &output.TextPrinter{}, loadConfig)
 | 
			
		||||
	client, versionGetter, initCfg, upgradeCfg, err := enforceRequirements(flagSet, flags.applyPlanFlags, args, flags.dryRun, true, &output.TextPrinter{})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Validate requested and validate actual version
 | 
			
		||||
	klog.V(1).Infoln("[upgrade/apply] validating requested and actual version")
 | 
			
		||||
	if err := configutil.NormalizeKubernetesVersion(&cfg.ClusterConfiguration); err != nil {
 | 
			
		||||
	if err := configutil.NormalizeKubernetesVersion(&initCfg.ClusterConfiguration); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Use normalized version string in all following code.
 | 
			
		||||
	newK8sVersion, err := version.ParseSemantic(cfg.KubernetesVersion)
 | 
			
		||||
	newK8sVersion, err := version.ParseSemantic(initCfg.KubernetesVersion)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return errors.Errorf("unable to parse normalized version %q as a semantic version", cfg.KubernetesVersion)
 | 
			
		||||
		return errors.Errorf("unable to parse normalized version %q as a semantic version", initCfg.KubernetesVersion)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := features.ValidateVersion(features.InitFeatureGates, cfg.FeatureGates, cfg.KubernetesVersion); err != nil {
 | 
			
		||||
	if err := features.ValidateVersion(features.InitFeatureGates, initCfg.FeatureGates, initCfg.KubernetesVersion); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Enforce the version skew policies
 | 
			
		||||
	klog.V(1).Infoln("[upgrade/version] enforcing version skew policies")
 | 
			
		||||
	if err := EnforceVersionPolicies(cfg.KubernetesVersion, newK8sVersion, flags, versionGetter); err != nil {
 | 
			
		||||
	allowRCUpgrades, ok := cmdutil.ValueFromFlagsOrConfig(flagSet, options.AllowRCUpgrades, upgradeCfg.Apply.AllowRCUpgrades, &flags.allowRCUpgrades).(*bool)
 | 
			
		||||
	if ok {
 | 
			
		||||
		flags.allowRCUpgrades = *allowRCUpgrades
 | 
			
		||||
	} else {
 | 
			
		||||
		return cmdutil.TypeMismatchErr("allowRCUpgrades", "bool")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	force, ok := cmdutil.ValueFromFlagsOrConfig(flagSet, "force", upgradeCfg.Apply.ForceUpgrade, &flags.force).(*bool)
 | 
			
		||||
	if ok {
 | 
			
		||||
		flags.force = *force
 | 
			
		||||
	} else {
 | 
			
		||||
		return cmdutil.TypeMismatchErr("force", "bool")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	allowExperimentalUpgrades, ok := cmdutil.ValueFromFlagsOrConfig(flagSet, options.AllowExperimentalUpgrades, upgradeCfg.Apply.AllowExperimentalUpgrades, &flags.allowExperimentalUpgrades).(*bool)
 | 
			
		||||
	if ok {
 | 
			
		||||
		flags.allowExperimentalUpgrades = *allowExperimentalUpgrades
 | 
			
		||||
	} else {
 | 
			
		||||
		return cmdutil.TypeMismatchErr("allowExperimentalUpgrades", "bool")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := EnforceVersionPolicies(initCfg.KubernetesVersion, newK8sVersion, flags, versionGetter); err != nil {
 | 
			
		||||
		return errors.Wrap(err, "[upgrade/version] FATAL")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// If the current session is interactive, ask the user whether they really want to upgrade.
 | 
			
		||||
	dryRun, ok := cmdutil.ValueFromFlagsOrConfig(flagSet, options.DryRun, upgradeCfg.Apply.DryRun, &flags.dryRun).(*bool)
 | 
			
		||||
	if ok {
 | 
			
		||||
		flags.dryRun = *dryRun
 | 
			
		||||
	} else {
 | 
			
		||||
		return cmdutil.TypeMismatchErr("dryRun", "bool")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if flags.sessionIsInteractive() {
 | 
			
		||||
		if err := cmdutil.InteractivelyConfirmAction("upgrade", "Are you sure you want to proceed?", os.Stdin); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
@@ -143,7 +176,7 @@ func runApply(flags *applyFlags, args []string) error {
 | 
			
		||||
		fmt.Println("[upgrade/prepull] Pulling images required for setting up a Kubernetes cluster")
 | 
			
		||||
		fmt.Println("[upgrade/prepull] This might take a minute or two, depending on the speed of your internet connection")
 | 
			
		||||
		fmt.Println("[upgrade/prepull] You can also perform this action in beforehand using 'kubeadm config images pull'")
 | 
			
		||||
		if err := preflight.RunPullImagesCheck(utilsexec.New(), cfg, sets.New(cfg.NodeRegistration.IgnorePreflightErrors...)); err != nil {
 | 
			
		||||
		if err := preflight.RunPullImagesCheck(utilsexec.New(), initCfg, sets.New(upgradeCfg.Apply.IgnorePreflightErrors...)); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
@@ -152,14 +185,35 @@ func runApply(flags *applyFlags, args []string) error {
 | 
			
		||||
 | 
			
		||||
	waiter := getWaiter(flags.dryRun, client, upgrade.UpgradeManifestTimeout)
 | 
			
		||||
 | 
			
		||||
	// If the config is set by flag, just overwrite it!
 | 
			
		||||
	etcdUpgrade, ok := cmdutil.ValueFromFlagsOrConfig(flagSet, options.EtcdUpgrade, upgradeCfg.Apply.EtcdUpgrade, &flags.etcdUpgrade).(*bool)
 | 
			
		||||
	if ok {
 | 
			
		||||
		upgradeCfg.Apply.EtcdUpgrade = etcdUpgrade
 | 
			
		||||
	} else {
 | 
			
		||||
		return cmdutil.TypeMismatchErr("etcdUpgrade", "bool")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	renewCerts, ok := cmdutil.ValueFromFlagsOrConfig(flagSet, options.CertificateRenewal, upgradeCfg.Apply.CertificateRenewal, &flags.renewCerts).(*bool)
 | 
			
		||||
	if ok {
 | 
			
		||||
		upgradeCfg.Apply.CertificateRenewal = renewCerts
 | 
			
		||||
	} else {
 | 
			
		||||
		return cmdutil.TypeMismatchErr("renewCerts", "bool")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(flags.patchesDir) > 0 {
 | 
			
		||||
		upgradeCfg.Apply.Patches = &kubeadmapi.Patches{Directory: flags.patchesDir}
 | 
			
		||||
	} else if upgradeCfg.Apply.Patches == nil {
 | 
			
		||||
		upgradeCfg.Apply.Patches = &kubeadmapi.Patches{}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Now; perform the upgrade procedure
 | 
			
		||||
	if err := PerformControlPlaneUpgrade(flags, client, waiter, cfg); err != nil {
 | 
			
		||||
	if err := PerformControlPlaneUpgrade(flags, client, waiter, initCfg, upgradeCfg); err != nil {
 | 
			
		||||
		return errors.Wrap(err, "[upgrade/apply] FATAL")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Upgrade RBAC rules and addons.
 | 
			
		||||
	klog.V(1).Infoln("[upgrade/postupgrade] upgrading RBAC rules and addons")
 | 
			
		||||
	if err := upgrade.PerformPostUpgradeTasks(client, cfg, flags.patchesDir, flags.dryRun, flags.applyPlanFlags.out); err != nil {
 | 
			
		||||
	if err := upgrade.PerformPostUpgradeTasks(client, initCfg, upgradeCfg.Apply.Patches.Directory, flags.dryRun, flags.applyPlanFlags.out); err != nil {
 | 
			
		||||
		return errors.Wrap(err, "[upgrade/postupgrade] FATAL post-upgrade error")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -169,7 +223,7 @@ func runApply(flags *applyFlags, args []string) error {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fmt.Println("")
 | 
			
		||||
	fmt.Printf("[upgrade/successful] SUCCESS! Your cluster was upgraded to %q. Enjoy!\n", cfg.KubernetesVersion)
 | 
			
		||||
	fmt.Printf("[upgrade/successful] SUCCESS! Your cluster was upgraded to %q. Enjoy!\n", initCfg.KubernetesVersion)
 | 
			
		||||
	fmt.Println("")
 | 
			
		||||
	fmt.Println("[upgrade/kubelet] Now that your control plane is upgraded, please proceed with upgrading your kubelets if you haven't already done so.")
 | 
			
		||||
 | 
			
		||||
@@ -203,15 +257,14 @@ func EnforceVersionPolicies(newK8sVersionStr string, newK8sVersion *version.Vers
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PerformControlPlaneUpgrade actually performs the upgrade procedure for the cluster of your type (self-hosted or static-pod-hosted)
 | 
			
		||||
func PerformControlPlaneUpgrade(flags *applyFlags, client clientset.Interface, waiter apiclient.Waiter, internalcfg *kubeadmapi.InitConfiguration) error {
 | 
			
		||||
 | 
			
		||||
func PerformControlPlaneUpgrade(flags *applyFlags, client clientset.Interface, waiter apiclient.Waiter, initCfg *kubeadmapi.InitConfiguration, upgradeCfg *kubeadmapi.UpgradeConfiguration) error {
 | 
			
		||||
	// OK, the cluster is hosted using static pods. Upgrade a static-pod hosted cluster
 | 
			
		||||
	fmt.Printf("[upgrade/apply] Upgrading your Static Pod-hosted control plane to version %q (timeout: %v)...\n",
 | 
			
		||||
		internalcfg.KubernetesVersion, upgrade.UpgradeManifestTimeout)
 | 
			
		||||
		initCfg.KubernetesVersion, upgrade.UpgradeManifestTimeout)
 | 
			
		||||
 | 
			
		||||
	if flags.dryRun {
 | 
			
		||||
		return upgrade.DryRunStaticPodUpgrade(flags.patchesDir, internalcfg)
 | 
			
		||||
		return upgrade.DryRunStaticPodUpgrade(upgradeCfg.Apply.Patches.Directory, initCfg)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return upgrade.PerformStaticPodUpgrade(client, waiter, internalcfg, flags.etcdUpgrade, flags.renewCerts, flags.patchesDir)
 | 
			
		||||
	return upgrade.PerformStaticPodUpgrade(client, waiter, initCfg, *upgradeCfg.Apply.EtcdUpgrade, *upgradeCfg.Apply.CertificateRenewal, upgradeCfg.Apply.Patches.Directory)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -24,21 +24,25 @@ import (
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
	"github.com/spf13/pflag"
 | 
			
		||||
 | 
			
		||||
	apierrors "k8s.io/apimachinery/pkg/api/errors"
 | 
			
		||||
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
			
		||||
	"k8s.io/apimachinery/pkg/util/sets"
 | 
			
		||||
	fakediscovery "k8s.io/client-go/discovery/fake"
 | 
			
		||||
	clientset "k8s.io/client-go/kubernetes"
 | 
			
		||||
	"k8s.io/klog/v2"
 | 
			
		||||
	"k8s.io/utils/ptr"
 | 
			
		||||
 | 
			
		||||
	kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
 | 
			
		||||
	kubeadmapiv1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta3"
 | 
			
		||||
	"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation"
 | 
			
		||||
	"k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
 | 
			
		||||
	cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util"
 | 
			
		||||
	"k8s.io/kubernetes/cmd/kubeadm/app/componentconfigs"
 | 
			
		||||
	"k8s.io/kubernetes/cmd/kubeadm/app/constants"
 | 
			
		||||
	"k8s.io/kubernetes/cmd/kubeadm/app/features"
 | 
			
		||||
	"k8s.io/kubernetes/cmd/kubeadm/app/phases/upgrade"
 | 
			
		||||
	"k8s.io/kubernetes/cmd/kubeadm/app/preflight"
 | 
			
		||||
	kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
 | 
			
		||||
	"k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
 | 
			
		||||
	configutil "k8s.io/kubernetes/cmd/kubeadm/app/util/config"
 | 
			
		||||
	dryrunutil "k8s.io/kubernetes/cmd/kubeadm/app/util/dryrun"
 | 
			
		||||
@@ -46,162 +50,121 @@ import (
 | 
			
		||||
	"k8s.io/kubernetes/cmd/kubeadm/app/util/output"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// isKubeadmConfigPresent checks if a kubeadm config type is found in the provided document map
 | 
			
		||||
func isKubeadmConfigPresent(docmap kubeadmapi.DocumentMap) bool {
 | 
			
		||||
	for gvk := range docmap {
 | 
			
		||||
		if gvk.Group == kubeadmapi.GroupName {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// loadConfig loads configuration from a file and/or the cluster. InitConfiguration, ClusterConfiguration and (optionally) component configs
 | 
			
		||||
// are loaded. This function allows the component configs to be loaded from a file that contains only them. If the file contains any kubeadm types
 | 
			
		||||
// in it (API group "kubeadm.k8s.io" present), then the supplied file is treaded as a legacy reconfiguration style "--config" use and the
 | 
			
		||||
// returned bool value is set to true (the only case to be done so).
 | 
			
		||||
func loadConfig(cfgPath string, client clientset.Interface, skipComponentConfigs bool, printer output.Printer) (*kubeadmapi.InitConfiguration, bool, error) {
 | 
			
		||||
	// Used for info logs here
 | 
			
		||||
	const logPrefix = "upgrade/config"
 | 
			
		||||
 | 
			
		||||
	// The usual case here is to not have a config file, but rather load the config from the cluster.
 | 
			
		||||
	// This is probably 90% of the time. So we handle it first.
 | 
			
		||||
	if cfgPath == "" {
 | 
			
		||||
		cfg, err := configutil.FetchInitConfigurationFromCluster(client, printer, logPrefix, false, skipComponentConfigs)
 | 
			
		||||
		return cfg, false, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Otherwise, we have a config file. Let's load it.
 | 
			
		||||
	configBytes, err := os.ReadFile(cfgPath)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, false, errors.Wrapf(err, "unable to load config from file %q", cfgPath)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Split the YAML documents in the file into a DocumentMap
 | 
			
		||||
	docmap, err := kubeadmutil.SplitYAMLDocuments(configBytes)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, false, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// If there are kubeadm types (API group kubeadm.k8s.io) present, we need to keep the existing behavior
 | 
			
		||||
	// here. Basically, we have to load all of the configs from the file and none from the cluster. Configs that are
 | 
			
		||||
	// missing from the file will be automatically regenerated by kubeadm even if they are present in the cluster.
 | 
			
		||||
	// The resulting configs overwrite the existing cluster ones at the end of a successful upgrade apply operation.
 | 
			
		||||
	if isKubeadmConfigPresent(docmap) {
 | 
			
		||||
		klog.Warning("WARNING: Usage of the --config flag with kubeadm config types for reconfiguring the cluster during upgrade is not recommended!")
 | 
			
		||||
		cfg, err := configutil.BytesToInitConfiguration(configBytes, false)
 | 
			
		||||
		return cfg, true, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// If no kubeadm config types are present, we assume that there are manually upgraded component configs in the file.
 | 
			
		||||
	// Hence, we load the kubeadm types from the cluster.
 | 
			
		||||
	initCfg, err := configutil.FetchInitConfigurationFromCluster(client, printer, logPrefix, false, true)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, false, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Stop here if the caller does not want us to load the component configs
 | 
			
		||||
	if !skipComponentConfigs {
 | 
			
		||||
		// Load the component configs with upgrades
 | 
			
		||||
		if err := componentconfigs.FetchFromClusterWithLocalOverwrites(&initCfg.ClusterConfiguration, client, docmap); err != nil {
 | 
			
		||||
			return nil, false, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Now default and validate the configs
 | 
			
		||||
		componentconfigs.Default(&initCfg.ClusterConfiguration, &initCfg.LocalAPIEndpoint, &initCfg.NodeRegistration)
 | 
			
		||||
		if errs := componentconfigs.Validate(&initCfg.ClusterConfiguration); len(errs) != 0 {
 | 
			
		||||
			return nil, false, errs.ToAggregate()
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return initCfg, false, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LoadConfigFunc is a function type that loads configuration from a file and/or the cluster.
 | 
			
		||||
type LoadConfigFunc func(cfgPath string, client clientset.Interface, skipComponentConfigs bool, printer output.Printer) (*kubeadmapi.InitConfiguration, bool, error)
 | 
			
		||||
 | 
			
		||||
// enforceRequirements verifies that it's okay to upgrade and then returns the variables needed for the rest of the procedure
 | 
			
		||||
func enforceRequirements(flags *applyPlanFlags, args []string, dryRun bool, upgradeApply bool, printer output.Printer, loadConfig LoadConfigFunc) (clientset.Interface, upgrade.VersionGetter, *kubeadmapi.InitConfiguration, error) {
 | 
			
		||||
	client, err := getClient(flags.kubeConfigPath, dryRun)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, nil, nil, errors.Wrapf(err, "couldn't create a Kubernetes client from file %q", flags.kubeConfigPath)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
func enforceRequirements(flagSet *pflag.FlagSet, flags *applyPlanFlags, args []string, dryRun bool, upgradeApply bool, printer output.Printer) (clientset.Interface, upgrade.VersionGetter, *kubeadmapi.InitConfiguration, *kubeadmapi.UpgradeConfiguration, error) {
 | 
			
		||||
	// Fetch the configuration from a file or ConfigMap and validate it
 | 
			
		||||
	_, _ = printer.Println("[upgrade/config] Loading the kubeadm configuration")
 | 
			
		||||
	_, _ = printer.Printf("[upgrade/config] Making sure the configuration is correct:\n")
 | 
			
		||||
 | 
			
		||||
	var newK8sVersion string
 | 
			
		||||
	cfg, legacyReconfigure, err := loadConfig(flags.cfgPath, client, !upgradeApply, printer)
 | 
			
		||||
	upgradeCfg, err := configutil.LoadUpgradeConfig(flags.cfgPath)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, nil, nil, errors.Wrap(err, "could not load the kubeadm configuration")
 | 
			
		||||
	} else if legacyReconfigure {
 | 
			
		||||
		// Set the newK8sVersion to the value in the ClusterConfiguration. This is done, so that users who use the --config option
 | 
			
		||||
		// to supply a new ClusterConfiguration don't have to specify the Kubernetes version twice,
 | 
			
		||||
		// if they don't want to upgrade but just change a setting.
 | 
			
		||||
		newK8sVersion = cfg.KubernetesVersion
 | 
			
		||||
		return nil, nil, nil, nil, errors.Wrap(err, "[upgrade/upgrade config] FATAL")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// The version arg is mandatory, during upgrade apply, unless it's specified in the config file
 | 
			
		||||
	if upgradeApply && newK8sVersion == "" {
 | 
			
		||||
		if err := cmdutil.ValidateExactArgNumber(args, []string{"version"}); err != nil {
 | 
			
		||||
			return nil, nil, nil, err
 | 
			
		||||
	// `dryRun` should be always `false` for `kubeadm plan`.
 | 
			
		||||
	isDryRun := ptr.To(false)
 | 
			
		||||
	printConfigCfg := upgradeCfg.Plan.PrintConfig
 | 
			
		||||
	ignoreErrCfg := upgradeCfg.Plan.IgnorePreflightErrors
 | 
			
		||||
	ok := false
 | 
			
		||||
	if upgradeApply {
 | 
			
		||||
		printConfigCfg = upgradeCfg.Apply.PrintConfig
 | 
			
		||||
		ignoreErrCfg = upgradeCfg.Apply.IgnorePreflightErrors
 | 
			
		||||
		isDryRun, ok = cmdutil.ValueFromFlagsOrConfig(flagSet, options.DryRun, upgradeCfg.Apply.DryRun, &dryRun).(*bool)
 | 
			
		||||
		if !ok {
 | 
			
		||||
			return nil, nil, nil, nil, cmdutil.TypeMismatchErr("dryRun", "bool")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	client, err := getClient(flags.kubeConfigPath, *isDryRun)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, nil, nil, nil, errors.Wrapf(err, "couldn't create a Kubernetes client from file %q", flags.kubeConfigPath)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ignorePreflightErrorsSet, err := validation.ValidateIgnorePreflightErrors(flags.ignorePreflightErrors, ignoreErrCfg)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, nil, nil, nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Also set the union of pre-flight errors to UpgradeConfiguration, to provide a consistent view of the runtime configuration.
 | 
			
		||||
	// .Plan.IgnorePreflightErrors is not set as it's not used.
 | 
			
		||||
	if upgradeApply {
 | 
			
		||||
		upgradeCfg.Apply.IgnorePreflightErrors = sets.List(ignorePreflightErrorsSet)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Ensure the user is root
 | 
			
		||||
	klog.V(1).Info("running preflight checks")
 | 
			
		||||
	if err := runPreflightChecks(client, ignorePreflightErrorsSet, printer); err != nil {
 | 
			
		||||
		return nil, nil, nil, nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	initCfg, err := configutil.FetchInitConfigurationFromCluster(client, printer, "upgrade/config", false, true)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if apierrors.IsNotFound(err) {
 | 
			
		||||
			_, _ = printer.Printf("[upgrade/config] In order to upgrade, a ConfigMap called %q in the %s namespace must exist.\n", constants.KubeadmConfigConfigMap, metav1.NamespaceSystem)
 | 
			
		||||
			_, _ = printer.Printf("[upgrade/config] Next steps:\n")
 | 
			
		||||
			_, _ = printer.Printf("\t- OPTION 1: Run 'kubeadm config upload from-flags' and specify the same CLI arguments you passed to 'kubeadm init' when you created your control-plane.\n")
 | 
			
		||||
			_, _ = printer.Printf("\t- OPTION 2: Run 'kubeadm config upload from-file' and specify the same config file you passed to 'kubeadm init' when you created your control-plane.\n")
 | 
			
		||||
			_, _ = printer.Println()
 | 
			
		||||
			err = errors.Errorf("the ConfigMap %q in the %s namespace used for getting configuration information was not found", constants.KubeadmConfigConfigMap, metav1.NamespaceSystem)
 | 
			
		||||
		}
 | 
			
		||||
		return nil, nil, nil, nil, errors.Wrap(err, "[upgrade/init config] FATAL")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	newK8sVersion := upgradeCfg.Plan.KubernetesVersion
 | 
			
		||||
	if upgradeApply {
 | 
			
		||||
		newK8sVersion = upgradeCfg.Apply.KubernetesVersion
 | 
			
		||||
		// The version arg is mandatory, during upgrade apply, unless it's specified in the config file
 | 
			
		||||
		if newK8sVersion == "" {
 | 
			
		||||
			if err := cmdutil.ValidateExactArgNumber(args, []string{"version"}); err != nil {
 | 
			
		||||
				return nil, nil, nil, nil, err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// If option was specified in both args and config file, args will overwrite the config file.
 | 
			
		||||
	if len(args) == 1 {
 | 
			
		||||
		newK8sVersion = args[0]
 | 
			
		||||
		if upgradeApply {
 | 
			
		||||
			// The `upgrade apply` version always overwrites the KubernetesVersion in the returned cfg with the target
 | 
			
		||||
			// version. While this is not the same for `upgrade plan` where the KubernetesVersion should be the old
 | 
			
		||||
			// one (because the call to getComponentConfigVersionStates requires the currently installed version).
 | 
			
		||||
			// This also makes the KubernetesVersion value returned for `upgrade plan` consistent as that command
 | 
			
		||||
			// allows to not specify a target version in which case KubernetesVersion will always hold the currently
 | 
			
		||||
			// installed one.
 | 
			
		||||
			cfg.KubernetesVersion = newK8sVersion
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ignorePreflightErrorsSet, err := validation.ValidateIgnorePreflightErrors(flags.ignorePreflightErrors, cfg.NodeRegistration.IgnorePreflightErrors)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, nil, nil, err
 | 
			
		||||
	}
 | 
			
		||||
	// Also set the union of pre-flight errors to InitConfiguration, to provide a consistent view of the runtime configuration:
 | 
			
		||||
	cfg.NodeRegistration.IgnorePreflightErrors = sets.List(ignorePreflightErrorsSet)
 | 
			
		||||
 | 
			
		||||
	// Ensure the user is root
 | 
			
		||||
	klog.V(1).Info("running preflight checks")
 | 
			
		||||
	if err := runPreflightChecks(client, ignorePreflightErrorsSet, printer); err != nil {
 | 
			
		||||
		return nil, nil, nil, err
 | 
			
		||||
	if upgradeApply {
 | 
			
		||||
		// The `upgrade apply` version always overwrites the KubernetesVersion in the returned cfg with the target
 | 
			
		||||
		// version. While this is not the same for `upgrade plan` where the KubernetesVersion should be the old
 | 
			
		||||
		// one (because the call to getComponentConfigVersionStates requires the currently installed version).
 | 
			
		||||
		// This also makes the KubernetesVersion value returned for `upgrade plan` consistent as that command
 | 
			
		||||
		// allows to not specify a target version in which case KubernetesVersion will always hold the currently
 | 
			
		||||
		// installed one.
 | 
			
		||||
		initCfg.KubernetesVersion = newK8sVersion
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Run healthchecks against the cluster
 | 
			
		||||
	if err := upgrade.CheckClusterHealth(client, &cfg.ClusterConfiguration, ignorePreflightErrorsSet, printer); err != nil {
 | 
			
		||||
		return nil, nil, nil, errors.Wrap(err, "[upgrade/health] FATAL")
 | 
			
		||||
	if err := upgrade.CheckClusterHealth(client, &initCfg.ClusterConfiguration, ignorePreflightErrorsSet, printer); err != nil {
 | 
			
		||||
		return nil, nil, nil, nil, errors.Wrap(err, "[upgrade/health] FATAL")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// If features gates are passed to the command line, use it (otherwise use featureGates from configuration)
 | 
			
		||||
	if flags.featureGatesString != "" {
 | 
			
		||||
		cfg.FeatureGates, err = features.NewFeatureGate(&features.InitFeatureGates, flags.featureGatesString)
 | 
			
		||||
		initCfg.FeatureGates, err = features.NewFeatureGate(&features.InitFeatureGates, flags.featureGatesString)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, nil, nil, errors.Wrap(err, "[upgrade/config] FATAL")
 | 
			
		||||
			return nil, nil, nil, nil, errors.Wrap(err, "[upgrade/config] FATAL")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Check if feature gate flags used in the cluster are consistent with the set of features currently supported by kubeadm
 | 
			
		||||
	if msg := features.CheckDeprecatedFlags(&features.InitFeatureGates, cfg.FeatureGates); len(msg) > 0 {
 | 
			
		||||
	if msg := features.CheckDeprecatedFlags(&features.InitFeatureGates, initCfg.FeatureGates); len(msg) > 0 {
 | 
			
		||||
		for _, m := range msg {
 | 
			
		||||
			printer.Printf("[upgrade/config] %s\n", m)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// If the user told us to print this information out; do it!
 | 
			
		||||
	if flags.printConfig {
 | 
			
		||||
		printConfiguration(&cfg.ClusterConfiguration, os.Stdout, printer)
 | 
			
		||||
	printConfig, ok := cmdutil.ValueFromFlagsOrConfig(flagSet, options.PrintConfig, printConfigCfg, &flags.printConfig).(*bool)
 | 
			
		||||
	if ok && *printConfig {
 | 
			
		||||
		printConfiguration(&initCfg.ClusterConfiguration, os.Stdout, printer)
 | 
			
		||||
	} else if !ok {
 | 
			
		||||
		return nil, nil, nil, nil, cmdutil.TypeMismatchErr("printConfig", "bool")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Use a real version getter interface that queries the API server, the kubeadm client and the Kubernetes CI system for latest versions
 | 
			
		||||
	return client, upgrade.NewOfflineVersionGetter(upgrade.NewKubeVersionGetter(client), newK8sVersion), cfg, nil
 | 
			
		||||
	return client, upgrade.NewOfflineVersionGetter(upgrade.NewKubeVersionGetter(client), newK8sVersion), initCfg, upgradeCfg, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// printConfiguration prints the external version of the API to yaml
 | 
			
		||||
 
 | 
			
		||||
@@ -24,7 +24,8 @@ import (
 | 
			
		||||
	"strings"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	clientset "k8s.io/client-go/kubernetes"
 | 
			
		||||
	"github.com/spf13/pflag"
 | 
			
		||||
 | 
			
		||||
	kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
 | 
			
		||||
	kubeadmapiv1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta3"
 | 
			
		||||
	"k8s.io/kubernetes/cmd/kubeadm/app/preflight"
 | 
			
		||||
@@ -53,25 +54,18 @@ users:
 | 
			
		||||
    client-certificate-data:
 | 
			
		||||
`
 | 
			
		||||
 | 
			
		||||
func fakeLoadConfig(cfgPath string, client clientset.Interface, skipComponentConfigs bool, printer output.Printer) (*kubeadmapi.InitConfiguration, bool, error) {
 | 
			
		||||
	return &kubeadmapi.InitConfiguration{}, false, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestEnforceRequirements(t *testing.T) {
 | 
			
		||||
	tmpDir := testutil.SetupTempDir(t)
 | 
			
		||||
	defer os.RemoveAll(tmpDir)
 | 
			
		||||
 | 
			
		||||
	fullPath := filepath.Join(tmpDir, "test-config-file")
 | 
			
		||||
	f, err := os.Create(fullPath)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Errorf("Unable to create test file %q: %v", fullPath, err)
 | 
			
		||||
	}
 | 
			
		||||
	defer f.Close()
 | 
			
		||||
 | 
			
		||||
	if _, err = f.WriteString(testConfigToken); err != nil {
 | 
			
		||||
		t.Errorf("Unable to write test file %q: %v", fullPath, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	tcases := []struct {
 | 
			
		||||
		name               string
 | 
			
		||||
		newK8sVersion      string
 | 
			
		||||
@@ -106,8 +100,7 @@ func TestEnforceRequirements(t *testing.T) {
 | 
			
		||||
	}
 | 
			
		||||
	for _, tt := range tcases {
 | 
			
		||||
		t.Run(tt.name, func(t *testing.T) {
 | 
			
		||||
			_, _, _, err := enforceRequirements(&tt.flags, nil, tt.dryRun, false, &output.TextPrinter{}, fakeLoadConfig)
 | 
			
		||||
 | 
			
		||||
			_, _, _, _, err := enforceRequirements(&pflag.FlagSet{}, &tt.flags, nil, tt.dryRun, false, &output.TextPrinter{})
 | 
			
		||||
			if err == nil && len(tt.expectedErr) != 0 {
 | 
			
		||||
				t.Error("Expected error, but got success")
 | 
			
		||||
			}
 | 
			
		||||
@@ -123,7 +116,6 @@ func TestEnforceRequirements(t *testing.T) {
 | 
			
		||||
			if err != nil && !strings.Contains(err.Error(), expErr) {
 | 
			
		||||
				t.Fatalf("enforceRequirements returned unexpected error, expected: %s, got %v", expErr, err)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -212,52 +204,3 @@ func TestPrintConfiguration(t *testing.T) {
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestIsKubeadmConfigPresent(t *testing.T) {
 | 
			
		||||
	var tcases = []struct {
 | 
			
		||||
		name     string
 | 
			
		||||
		gvkmap   kubeadmapi.DocumentMap
 | 
			
		||||
		expected bool
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			name: " Wrong Group value",
 | 
			
		||||
			gvkmap: kubeadmapi.DocumentMap{
 | 
			
		||||
				{Group: "foo.k8s.io", Version: "v1", Kind: "Foo"}: []byte(`kind: Foo`),
 | 
			
		||||
			},
 | 
			
		||||
			expected: false,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "Empty Group value",
 | 
			
		||||
			gvkmap: kubeadmapi.DocumentMap{
 | 
			
		||||
				{Group: "", Version: "v1", Kind: "Empty"}: []byte(`kind: Empty`),
 | 
			
		||||
			},
 | 
			
		||||
			expected: false,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:     "Nil value",
 | 
			
		||||
			gvkmap:   nil,
 | 
			
		||||
			expected: false,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "Correct Group value 1",
 | 
			
		||||
			gvkmap: kubeadmapi.DocumentMap{
 | 
			
		||||
				{Group: "kubeadm.k8s.io", Version: "v1", Kind: "Empty"}: []byte(`kind: Empty`),
 | 
			
		||||
			},
 | 
			
		||||
			expected: true,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "Correct Group value 2",
 | 
			
		||||
			gvkmap: kubeadmapi.DocumentMap{
 | 
			
		||||
				{Group: kubeadmapi.GroupName, Version: "v1", Kind: "Empty"}: []byte(`kind: Empty`),
 | 
			
		||||
			},
 | 
			
		||||
			expected: true,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	for _, tt := range tcases {
 | 
			
		||||
		t.Run(tt.name, func(t *testing.T) {
 | 
			
		||||
			if isKubeadmConfigPresent(tt.gvkmap) != tt.expected {
 | 
			
		||||
				t.Error("unexpected result")
 | 
			
		||||
			}
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -23,13 +23,15 @@ import (
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
	"github.com/pmezard/go-difflib/difflib"
 | 
			
		||||
	"github.com/spf13/cobra"
 | 
			
		||||
	"github.com/spf13/pflag"
 | 
			
		||||
 | 
			
		||||
	corev1 "k8s.io/api/core/v1"
 | 
			
		||||
	"k8s.io/apimachinery/pkg/util/version"
 | 
			
		||||
	client "k8s.io/client-go/kubernetes"
 | 
			
		||||
	clientset "k8s.io/client-go/kubernetes"
 | 
			
		||||
	"k8s.io/klog/v2"
 | 
			
		||||
 | 
			
		||||
	kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
 | 
			
		||||
	"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation"
 | 
			
		||||
	"k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
 | 
			
		||||
	cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util"
 | 
			
		||||
	"k8s.io/kubernetes/cmd/kubeadm/app/constants"
 | 
			
		||||
@@ -37,6 +39,7 @@ import (
 | 
			
		||||
	kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
 | 
			
		||||
	configutil "k8s.io/kubernetes/cmd/kubeadm/app/util/config"
 | 
			
		||||
	kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig"
 | 
			
		||||
	"k8s.io/kubernetes/cmd/kubeadm/app/util/output"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type diffFlags struct {
 | 
			
		||||
@@ -74,7 +77,11 @@ func newCmdDiff(out io.Writer) *cobra.Command {
 | 
			
		||||
				flags.schedulerManifestPath); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			return runDiff(flags, args)
 | 
			
		||||
 | 
			
		||||
			if err := validation.ValidateMixedArguments(cmd.Flags()); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			return runDiff(cmd.Flags(), flags, args, configutil.FetchInitConfigurationFromCluster)
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -107,50 +114,49 @@ func validateManifestsPath(manifests ...string) (err error) {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func runDiff(flags *diffFlags, args []string) error {
 | 
			
		||||
	var err error
 | 
			
		||||
	var cfg *kubeadmapi.InitConfiguration
 | 
			
		||||
	if flags.cfgPath != "" {
 | 
			
		||||
		cfg, err = configutil.LoadInitConfigurationFromFile(flags.cfgPath, configutil.LoadOrDefaultConfigurationOptions{
 | 
			
		||||
			SkipCRIDetect: true,
 | 
			
		||||
		})
 | 
			
		||||
	} else {
 | 
			
		||||
		var client client.Interface
 | 
			
		||||
		client, err = kubeconfigutil.ClientSetFromFile(flags.kubeConfigPath)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return errors.Wrapf(err, "couldn't create a Kubernetes client from file %q", flags.kubeConfigPath)
 | 
			
		||||
		}
 | 
			
		||||
		cfg, err = configutil.FetchInitConfigurationFromCluster(client, nil, "upgrade/diff", false, false)
 | 
			
		||||
// FetchInitConfigurationFunc defines the signature of the function which will fetch InitConfiguration from cluster.
 | 
			
		||||
type FetchInitConfigurationFunc func(client clientset.Interface, printer output.Printer, logPrefix string, newControlPlane, skipComponentConfigs bool) (*kubeadmapi.InitConfiguration, error)
 | 
			
		||||
 | 
			
		||||
func runDiff(fs *pflag.FlagSet, flags *diffFlags, args []string, fetchInitConfigurationFromCluster FetchInitConfigurationFunc) error {
 | 
			
		||||
	upgradeCfg, err := configutil.LoadUpgradeConfig(flags.cfgPath)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	client, err := kubeconfigutil.ClientSetFromFile(flags.kubeConfigPath)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return errors.Wrapf(err, "couldn't create a Kubernetes client from file %q", flags.kubeConfigPath)
 | 
			
		||||
	}
 | 
			
		||||
	initCfg, err := fetchInitConfigurationFromCluster(client, &output.TextPrinter{}, "upgrade/diff", false, true)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// If the version is specified in config file, pick up that value.
 | 
			
		||||
	if cfg.KubernetesVersion != "" {
 | 
			
		||||
		flags.newK8sVersionStr = cfg.KubernetesVersion
 | 
			
		||||
	// Pick up the version from the ClusterConfiguration.
 | 
			
		||||
	if initCfg.KubernetesVersion != "" {
 | 
			
		||||
		flags.newK8sVersionStr = initCfg.KubernetesVersion
 | 
			
		||||
	}
 | 
			
		||||
	if upgradeCfg.Diff.KubernetesVersion != "" {
 | 
			
		||||
		flags.newK8sVersionStr = upgradeCfg.Diff.KubernetesVersion
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// If the new version is already specified in config file, version arg is optional.
 | 
			
		||||
	// Version must be specified via version arg if it's not set in ClusterConfiguration.
 | 
			
		||||
	if flags.newK8sVersionStr == "" {
 | 
			
		||||
		if err := cmdutil.ValidateExactArgNumber(args, []string{"version"}); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// If option was specified in both args and config file, args will overwrite the config file.
 | 
			
		||||
	if len(args) == 1 {
 | 
			
		||||
		flags.newK8sVersionStr = args[0]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, err = version.ParseSemantic(flags.newK8sVersionStr)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cfg.ClusterConfiguration.KubernetesVersion = flags.newK8sVersionStr
 | 
			
		||||
	initCfg.ClusterConfiguration.KubernetesVersion = flags.newK8sVersionStr
 | 
			
		||||
 | 
			
		||||
	specs := controlplane.GetStaticPodSpecs(&cfg.ClusterConfiguration, &cfg.LocalAPIEndpoint, nil)
 | 
			
		||||
	specs := controlplane.GetStaticPodSpecs(&initCfg.ClusterConfiguration, &initCfg.LocalAPIEndpoint, nil)
 | 
			
		||||
	for spec, pod := range specs {
 | 
			
		||||
		var path string
 | 
			
		||||
		switch spec {
 | 
			
		||||
@@ -164,7 +170,6 @@ func runDiff(flags *diffFlags, args []string) error {
 | 
			
		||||
			klog.Errorf("[diff] unknown spec %v", spec)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		newManifest, err := kubeadmutil.MarshalToYaml(&pod, corev1.SchemeGroupVersion)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
@@ -183,7 +188,7 @@ func runDiff(flags *diffFlags, args []string) error {
 | 
			
		||||
			B:        difflib.SplitLines(string(newManifest)),
 | 
			
		||||
			FromFile: path,
 | 
			
		||||
			ToFile:   "new manifest",
 | 
			
		||||
			Context:  flags.contextLines,
 | 
			
		||||
			Context:  cmdutil.ValueFromFlagsOrConfig(fs, "context-lines", upgradeCfg.Diff.DiffContextLines, flags.contextLines).(int),
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		difflib.WriteUnifiedDiff(flags.out, diff)
 | 
			
		||||
 
 | 
			
		||||
@@ -24,8 +24,10 @@ import (
 | 
			
		||||
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
 | 
			
		||||
	kubeadmapiv1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta3"
 | 
			
		||||
	"k8s.io/kubernetes/cmd/kubeadm/app/constants"
 | 
			
		||||
	clientset "k8s.io/client-go/kubernetes"
 | 
			
		||||
	kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
 | 
			
		||||
	kubeadmapiv1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta4"
 | 
			
		||||
	"k8s.io/kubernetes/cmd/kubeadm/app/util/output"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func createTestRunDiffFile(contents []byte) (string, error) {
 | 
			
		||||
@@ -42,23 +44,25 @@ func createTestRunDiffFile(contents []byte) (string, error) {
 | 
			
		||||
	return file.Name(), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRunDiff(t *testing.T) {
 | 
			
		||||
	currentVersion := "v" + constants.CurrentKubernetesVersion.String()
 | 
			
		||||
func fakeFetchInitConfig(client clientset.Interface, printer output.Printer, logPrefix string, newControlPlane, skipComponentConfigs bool) (*kubeadmapi.InitConfiguration, error) {
 | 
			
		||||
	return &kubeadmapi.InitConfiguration{
 | 
			
		||||
		ClusterConfiguration: kubeadmapi.ClusterConfiguration{
 | 
			
		||||
			KubernetesVersion: "v1.0.1",
 | 
			
		||||
		},
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRunDiff(t *testing.T) {
 | 
			
		||||
	// create a temporary file with valid ClusterConfiguration
 | 
			
		||||
	testUpgradeDiffConfigContents := []byte(fmt.Sprintf(`
 | 
			
		||||
apiVersion: %s
 | 
			
		||||
kind: InitConfiguration
 | 
			
		||||
---
 | 
			
		||||
apiVersion: %[1]s
 | 
			
		||||
kind: ClusterConfiguration
 | 
			
		||||
kubernetesVersion: %s`, kubeadmapiv1.SchemeGroupVersion.String(), currentVersion))
 | 
			
		||||
kind: UpgradeConfiguration
 | 
			
		||||
contextLines: 4`, kubeadmapiv1.SchemeGroupVersion.String()))
 | 
			
		||||
	testUpgradeDiffConfig, err := createTestRunDiffFile(testUpgradeDiffConfigContents)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	defer os.Remove(testUpgradeDiffConfig)
 | 
			
		||||
 | 
			
		||||
	// create a temporary manifest file with dummy contents
 | 
			
		||||
	testUpgradeDiffManifestContents := []byte("some-contents")
 | 
			
		||||
	testUpgradeDiffManifest, err := createTestRunDiffFile(testUpgradeDiffManifestContents)
 | 
			
		||||
@@ -67,6 +71,13 @@ kubernetesVersion: %s`, kubeadmapiv1.SchemeGroupVersion.String(), currentVersion
 | 
			
		||||
	}
 | 
			
		||||
	defer os.Remove(testUpgradeDiffManifest)
 | 
			
		||||
 | 
			
		||||
	kubeConfigPath, err := createTestRunDiffFile([]byte(testConfigToken))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	//nolint:errcheck
 | 
			
		||||
	defer os.Remove(kubeConfigPath)
 | 
			
		||||
 | 
			
		||||
	flags := &diffFlags{
 | 
			
		||||
		cfgPath: "",
 | 
			
		||||
		out:     io.Discard,
 | 
			
		||||
@@ -118,12 +129,14 @@ kubernetesVersion: %s`, kubeadmapiv1.SchemeGroupVersion.String(), currentVersion
 | 
			
		||||
	for _, tc := range testCases {
 | 
			
		||||
		t.Run(tc.name, func(t *testing.T) {
 | 
			
		||||
			flags.cfgPath = tc.cfgPath
 | 
			
		||||
			flags.kubeConfigPath = kubeConfigPath
 | 
			
		||||
			cmd := newCmdDiff(os.Stdout)
 | 
			
		||||
			if tc.setManifestPath {
 | 
			
		||||
				flags.apiServerManifestPath = tc.manifestPath
 | 
			
		||||
				flags.controllerManagerManifestPath = tc.manifestPath
 | 
			
		||||
				flags.schedulerManifestPath = tc.manifestPath
 | 
			
		||||
			}
 | 
			
		||||
			if err := runDiff(flags, tc.args); (err != nil) != tc.expectedError {
 | 
			
		||||
			if err := runDiff(cmd.Flags(), flags, tc.args, fakeFetchInitConfig); (err != nil) != tc.expectedError {
 | 
			
		||||
				t.Fatalf("expected error: %v, saw: %v, error: %v", tc.expectedError, (err != nil), err)
 | 
			
		||||
			}
 | 
			
		||||
		})
 | 
			
		||||
 
 | 
			
		||||
@@ -32,6 +32,7 @@ import (
 | 
			
		||||
	"k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
 | 
			
		||||
	phases "k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/upgrade/node"
 | 
			
		||||
	"k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/workflow"
 | 
			
		||||
	cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util"
 | 
			
		||||
	"k8s.io/kubernetes/cmd/kubeadm/app/constants"
 | 
			
		||||
	configutil "k8s.io/kubernetes/cmd/kubeadm/app/util/config"
 | 
			
		||||
)
 | 
			
		||||
@@ -40,6 +41,7 @@ import (
 | 
			
		||||
// Please note that this structure includes the public kubeadm config API, but only a subset of the options
 | 
			
		||||
// supported by this api will be exposed as a flag.
 | 
			
		||||
type nodeOptions struct {
 | 
			
		||||
	cfgPath               string
 | 
			
		||||
	kubeConfigPath        string
 | 
			
		||||
	etcdUpgrade           bool
 | 
			
		||||
	renewCerts            bool
 | 
			
		||||
@@ -57,7 +59,8 @@ type nodeData struct {
 | 
			
		||||
	etcdUpgrade           bool
 | 
			
		||||
	renewCerts            bool
 | 
			
		||||
	dryRun                bool
 | 
			
		||||
	cfg                   *kubeadmapi.InitConfiguration
 | 
			
		||||
	cfg                   *kubeadmapi.UpgradeConfiguration
 | 
			
		||||
	initCfg               *kubeadmapi.InitConfiguration
 | 
			
		||||
	isControlPlaneNode    bool
 | 
			
		||||
	client                clientset.Interface
 | 
			
		||||
	patchesDir            string
 | 
			
		||||
@@ -75,6 +78,10 @@ func newCmdNode(out io.Writer) *cobra.Command {
 | 
			
		||||
		Use:   "node",
 | 
			
		||||
		Short: "Upgrade commands for a node in the cluster",
 | 
			
		||||
		RunE: func(cmd *cobra.Command, args []string) error {
 | 
			
		||||
			if err := validation.ValidateMixedArguments(cmd.Flags()); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return nodeRunner.Run(args)
 | 
			
		||||
		},
 | 
			
		||||
		Args: cobra.NoArgs,
 | 
			
		||||
@@ -83,6 +90,7 @@ func newCmdNode(out io.Writer) *cobra.Command {
 | 
			
		||||
	// adds flags to the node command
 | 
			
		||||
	// flags could be eventually inherited by the sub-commands automatically generated for phases
 | 
			
		||||
	addUpgradeNodeFlags(cmd.Flags(), nodeOptions)
 | 
			
		||||
	options.AddConfigFlag(cmd.Flags(), &nodeOptions.cfgPath)
 | 
			
		||||
	options.AddPatchesFlag(cmd.Flags(), &nodeOptions.patchesDir)
 | 
			
		||||
 | 
			
		||||
	// initialize the workflow runner with the list of phases
 | 
			
		||||
@@ -93,7 +101,15 @@ func newCmdNode(out io.Writer) *cobra.Command {
 | 
			
		||||
	// sets the data builder function, that will be used by the runner
 | 
			
		||||
	// both when running the entire workflow or single phases
 | 
			
		||||
	nodeRunner.SetDataInitializer(func(cmd *cobra.Command, args []string) (workflow.RunData, error) {
 | 
			
		||||
		return newNodeData(cmd, args, nodeOptions, out)
 | 
			
		||||
		data, err := newNodeData(cmd, args, nodeOptions, out)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		// If the flag for skipping phases was empty, use the values from config
 | 
			
		||||
		if len(nodeRunner.Options.SkipPhases) == 0 {
 | 
			
		||||
			nodeRunner.Options.SkipPhases = data.cfg.Node.SkipPhases
 | 
			
		||||
		}
 | 
			
		||||
		return data, nil
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	// binds the Runner to kubeadm upgrade node command by altering
 | 
			
		||||
@@ -124,50 +140,69 @@ func addUpgradeNodeFlags(flagSet *flag.FlagSet, nodeOptions *nodeOptions) {
 | 
			
		||||
// newNodeData returns a new nodeData struct to be used for the execution of the kubeadm upgrade node workflow.
 | 
			
		||||
// This func takes care of validating nodeOptions passed to the command, and then it converts
 | 
			
		||||
// options into the internal InitConfiguration type that is used as input all the phases in the kubeadm upgrade node workflow
 | 
			
		||||
func newNodeData(cmd *cobra.Command, args []string, options *nodeOptions, out io.Writer) (*nodeData, error) {
 | 
			
		||||
func newNodeData(cmd *cobra.Command, args []string, nodeOptions *nodeOptions, out io.Writer) (*nodeData, error) {
 | 
			
		||||
	// Checks if a node is a control-plane node by looking up the kube-apiserver manifest file
 | 
			
		||||
	isControlPlaneNode := true
 | 
			
		||||
	filepath := constants.GetStaticPodFilepath(constants.KubeAPIServer, constants.GetStaticPodDirectory())
 | 
			
		||||
	if _, err := os.Stat(filepath); os.IsNotExist(err) {
 | 
			
		||||
		isControlPlaneNode = false
 | 
			
		||||
	}
 | 
			
		||||
	if len(options.kubeConfigPath) == 0 {
 | 
			
		||||
	if len(nodeOptions.kubeConfigPath) == 0 {
 | 
			
		||||
		// Update the kubeconfig path depending on whether this is a control plane node or not.
 | 
			
		||||
		options.kubeConfigPath = constants.GetKubeletKubeConfigPath()
 | 
			
		||||
		nodeOptions.kubeConfigPath = constants.GetKubeletKubeConfigPath()
 | 
			
		||||
		if isControlPlaneNode {
 | 
			
		||||
			options.kubeConfigPath = constants.GetAdminKubeConfigPath()
 | 
			
		||||
			nodeOptions.kubeConfigPath = constants.GetAdminKubeConfigPath()
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	client, err := getClient(options.kubeConfigPath, options.dryRun)
 | 
			
		||||
	upgradeCfg, err := configutil.LoadUpgradeConfig(nodeOptions.cfgPath)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errors.Wrapf(err, "couldn't create a Kubernetes client from file %q", options.kubeConfigPath)
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dryRun, ok := cmdutil.ValueFromFlagsOrConfig(cmd.Flags(), options.DryRun, upgradeCfg.Node.DryRun, &nodeOptions.dryRun).(*bool)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return nil, cmdutil.TypeMismatchErr("dryRun", "bool")
 | 
			
		||||
	}
 | 
			
		||||
	client, err := getClient(nodeOptions.kubeConfigPath, *dryRun)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errors.Wrapf(err, "couldn't create a Kubernetes client from file %q", nodeOptions.kubeConfigPath)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Fetches the cluster configuration
 | 
			
		||||
	// NB in case of control-plane node, we are reading all the info for the node; in case of NOT control-plane node
 | 
			
		||||
	//    (worker node), we are not reading local API address and the CRI socket from the node object
 | 
			
		||||
	cfg, err := configutil.FetchInitConfigurationFromCluster(client, nil, "upgrade", !isControlPlaneNode, false)
 | 
			
		||||
	initCfg, err := configutil.FetchInitConfigurationFromCluster(client, nil, "upgrade", !isControlPlaneNode, false)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errors.Wrap(err, "unable to fetch the kubeadm-config ConfigMap")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ignorePreflightErrorsSet, err := validation.ValidateIgnorePreflightErrors(options.ignorePreflightErrors, cfg.NodeRegistration.IgnorePreflightErrors)
 | 
			
		||||
	ignorePreflightErrorsSet, err := validation.ValidateIgnorePreflightErrors(nodeOptions.ignorePreflightErrors, initCfg.NodeRegistration.IgnorePreflightErrors)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	// Also set the union of pre-flight errors to JoinConfiguration, to provide a consistent view of the runtime configuration:
 | 
			
		||||
	cfg.NodeRegistration.IgnorePreflightErrors = sets.List(ignorePreflightErrorsSet)
 | 
			
		||||
	initCfg.NodeRegistration.IgnorePreflightErrors = sets.List(ignorePreflightErrorsSet)
 | 
			
		||||
 | 
			
		||||
	var patchesDir string
 | 
			
		||||
	if upgradeCfg.Node.Patches != nil {
 | 
			
		||||
		patchesDir = cmdutil.ValueFromFlagsOrConfig(cmd.Flags(), options.Patches, upgradeCfg.Node.Patches.Directory, nodeOptions.patchesDir).(string)
 | 
			
		||||
	} else {
 | 
			
		||||
		patchesDir = nodeOptions.patchesDir
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &nodeData{
 | 
			
		||||
		etcdUpgrade:           options.etcdUpgrade,
 | 
			
		||||
		renewCerts:            options.renewCerts,
 | 
			
		||||
		dryRun:                options.dryRun,
 | 
			
		||||
		cfg:                   cfg,
 | 
			
		||||
		cfg:                   upgradeCfg,
 | 
			
		||||
		dryRun:                *dryRun,
 | 
			
		||||
		initCfg:               initCfg,
 | 
			
		||||
		client:                client,
 | 
			
		||||
		isControlPlaneNode:    isControlPlaneNode,
 | 
			
		||||
		patchesDir:            options.patchesDir,
 | 
			
		||||
		ignorePreflightErrors: ignorePreflightErrorsSet,
 | 
			
		||||
		kubeConfigPath:        options.kubeConfigPath,
 | 
			
		||||
		kubeConfigPath:        nodeOptions.kubeConfigPath,
 | 
			
		||||
		outputWriter:          out,
 | 
			
		||||
		patchesDir:            patchesDir,
 | 
			
		||||
		etcdUpgrade:           *cmdutil.ValueFromFlagsOrConfig(cmd.Flags(), options.EtcdUpgrade, upgradeCfg.Node.EtcdUpgrade, &nodeOptions.etcdUpgrade).(*bool),
 | 
			
		||||
		renewCerts:            *cmdutil.ValueFromFlagsOrConfig(cmd.Flags(), options.CertificateRenewal, upgradeCfg.Node.CertificateRenewal, &nodeOptions.renewCerts).(*bool),
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -186,11 +221,16 @@ func (d *nodeData) RenewCerts() bool {
 | 
			
		||||
	return d.renewCerts
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Cfg returns initConfiguration.
 | 
			
		||||
func (d *nodeData) Cfg() *kubeadmapi.InitConfiguration {
 | 
			
		||||
// Cfg returns upgradeConfiguration.
 | 
			
		||||
func (d *nodeData) Cfg() *kubeadmapi.UpgradeConfiguration {
 | 
			
		||||
	return d.cfg
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// InitCfg returns the InitConfiguration.
 | 
			
		||||
func (d *nodeData) InitCfg() *kubeadmapi.InitConfiguration {
 | 
			
		||||
	return d.initCfg
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsControlPlaneNode returns the isControlPlaneNode flag.
 | 
			
		||||
func (d *nodeData) IsControlPlaneNode() bool {
 | 
			
		||||
	return d.isControlPlaneNode
 | 
			
		||||
 
 | 
			
		||||
@@ -27,14 +27,17 @@ import (
 | 
			
		||||
	"github.com/lithammer/dedent"
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
	"github.com/spf13/cobra"
 | 
			
		||||
	"github.com/spf13/pflag"
 | 
			
		||||
 | 
			
		||||
	"k8s.io/apimachinery/pkg/runtime"
 | 
			
		||||
	"k8s.io/apimachinery/pkg/util/version"
 | 
			
		||||
	"k8s.io/cli-runtime/pkg/genericclioptions"
 | 
			
		||||
	"k8s.io/klog/v2"
 | 
			
		||||
 | 
			
		||||
	"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation"
 | 
			
		||||
	outputapischeme "k8s.io/kubernetes/cmd/kubeadm/app/apis/output/scheme"
 | 
			
		||||
	outputapiv1alpha3 "k8s.io/kubernetes/cmd/kubeadm/app/apis/output/v1alpha3"
 | 
			
		||||
	"k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
 | 
			
		||||
	cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util"
 | 
			
		||||
	"k8s.io/kubernetes/cmd/kubeadm/app/componentconfigs"
 | 
			
		||||
	"k8s.io/kubernetes/cmd/kubeadm/app/constants"
 | 
			
		||||
@@ -64,13 +67,16 @@ func newCmdPlan(apf *applyPlanFlags) *cobra.Command {
 | 
			
		||||
		Use:   "plan [version] [flags]",
 | 
			
		||||
		Short: "Check which versions are available to upgrade to and validate whether your current cluster is upgradeable.",
 | 
			
		||||
		Long:  upgradePlanLongDesc,
 | 
			
		||||
		RunE: func(_ *cobra.Command, args []string) error {
 | 
			
		||||
		RunE: func(cmd *cobra.Command, args []string) error {
 | 
			
		||||
			printer, err := outputFlags.ToPrinter()
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return errors.Wrap(err, "could not construct output printer")
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return runPlan(flags, args, printer)
 | 
			
		||||
			if err := validation.ValidateMixedArguments(cmd.Flags()); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			return runPlan(cmd.Flags(), flags, args, printer)
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -91,29 +97,41 @@ func newComponentUpgradePlan(name, currentVersion, newVersion string) outputapiv
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// runPlan takes care of outputting available versions to upgrade to for the user
 | 
			
		||||
func runPlan(flags *planFlags, args []string, printer output.Printer) error {
 | 
			
		||||
func runPlan(flagSet *pflag.FlagSet, flags *planFlags, args []string, printer output.Printer) error {
 | 
			
		||||
	// Start with the basics, verify that the cluster is healthy, build a client and a versionGetter. Never dry-run when planning.
 | 
			
		||||
	klog.V(1).Infoln("[upgrade/plan] verifying health of cluster")
 | 
			
		||||
	klog.V(1).Infoln("[upgrade/plan] retrieving configuration from cluster")
 | 
			
		||||
	client, versionGetter, cfg, err := enforceRequirements(flags.applyPlanFlags, args, false, false, printer, loadConfig)
 | 
			
		||||
	client, versionGetter, initCfg, upgradeCfg, err := enforceRequirements(flagSet, flags.applyPlanFlags, args, false, false, printer)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Currently this is the only method we have for distinguishing
 | 
			
		||||
	// external etcd vs static pod etcd
 | 
			
		||||
	isExternalEtcd := cfg.Etcd.External != nil
 | 
			
		||||
	isExternalEtcd := initCfg.Etcd.External != nil
 | 
			
		||||
 | 
			
		||||
	// Compute which upgrade possibilities there are
 | 
			
		||||
	klog.V(1).Infoln("[upgrade/plan] computing upgrade possibilities")
 | 
			
		||||
	availUpgrades, err := upgrade.GetAvailableUpgrades(versionGetter, flags.allowExperimentalUpgrades, flags.allowRCUpgrades, isExternalEtcd, client, constants.GetStaticPodDirectory(), printer)
 | 
			
		||||
 | 
			
		||||
	// flags are respected while keeping the configuration file not changed.
 | 
			
		||||
	allowRCUpgrades, ok := cmdutil.ValueFromFlagsOrConfig(flagSet, options.AllowRCUpgrades, upgradeCfg.Plan.AllowRCUpgrades, &flags.allowRCUpgrades).(*bool)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return cmdutil.TypeMismatchErr("allowRCUpgrades", "bool")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	allowExperimentalUpgrades, ok := cmdutil.ValueFromFlagsOrConfig(flagSet, options.AllowExperimentalUpgrades, upgradeCfg.Plan.AllowExperimentalUpgrades, &flags.allowExperimentalUpgrades).(*bool)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return cmdutil.TypeMismatchErr("allowExperimentalUpgrades", "bool")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	availUpgrades, err := upgrade.GetAvailableUpgrades(versionGetter, *allowExperimentalUpgrades, *allowRCUpgrades, isExternalEtcd, client, constants.GetStaticPodDirectory(), printer)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return errors.Wrap(err, "[upgrade/versions] FATAL")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Fetch the current state of the component configs
 | 
			
		||||
	klog.V(1).Infoln("[upgrade/plan] analysing component config version states")
 | 
			
		||||
	configVersionStates, err := componentconfigs.GetVersionStates(&cfg.ClusterConfiguration, client)
 | 
			
		||||
	configVersionStates, err := componentconfigs.GetVersionStates(&initCfg.ClusterConfiguration, client)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return errors.WithMessage(err, "[upgrade/versions] FATAL")
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -30,6 +30,7 @@ import (
 | 
			
		||||
	clientset "k8s.io/client-go/kubernetes"
 | 
			
		||||
	"k8s.io/client-go/tools/clientcmd"
 | 
			
		||||
	"k8s.io/klog/v2"
 | 
			
		||||
	"k8s.io/utils/ptr"
 | 
			
		||||
 | 
			
		||||
	"k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
 | 
			
		||||
	kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
 | 
			
		||||
@@ -135,6 +136,18 @@ func ValueFromFlagsOrConfig(flagSet *pflag.FlagSet, name string, cfgValue interf
 | 
			
		||||
	if flagSet.Changed(name) {
 | 
			
		||||
		return flagValue
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// covert the nil to false if this is a bool, this will help to get rid of nil dereference error.
 | 
			
		||||
	cfg, ok := cfgValue.(*bool)
 | 
			
		||||
	if ok && cfg == nil {
 | 
			
		||||
		return ptr.To(false)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// assume config has all the defaults set correctly.
 | 
			
		||||
	return cfgValue
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TypeMismatchErr return an error which indicates how the type is mismatched.
 | 
			
		||||
func TypeMismatchErr(opt, rType string) error {
 | 
			
		||||
	return errors.Errorf("type mismatch, %s is expected to be a pointer to %s", opt, rType)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -128,6 +128,12 @@ func TestValueFromFlagsOrConfig(t *testing.T) {
 | 
			
		||||
			flagValue: false,
 | 
			
		||||
			expected:  false,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:      "nil bool is converted to false",
 | 
			
		||||
			cfg:       (*bool)(nil),
 | 
			
		||||
			flagValue: false,
 | 
			
		||||
			expected:  false,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	for _, tt := range tests {
 | 
			
		||||
		type options struct {
 | 
			
		||||
@@ -140,11 +146,15 @@ func TestValueFromFlagsOrConfig(t *testing.T) {
 | 
			
		||||
		fs.BoolVar(&fakeOptions.bar, "bar", false, "")
 | 
			
		||||
 | 
			
		||||
		t.Run(tt.name, func(t *testing.T) {
 | 
			
		||||
			err := fs.Set(tt.flag, fmt.Sprintf("%v", tt.flagValue))
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				t.Fatalf("failed to set the value of the flag %v", tt.flagValue)
 | 
			
		||||
			if tt.flag != "" {
 | 
			
		||||
				if err := fs.Set(tt.flag, fmt.Sprintf("%v", tt.flagValue)); err != nil {
 | 
			
		||||
					t.Fatalf("failed to set the value of the flag %v", tt.flagValue)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			actualResult := ValueFromFlagsOrConfig(&fs, tt.flag, tt.cfg, tt.flagValue)
 | 
			
		||||
			if result, ok := actualResult.(*bool); ok {
 | 
			
		||||
				actualResult = *result
 | 
			
		||||
			}
 | 
			
		||||
			if actualResult != tt.expected {
 | 
			
		||||
				t.Errorf(
 | 
			
		||||
					"failed ValueFromFlagsOrConfig:\n\texpected: %s\n\t  actual: %s",
 | 
			
		||||
 
 | 
			
		||||
@@ -452,6 +452,8 @@ const (
 | 
			
		||||
	EtcdUserName string = "kubeadm-etcd"
 | 
			
		||||
	// ServiceAccountKeyReadersGroupName is the group of users that are allowed to read the service account private key.
 | 
			
		||||
	ServiceAccountKeyReadersGroupName string = "kubeadm-sa-key-readers"
 | 
			
		||||
	// UpgradeConfigurationKind is the string kind value for the UpgradeConfiguration struct
 | 
			
		||||
	UpgradeConfigurationKind = "UpgradeConfiguration"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
 
 | 
			
		||||
@@ -14,6 +14,7 @@ See the License for the specific language governing permissions and
 | 
			
		||||
limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
// Package config contains utilities for managing the kubeadm configuration API.
 | 
			
		||||
package config
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
@@ -490,3 +491,13 @@ func defaultEmptyMigrateMutators() migrateMutators {
 | 
			
		||||
 | 
			
		||||
	return *mutators
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// isKubeadmConfigPresent checks if a kubeadm config type is found in the provided document map
 | 
			
		||||
func isKubeadmConfigPresent(docmap kubeadmapi.DocumentMap) bool {
 | 
			
		||||
	for gvk := range docmap {
 | 
			
		||||
		if gvk.Group == kubeadmapi.GroupName {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -858,3 +858,52 @@ func TestDefaultMigrateMutators(t *testing.T) {
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestIsKubeadmConfigPresent(t *testing.T) {
 | 
			
		||||
	var tcases = []struct {
 | 
			
		||||
		name     string
 | 
			
		||||
		gvkmap   kubeadmapi.DocumentMap
 | 
			
		||||
		expected bool
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			name: " Wrong Group value",
 | 
			
		||||
			gvkmap: kubeadmapi.DocumentMap{
 | 
			
		||||
				{Group: "foo.k8s.io", Version: "v1", Kind: "Foo"}: []byte(`kind: Foo`),
 | 
			
		||||
			},
 | 
			
		||||
			expected: false,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "Empty Group value",
 | 
			
		||||
			gvkmap: kubeadmapi.DocumentMap{
 | 
			
		||||
				{Group: "", Version: "v1", Kind: "Empty"}: []byte(`kind: Empty`),
 | 
			
		||||
			},
 | 
			
		||||
			expected: false,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:     "Nil value",
 | 
			
		||||
			gvkmap:   nil,
 | 
			
		||||
			expected: false,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "Correct Group value 1",
 | 
			
		||||
			gvkmap: kubeadmapi.DocumentMap{
 | 
			
		||||
				{Group: "kubeadm.k8s.io", Version: "v1", Kind: "Empty"}: []byte(`kind: Empty`),
 | 
			
		||||
			},
 | 
			
		||||
			expected: true,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "Correct Group value 2",
 | 
			
		||||
			gvkmap: kubeadmapi.DocumentMap{
 | 
			
		||||
				{Group: kubeadmapi.GroupName, Version: "v1", Kind: "Empty"}: []byte(`kind: Empty`),
 | 
			
		||||
			},
 | 
			
		||||
			expected: true,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	for _, tt := range tcases {
 | 
			
		||||
		t.Run(tt.name, func(t *testing.T) {
 | 
			
		||||
			if isKubeadmConfigPresent(tt.gvkmap) != tt.expected {
 | 
			
		||||
				t.Error("unexpected result")
 | 
			
		||||
			}
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										158
									
								
								cmd/kubeadm/app/util/config/upgradeconfiguration.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										158
									
								
								cmd/kubeadm/app/util/config/upgradeconfiguration.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,158 @@
 | 
			
		||||
/*
 | 
			
		||||
Copyright 2024 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 config
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"os"
 | 
			
		||||
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
 | 
			
		||||
	"k8s.io/apimachinery/pkg/runtime"
 | 
			
		||||
	"k8s.io/apimachinery/pkg/util/sets"
 | 
			
		||||
	"k8s.io/klog/v2"
 | 
			
		||||
	kubeproxyconfig "k8s.io/kube-proxy/config/v1alpha1"
 | 
			
		||||
	kubeletconfig "k8s.io/kubelet/config/v1beta1"
 | 
			
		||||
 | 
			
		||||
	kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
 | 
			
		||||
	kubeadmscheme "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/scheme"
 | 
			
		||||
	kubeadmapiv1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta4"
 | 
			
		||||
	"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation"
 | 
			
		||||
	"k8s.io/kubernetes/cmd/kubeadm/app/componentconfigs"
 | 
			
		||||
	kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
 | 
			
		||||
	"k8s.io/kubernetes/cmd/kubeadm/app/util/config/strict"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var componentCfgGV = sets.New(kubeproxyconfig.GroupName, kubeletconfig.GroupName)
 | 
			
		||||
 | 
			
		||||
// DefaultUpgradeConfiguration return a default UpgradeConfiguration
 | 
			
		||||
func DefaultUpgradeConfiguration() (*kubeadmapi.UpgradeConfiguration, error) {
 | 
			
		||||
	versionedCfg := &kubeadmapiv1.UpgradeConfiguration{}
 | 
			
		||||
	kubeadmscheme.Scheme.Default(versionedCfg)
 | 
			
		||||
	cfg := &kubeadmapi.UpgradeConfiguration{}
 | 
			
		||||
	if err := kubeadmscheme.Scheme.Convert(versionedCfg, cfg, nil); err != nil {
 | 
			
		||||
		return nil, errors.Wrap(err, "could not prepare a defaulted UpgradeConfiguration")
 | 
			
		||||
	}
 | 
			
		||||
	return cfg, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// documentMapToUpgradeConfiguration takes a map between GVKs and YAML documents (as returned by SplitYAMLDocuments),
 | 
			
		||||
// finds a UpgradeConfiguration, decodes it, dynamically defaults it and then validates it prior to return.
 | 
			
		||||
func documentMapToUpgradeConfiguration(gvkmap kubeadmapi.DocumentMap, allowDeprecated bool) (*kubeadmapi.UpgradeConfiguration, error) {
 | 
			
		||||
	var internalcfg *kubeadmapi.UpgradeConfiguration
 | 
			
		||||
 | 
			
		||||
	for gvk, bytes := range gvkmap {
 | 
			
		||||
		// check if this version is supported and possibly not deprecated
 | 
			
		||||
		if err := validateSupportedVersion(gvk.GroupVersion(), allowDeprecated, true); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// verify the validity of the YAML
 | 
			
		||||
		if err := strict.VerifyUnmarshalStrict([]*runtime.Scheme{kubeadmscheme.Scheme}, gvk, bytes); err != nil {
 | 
			
		||||
			klog.Warning(err.Error())
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if kubeadmutil.GroupVersionKindsHasInitConfiguration(gvk) || kubeadmutil.GroupVersionKindsHasClusterConfiguration(gvk) {
 | 
			
		||||
			klog.Warningf("[config] WARNING: YAML document with GroupVersionKind %v is deprecated for upgrade, please use config file with kind of UpgradeConfiguration instead \n", gvk)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if kubeadmutil.GroupVersionKindsHasUpgradeConfiguration(gvk) {
 | 
			
		||||
			// Set internalcfg to an empty struct value the deserializer will populate
 | 
			
		||||
			internalcfg = &kubeadmapi.UpgradeConfiguration{}
 | 
			
		||||
			// Decode the bytes into the internal struct. Under the hood, the bytes will be unmarshalled into the
 | 
			
		||||
			// right external version, defaulted, and converted into the internal version.
 | 
			
		||||
			if err := runtime.DecodeInto(kubeadmscheme.Codecs.UniversalDecoder(), bytes, internalcfg); err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// If the group is neither a kubeadm core type or of a supported component config group, we dump a warning about it being ignored
 | 
			
		||||
		if !componentconfigs.Scheme.IsGroupRegistered(gvk.Group) {
 | 
			
		||||
			klog.Warningf("[config] WARNING: Ignored YAML document with GroupVersionKind %v\n", gvk)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// If UpgradeConfiguration wasn't given, default it by creating an external struct instance, default it and convert into the internal type
 | 
			
		||||
	if internalcfg == nil {
 | 
			
		||||
		extinitcfg := &kubeadmapiv1.UpgradeConfiguration{}
 | 
			
		||||
		kubeadmscheme.Scheme.Default(extinitcfg)
 | 
			
		||||
		// Set upgradeCfg to an empty struct value the deserializer will populate
 | 
			
		||||
		internalcfg = &kubeadmapi.UpgradeConfiguration{}
 | 
			
		||||
		if err := kubeadmscheme.Scheme.Convert(extinitcfg, internalcfg, nil); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Validates cfg
 | 
			
		||||
	if err := validation.ValidateUpgradeConfiguration(internalcfg).ToAggregate(); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return internalcfg, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DocMapToUpgradeConfiguration converts documentMap to an internal, defaulted and validated UpgradeConfiguration object.
 | 
			
		||||
// The map may contain many different YAML documents. These YAML documents are parsed one-by-one
 | 
			
		||||
// and well-known ComponentConfig GroupVersionKinds are stored inside of the internal UpgradeConfiguration struct.
 | 
			
		||||
// The resulting UpgradeConfiguration is then dynamically defaulted and validated prior to return.
 | 
			
		||||
func DocMapToUpgradeConfiguration(gvkmap kubeadmapi.DocumentMap) (*kubeadmapi.UpgradeConfiguration, error) {
 | 
			
		||||
	return documentMapToUpgradeConfiguration(gvkmap, false)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LoadUpgradeConfig loads UpgradeConfiguration from a file.
 | 
			
		||||
func LoadUpgradeConfig(cfgPath string) (*kubeadmapi.UpgradeConfiguration, error) {
 | 
			
		||||
	var err error
 | 
			
		||||
	var upgradeCfg *kubeadmapi.UpgradeConfiguration
 | 
			
		||||
	if cfgPath == "" {
 | 
			
		||||
		if upgradeCfg, err = DefaultUpgradeConfiguration(); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		return upgradeCfg, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Otherwise, we have a config file. Let's load it.
 | 
			
		||||
	configBytes, err := os.ReadFile(cfgPath)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errors.Wrapf(err, "unable to load config from file %q", cfgPath)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Split the YAML documents in the file into a DocumentMap
 | 
			
		||||
	docmap, err := kubeadmutil.SplitYAMLDocuments(configBytes)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Convert documentMap to internal UpgradeConfiguration, InitConfiguration and ClusterConfiguration from config file will be ignored.
 | 
			
		||||
	// Upgrade should respect the cluster configuration from the existing cluster, re-configure the cluster with a InitConfiguration and
 | 
			
		||||
	// ClusterConfiguration from the config file is not allowed for upgrade.
 | 
			
		||||
	if isKubeadmConfigPresent(docmap) {
 | 
			
		||||
		if upgradeCfg, err = DocMapToUpgradeConfiguration(docmap); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Check is there any component configs defined in the config file.
 | 
			
		||||
	for gvk := range docmap {
 | 
			
		||||
		if componentCfgGV.Has(gvk.Group) {
 | 
			
		||||
			klog.Warningf("[config] WARNING: YAML document with Component Configs %v is deprecated for upgrade and will be ignored \n", gvk.Group)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return upgradeCfg, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										104
									
								
								cmd/kubeadm/app/util/config/upgradeconfiguration_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								cmd/kubeadm/app/util/config/upgradeconfiguration_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,104 @@
 | 
			
		||||
/*
 | 
			
		||||
Copyright 2024 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 config
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
			
		||||
	"k8s.io/utils/ptr"
 | 
			
		||||
	"sigs.k8s.io/yaml"
 | 
			
		||||
 | 
			
		||||
	"github.com/google/go-cmp/cmp"
 | 
			
		||||
	kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
 | 
			
		||||
	kubeadmapiv1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta4"
 | 
			
		||||
	"k8s.io/kubernetes/cmd/kubeadm/app/constants"
 | 
			
		||||
	kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestDocMapToUpgradeConfiguration(t *testing.T) {
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		name        string
 | 
			
		||||
		cfg         kubeadmapiv1.UpgradeConfiguration
 | 
			
		||||
		expectedCfg kubeadmapi.UpgradeConfiguration
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			name: "default config is set correctly",
 | 
			
		||||
			cfg: kubeadmapiv1.UpgradeConfiguration{
 | 
			
		||||
				TypeMeta: metav1.TypeMeta{
 | 
			
		||||
					APIVersion: kubeadmapiv1.SchemeGroupVersion.String(),
 | 
			
		||||
					Kind:       constants.UpgradeConfigurationKind,
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expectedCfg: kubeadmapi.UpgradeConfiguration{
 | 
			
		||||
				Apply: kubeadmapi.UpgradeApplyConfiguration{
 | 
			
		||||
					CertificateRenewal: ptr.To(true),
 | 
			
		||||
					EtcdUpgrade:        ptr.To(true),
 | 
			
		||||
				},
 | 
			
		||||
				Node: kubeadmapi.UpgradeNodeConfiguration{
 | 
			
		||||
					CertificateRenewal: ptr.To(true),
 | 
			
		||||
					EtcdUpgrade:        ptr.To(true),
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "cfg has part of fields configured",
 | 
			
		||||
			cfg: kubeadmapiv1.UpgradeConfiguration{
 | 
			
		||||
				Apply: kubeadmapiv1.UpgradeApplyConfiguration{
 | 
			
		||||
					CertificateRenewal: ptr.To(false),
 | 
			
		||||
				},
 | 
			
		||||
				Node: kubeadmapiv1.UpgradeNodeConfiguration{
 | 
			
		||||
					EtcdUpgrade: ptr.To(false),
 | 
			
		||||
				},
 | 
			
		||||
				TypeMeta: metav1.TypeMeta{
 | 
			
		||||
					APIVersion: kubeadmapiv1.SchemeGroupVersion.String(),
 | 
			
		||||
					Kind:       constants.UpgradeConfigurationKind,
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expectedCfg: kubeadmapi.UpgradeConfiguration{
 | 
			
		||||
				Apply: kubeadmapi.UpgradeApplyConfiguration{
 | 
			
		||||
					CertificateRenewal: ptr.To(false),
 | 
			
		||||
					EtcdUpgrade:        ptr.To(true),
 | 
			
		||||
				},
 | 
			
		||||
				Node: kubeadmapi.UpgradeNodeConfiguration{
 | 
			
		||||
					CertificateRenewal: ptr.To(true),
 | 
			
		||||
					EtcdUpgrade:        ptr.To(false),
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, tc := range tests {
 | 
			
		||||
		t.Run(tc.name, func(t *testing.T) {
 | 
			
		||||
			b, err := yaml.Marshal(tc.cfg)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				t.Fatalf("unexpected error while marshalling to YAML: %v", err)
 | 
			
		||||
			}
 | 
			
		||||
			docmap, err := kubeadmutil.SplitYAMLDocuments(b)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				t.Fatalf("Unexpect error of SplitYAMLDocuments: %v", err)
 | 
			
		||||
			}
 | 
			
		||||
			cfg, err := DocMapToUpgradeConfiguration(docmap)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				t.Fatalf("unexpected error of DocMapToUpgradeConfiguration: %v\nconfig: %s", err, string(b))
 | 
			
		||||
			}
 | 
			
		||||
			if diff := cmp.Diff(*cfg, tc.expectedCfg); diff != "" {
 | 
			
		||||
				t.Fatalf("DocMapToUpgradeConfiguration returned unexpected diff (-want,+got):\n%s", diff)
 | 
			
		||||
			}
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -151,3 +151,8 @@ func GroupVersionKindsHasJoinConfiguration(gvks ...schema.GroupVersionKind) bool
 | 
			
		||||
func GroupVersionKindsHasResetConfiguration(gvks ...schema.GroupVersionKind) bool {
 | 
			
		||||
	return GroupVersionKindsHasKind(gvks, constants.ResetConfigurationKind)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GroupVersionKindsHasUpgradeConfiguration returns whether the following gvk slice contains a UpgradeConfiguration object
 | 
			
		||||
func GroupVersionKindsHasUpgradeConfiguration(gvks ...schema.GroupVersionKind) bool {
 | 
			
		||||
	return GroupVersionKindsHasKind(gvks, constants.UpgradeConfigurationKind)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -431,3 +431,69 @@ func TestGroupVersionKindsHasResetConfiguration(t *testing.T) {
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestGroupVersionKindsHasClusterConfiguration(t *testing.T) {
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		name     string
 | 
			
		||||
		gvks     []schema.GroupVersionKind
 | 
			
		||||
		expected bool
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			name: "does not have ClusterConfiguraiton",
 | 
			
		||||
			gvks: []schema.GroupVersionKind{
 | 
			
		||||
				{Group: "foo.k8s.io", Version: "v1", Kind: "Foo"},
 | 
			
		||||
			},
 | 
			
		||||
			expected: false,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "has ClusterConfiguraiton",
 | 
			
		||||
			gvks: []schema.GroupVersionKind{
 | 
			
		||||
				{Group: "foo.k8s.io", Version: "v1", Kind: "Foo"},
 | 
			
		||||
				{Group: "foo.k8s.io", Version: "v1", Kind: "ClusterConfiguration"},
 | 
			
		||||
			},
 | 
			
		||||
			expected: true,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	for _, rt := range tests {
 | 
			
		||||
		t.Run(rt.name, func(t *testing.T) {
 | 
			
		||||
			actual := GroupVersionKindsHasClusterConfiguration(rt.gvks...)
 | 
			
		||||
			if rt.expected != actual {
 | 
			
		||||
				t.Errorf("expected gvks to have a ClusterConfiguration: %t\n\tactual: %t\n", rt.expected, actual)
 | 
			
		||||
			}
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestGroupVersionKindsHasUpgradeConfiguration(t *testing.T) {
 | 
			
		||||
	var tests = []struct {
 | 
			
		||||
		name     string
 | 
			
		||||
		gvks     []schema.GroupVersionKind
 | 
			
		||||
		kind     string
 | 
			
		||||
		expected bool
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			name: "no UpgradeConfiguration found",
 | 
			
		||||
			gvks: []schema.GroupVersionKind{
 | 
			
		||||
				{Group: "foo.k8s.io", Version: "v1", Kind: "Foo"},
 | 
			
		||||
			},
 | 
			
		||||
			expected: false,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "UpgradeConfiguration is found",
 | 
			
		||||
			gvks: []schema.GroupVersionKind{
 | 
			
		||||
				{Group: "foo.k8s.io", Version: "v1", Kind: "Foo"},
 | 
			
		||||
				{Group: "bar.k8s.io", Version: "v2", Kind: "UpgradeConfiguration"},
 | 
			
		||||
			},
 | 
			
		||||
			expected: true,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, rt := range tests {
 | 
			
		||||
		t.Run(rt.name, func(t2 *testing.T) {
 | 
			
		||||
			actual := GroupVersionKindsHasUpgradeConfiguration(rt.gvks...)
 | 
			
		||||
			if rt.expected != actual {
 | 
			
		||||
				t2.Errorf("expected gvks has UpgradeConfiguration: %t\n\tactual: %t\n", rt.expected, actual)
 | 
			
		||||
			}
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user