From b76c117bdcef802d752714108719c5c63ef4654c Mon Sep 17 00:00:00 2001 From: thiyyakat Date: Wed, 29 Oct 2025 11:24:50 +0530 Subject: [PATCH 01/43] [WIP] Add support for machine preservation through annotations # Conflicts: # pkg/util/provider/machinecontroller/machine.go # pkg/util/provider/machinecontroller/machine_util.go --- ...achine.sapcloud.io_machinedeployments.yaml | 4 + .../crds/machine.sapcloud.io_machines.yaml | 9 ++ .../crds/machine.sapcloud.io_machinesets.yaml | 9 ++ machine-controller-manager | 1 + pkg/apis/machine/types.go | 3 + pkg/apis/machine/v1alpha1/machine_types.go | 6 + pkg/apis/machine/v1alpha1/machineset_types.go | 4 + pkg/apis/machine/v1alpha1/shared_types.go | 4 + pkg/controller/machineset.go | 1 + .../provider/machinecontroller/machine.go | 60 ++++++++++ .../machinecontroller/machine_util.go | 111 +++++++++++++++++- pkg/util/provider/machineutils/utils.go | 23 ++++ pkg/util/provider/options/types.go | 3 + 13 files changed, 236 insertions(+), 2 deletions(-) create mode 160000 machine-controller-manager diff --git a/kubernetes/crds/machine.sapcloud.io_machinedeployments.yaml b/kubernetes/crds/machine.sapcloud.io_machinedeployments.yaml index d836282a2..848dc96ce 100644 --- a/kubernetes/crds/machine.sapcloud.io_machinedeployments.yaml +++ b/kubernetes/crds/machine.sapcloud.io_machinedeployments.yaml @@ -419,6 +419,10 @@ spec: type: boolean type: object type: object + preserveTimeout: + description: MachinePreserveTimeout is the timeout after the + machine preservation is stopped + type: string providerID: description: ProviderID represents the provider's unique ID given to a machine diff --git a/kubernetes/crds/machine.sapcloud.io_machines.yaml b/kubernetes/crds/machine.sapcloud.io_machines.yaml index 9378f0274..1d9150c4d 100644 --- a/kubernetes/crds/machine.sapcloud.io_machines.yaml +++ b/kubernetes/crds/machine.sapcloud.io_machines.yaml @@ -216,6 +216,10 @@ spec: type: boolean type: object type: object + preserveTimeout: + description: MachinePreserveTimeout is the timeout after the machine + preservation is stopped + type: string providerID: description: ProviderID represents the provider's unique ID given to a machine @@ -287,6 +291,11 @@ spec: description: MachinePhase is a label for the condition of a machine at the current time. type: string + preserveExpiryTime: + description: PreserveExpiryTime is the time at which MCM will + stop preserving the machine + format: date-time + type: string timeoutActive: type: boolean type: object diff --git a/kubernetes/crds/machine.sapcloud.io_machinesets.yaml b/kubernetes/crds/machine.sapcloud.io_machinesets.yaml index c569dffe1..9a6f616fc 100644 --- a/kubernetes/crds/machine.sapcloud.io_machinesets.yaml +++ b/kubernetes/crds/machine.sapcloud.io_machinesets.yaml @@ -301,6 +301,10 @@ spec: type: boolean type: object type: object + preserveTimeout: + description: MachinePreserveTimeout is the timeout after the + machine preservation is stopped + type: string providerID: description: ProviderID represents the provider's unique ID given to a machine @@ -312,6 +316,11 @@ spec: description: MachineSetStatus holds the most recently observed status of MachineSet. properties: + autoPreserveFailedMachineCount: + description: AutoPreserveFailedMachineCount is the number of machines + in the machine set that have been auto-preserved upon failure + format: int32 + type: integer availableReplicas: description: The number of available replicas (ready for at least minReadySeconds) for this replica set. diff --git a/machine-controller-manager b/machine-controller-manager new file mode 160000 index 000000000..f2cbb0378 --- /dev/null +++ b/machine-controller-manager @@ -0,0 +1 @@ +Subproject commit f2cbb037802eb399e7b655388ef6e182c90cb70f diff --git a/pkg/apis/machine/types.go b/pkg/apis/machine/types.go index 0facf09ba..4f6c6a8d5 100644 --- a/pkg/apis/machine/types.go +++ b/pkg/apis/machine/types.go @@ -97,6 +97,9 @@ type MachineConfiguration struct { // MachineInPlaceUpdateTimeout is the timeout after which in-place update is declared failed. MachineInPlaceUpdateTimeout *metav1.Duration + // MachinePreserveTimeout is the timeout after the machine preservation is stopped + // +optional + MachinePreserveTimeout *metav1.Duration `json:"preserveTimeout,omitempty"` // DisableHealthTimeout if set to true, health timeout will be ignored. Leading to machine never being declared failed. // This is intended to be used only for in-place updates. DisableHealthTimeout *bool diff --git a/pkg/apis/machine/v1alpha1/machine_types.go b/pkg/apis/machine/v1alpha1/machine_types.go index 19e017925..72ac95880 100644 --- a/pkg/apis/machine/v1alpha1/machine_types.go +++ b/pkg/apis/machine/v1alpha1/machine_types.go @@ -204,6 +204,9 @@ const ( // MachineOperationDelete indicates that the operation was a delete MachineOperationDelete MachineOperationType = "Delete" + + // MachineOperationPreserve indicates that the operation was a preserve + MachineOperationPreserve MachineOperationType = "Preserve" ) // The below types are used by kube_client and api_server. @@ -252,6 +255,9 @@ type CurrentStatus struct { // Last update time of current status LastUpdateTime metav1.Time `json:"lastUpdateTime,omitempty"` + + // PreserveExpiryTime is the time at which MCM will stop preserving the machine + PreserveExpiryTime metav1.Time `json:"preserveExpiryTime,omitempty"` } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object diff --git a/pkg/apis/machine/v1alpha1/machineset_types.go b/pkg/apis/machine/v1alpha1/machineset_types.go index 2e6eb1d6e..b9ad20ec4 100644 --- a/pkg/apis/machine/v1alpha1/machineset_types.go +++ b/pkg/apis/machine/v1alpha1/machineset_types.go @@ -135,4 +135,8 @@ type MachineSetStatus struct { // FailedMachines has summary of machines on which lastOperation Failed // +optional FailedMachines *[]MachineSummary `json:"failedMachines,omitempty"` + + // AutoPreserveFailedMachineCount is the number of machines in the machine set that have been auto-preserved upon failure + // +optional + AutoPreserveFailedMachineCount int32 `json:"autoPreserveFailedMachineCount,omitempty"` } diff --git a/pkg/apis/machine/v1alpha1/shared_types.go b/pkg/apis/machine/v1alpha1/shared_types.go index 687151218..832254149 100644 --- a/pkg/apis/machine/v1alpha1/shared_types.go +++ b/pkg/apis/machine/v1alpha1/shared_types.go @@ -44,6 +44,10 @@ type MachineConfiguration struct { // +optional MachineInPlaceUpdateTimeout *metav1.Duration `json:"inPlaceUpdateTimeout,omitempty"` + // MachinePreserveTimeout is the timeout after the machine preservation is stopped + // +optional + MachinePreserveTimeout *metav1.Duration `json:"preserveTimeout,omitempty"` + // DisableHealthTimeout if set to true, health timeout will be ignored. Leading to machine never being declared failed. // This is intended to be used only for in-place updates. // +optional diff --git a/pkg/controller/machineset.go b/pkg/controller/machineset.go index 6a5701e3e..b445efef3 100644 --- a/pkg/controller/machineset.go +++ b/pkg/controller/machineset.go @@ -672,6 +672,7 @@ func slowStartBatch(count int, initialBatchSize int, fn func() error) (int, erro return successes, nil } +// TODO@thiyyakat: ensure preserved machines are the last to be deleted func getMachinesToDelete(filteredMachines []*v1alpha1.Machine, diff int) []*v1alpha1.Machine { // No need to sort machines if we are about to delete all of them. // diff will always be <= len(filteredMachines), so not need to handle > case. diff --git a/pkg/util/provider/machinecontroller/machine.go b/pkg/util/provider/machinecontroller/machine.go index 420c3a87d..8df22e071 100644 --- a/pkg/util/provider/machinecontroller/machine.go +++ b/pkg/util/provider/machinecontroller/machine.go @@ -718,3 +718,63 @@ func (c *controller) isCreationProcessing(machine *v1alpha1.Machine) bool { _, isMachineInCreationFlow := c.pendingMachineCreationMap.Load(getMachineKey(machine)) return isMachineInCreationFlow } + +// TODO@thiyyakat: check case where, preserved and annotated but times out. Not handled currently +// possible cases: +// 1. Annotated +// - already preserved, check for timeout +// - already preserved, check for explicit stop preservation +// - needs to be preserved on failure +// - needs to be preserved now +// 2. Unannotated +// - failed machine, autoPreserveMax not breached, must be preserved +// - failed machine, already preserved, check for timeout +// Auto-preserve case will have to be handled where machine moved from Unknown to Failed + +func (c *controller) machinePreservation(ctx context.Context, machine *v1alpha1.Machine) (machineutils.RetryPeriod, error) { + // check if rolling update is ongoing, if yes, do nothing + machineDeployment, err := c.getMachineDeploymentForMachine(machine) + if err != nil { + klog.Errorf("Error getting machine deployment for machine %q: %s", machine.Name, err) + return machineutils.ShortRetry, err + } + for _, c := range machineDeployment.Status.Conditions { + if c.Type == v1alpha1.MachineDeploymentProgressing { + if c.Status == v1alpha1.ConditionTrue { + return machineutils.LongRetry, nil + } + break + } + } + // check if machine needs to be preserved due to annotation + isPreserved := machineutils.IsMachinePreserved(machine) + value, exists := machine.Annotations[machineutils.PreserveMachineAnnotationKey] + if !isPreserved && exists { + switch value { + case machineutils.PreserveMachineAnnotationValueNow: + return c.preserveMachine(ctx, machine) + case machineutils.PreserveMachineAnnotationValueWhenFailed: + // check if machine is in Failed state + if machineutils.IsMachineFailed(machine) { + return c.preserveMachine(ctx, machine) + } + } + } else if isPreserved { + if value == machineutils.PreserveMachineAnnotationValueFalse || metav1.Now().After(machine.Status.CurrentStatus.PreserveExpiryTime.Time) { + return c.stopMachinePreservation(ctx, machine) + } + } + // if the machine is neither preserved nor annotated, need not handle it here. Auto-preservation + // handled on failure + return machineutils.LongRetry, nil +} + +// getMachineDeploymentForMachine returns the machine deployment for a given machine +func (c *controller) getMachineDeploymentForMachine(machine *v1alpha1.Machine) (*v1alpha1.MachineDeployment, error) { + machineDeploymentName := getMachineDeploymentName(machine) + machineDeployment, err := c.controlMachineClient.MachineDeployments(c.namespace).Get(context.TODO(), machineDeploymentName, metav1.GetOptions{ + TypeMeta: metav1.TypeMeta{}, + ResourceVersion: "", + }) + return machineDeployment, err +} diff --git a/pkg/util/provider/machinecontroller/machine_util.go b/pkg/util/provider/machinecontroller/machine_util.go index 36fa6f414..ef1a54a42 100644 --- a/pkg/util/provider/machinecontroller/machine_util.go +++ b/pkg/util/provider/machinecontroller/machine_util.go @@ -29,6 +29,8 @@ import ( "errors" "fmt" "maps" + "github.com/gardener/machine-controller-manager/pkg/controller/autoscaler" + "github.com/gardener/machine-controller-manager/pkg/util/annotations" "math" "runtime" "strconv" @@ -1293,7 +1295,8 @@ func (c *controller) setMachineTerminationStatus(ctx context.Context, deleteMach clone.Status.CurrentStatus = v1alpha1.CurrentStatus{ Phase: v1alpha1.MachineTerminating, // TimeoutActive: false, - LastUpdateTime: metav1.Now(), + LastUpdateTime: metav1.Now(), + PreserveExpiryTime: metav1.Time{}, } _, err := c.controlMachineClient.Machines(clone.Namespace).UpdateStatus(ctx, clone, metav1.UpdateOptions{}) @@ -2034,7 +2037,7 @@ func (c *controller) getEffectiveHealthTimeout(machine *v1alpha1.Machine) *metav return effectiveHealthTimeout } -// getEffectiveHealthTimeout returns the creationTimeout set on the machine-object, otherwise returns the timeout set using the global-flag. +// getEffectiveCreationTimeout returns the creationTimeout set on the machine-object, otherwise returns the timeout set using the global-flag. func (c *controller) getEffectiveCreationTimeout(machine *v1alpha1.Machine) *metav1.Duration { var effectiveCreationTimeout *metav1.Duration if machine.Spec.MachineConfiguration != nil && machine.Spec.MachineConfiguration.MachineCreationTimeout != nil { @@ -2333,3 +2336,107 @@ func (c *controller) fetchMatchingNodeName(machineName string) (string, error) { } return "", fmt.Errorf("machine %q not found in node lister for machine %q", machineName, machineName) } + +func (c *controller) preserveMachine(ctx context.Context, machine *v1alpha1.Machine) (machineutils.RetryPeriod, error) { + clone := machine.DeepCopy() + klog.V(2).Infof("Preserving machine %q", machine.Name) + clone.Status.LastOperation = v1alpha1.LastOperation{ + Description: "Preserving machine", + State: v1alpha1.MachineStateSuccessful, + Type: v1alpha1.MachineOperationPreserve, + LastUpdateTime: metav1.Now(), + } + clone.Status.CurrentStatus = v1alpha1.CurrentStatus{ + Phase: clone.Status.CurrentStatus.Phase, + LastUpdateTime: metav1.Now(), + PreserveExpiryTime: metav1.NewTime(metav1.Now().Add(c.getEffectiveMachinePreserveTimeout(machine).Duration)), + } + // if backing node exists, add annotations to prevent scale down by autoscaler + if machine.Labels[v1alpha1.NodeLabelKey] != "" { + clusterAutoscalerScaleDownAnnotations := make(map[string]string) + clusterAutoscalerScaleDownAnnotations[autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationKey] = autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationValue + // We do this to avoid accidentally deleting the user provided annotations. + clusterAutoscalerScaleDownAnnotations[autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationByMCMKey] = autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationByMCMValue + nodeName := machine.Labels[v1alpha1.NodeLabelKey] + node, err := c.nodeLister.Get(nodeName) + if err != nil { + klog.Errorf("Error trying to get node %q: %v", nodeName, err) + return machineutils.ShortRetry, err + } + updatedNode, _, err := annotations.AddOrUpdateAnnotation(node, clusterAutoscalerScaleDownAnnotations) + if err != nil { + klog.Warningf("Adding annotation failed for node: %s, %s", machine.Labels[v1alpha1.NodeLabelKey], err) + } + _, err = c.targetCoreClient.CoreV1().Nodes().Update(ctx, updatedNode, metav1.UpdateOptions{}) + if err != nil { + klog.Errorf("Error trying to update node %q: %v", nodeName, err) + return machineutils.ShortRetry, err + } + } + _, err := c.controlMachineClient.Machines(clone.Namespace).UpdateStatus(ctx, clone, metav1.UpdateOptions{}) + if err != nil { + // Keep retrying until update goes through + klog.Errorf("Machine/status UPDATE failed for machine %q. Retrying, error: %s", machine.Name, err) + } else { + klog.V(2).Infof("Machine %q status updated to preserved ", machine.Name) + // Return error even when machine object is updated to ensure reconcilation is restarted + err = fmt.Errorf("machine preservation in process") + } + if apierrors.IsConflict(err) { + return machineutils.ConflictRetry, err + } + return machineutils.ShortRetry, err +} + +func (c *controller) stopMachinePreservation(ctx context.Context, machine *v1alpha1.Machine) (machineutils.RetryPeriod, error) { + clone := machine.DeepCopy() + delete(clone.Annotations, autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationKey) + delete(clone.Annotations, autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationByMCMKey) + delete(clone.Annotations, machineutils.PreserveMachineAnnotationKey) + // if backing node exists, remove annotations that would prevent scale down by autoscaler + if machine.Labels[v1alpha1.NodeLabelKey] != "" { + nodeName := machine.Labels[v1alpha1.NodeLabelKey] + node, err := c.nodeLister.Get(nodeName) + if err != nil { + klog.Errorf("Error trying to get node %q: %v", nodeName, err) + return machineutils.ShortRetry, err + } + //remove annotations from node, values do not matter here + preservationAnnotations := make(map[string]string) + preservationAnnotations[autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationKey] = "" + preservationAnnotations[autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationByMCMKey] = "" + preservationAnnotations[machineutils.PreserveMachineAnnotationKey] = "" + updatedNode, _, err := annotations.RemoveAnnotation(node, preservationAnnotations) + if err != nil { + klog.Warningf("Removing annotation failed for node: %s, %s", machine.Labels[v1alpha1.NodeLabelKey], err) + } + _, err = c.targetCoreClient.CoreV1().Nodes().Update(ctx, updatedNode, metav1.UpdateOptions{}) + if err != nil { + klog.Errorf("Error trying to update node %q: %v", nodeName, err) + return machineutils.ShortRetry, err + } + } + clone.Status.CurrentStatus = v1alpha1.CurrentStatus{ + Phase: clone.Status.CurrentStatus.Phase, + LastUpdateTime: metav1.Now(), + PreserveExpiryTime: metav1.Time{}, + } + _, err := c.controlMachineClient.Machines(clone.Namespace).Update(ctx, clone, metav1.UpdateOptions{}) + if err != nil { + // Keep retrying until update goes through + klog.Errorf("Machine UPDATE failed for machine %q. Retrying, error: %s", machine.Name, err) + return machineutils.ShortRetry, err + } else { + klog.V(2).Infof("Machine %q updated to stop preservation ", machine.Name) + // Return error even when machine object is updated to ensure reconcilation is restarted + } + // if machine is in failed state transition to Terminating + if clone.Status.CurrentStatus.Phase == v1alpha1.MachineFailed { + err = c.controlMachineClient.Machines(c.namespace).Delete(ctx, machine.Name, metav1.DeleteOptions{}) + if err != nil { + klog.Errorf("Error trying to delete machine %q: %v", machine.Name, err) + return machineutils.ShortRetry, err + } + } + return machineutils.LongRetry, nil +} diff --git a/pkg/util/provider/machineutils/utils.go b/pkg/util/provider/machineutils/utils.go index 31ed3cf89..20ff53de2 100644 --- a/pkg/util/provider/machineutils/utils.go +++ b/pkg/util/provider/machineutils/utils.go @@ -82,6 +82,21 @@ const ( // LabelKeyMachineSetScaleUpDisabled is the label key that indicates scaling up of the machine set is disabled. LabelKeyMachineSetScaleUpDisabled = "node.machine.sapcloud.io/scale-up-disabled" + + // PreserveMachineAnnotationKey is the annotation used to explicitly request that a Machine be preserved + PreserveMachineAnnotationKey = "node.machine.sapcloud.io/preserve" + + // PreserveMachineAnnotationValueNow is the annotation value used to explicitly request that + // a Machine be preserved immediately in its current phase + PreserveMachineAnnotationValueNow = "now" + + // PreserveMachineAnnotationValueWhenFailed is the annotation value used to explicitly request that + // a Machine be preserved if and when in it enters Failed phase + PreserveMachineAnnotationValueWhenFailed = "when-failed" + + //PreserveMachineAnnotationValueFalse is the annotation value used to explicitly request that + // a Machine should not be preserved any longer, even if the expiry timeout has not been reached + PreserveMachineAnnotationValueFalse = "false" ) // RetryPeriod is an alias for specifying the retry period @@ -125,3 +140,11 @@ func IsMachineFailed(p *v1alpha1.Machine) bool { func IsMachineTriggeredForDeletion(m *v1alpha1.Machine) bool { return m.Annotations[MachinePriority] == "1" || m.Annotations[TriggerDeletionByMCM] == "true" } + +// IsMachinePreserved checks if machine is preserved by MCM +func IsMachinePreserved(m *v1alpha1.Machine) bool { + if !m.Status.CurrentStatus.PreserveExpiryTime.IsZero() { + return true + } + return false +} diff --git a/pkg/util/provider/options/types.go b/pkg/util/provider/options/types.go index d1be4c2c9..08ff30da7 100644 --- a/pkg/util/provider/options/types.go +++ b/pkg/util/provider/options/types.go @@ -97,6 +97,9 @@ type SafetyOptions struct { PvDetachTimeout metav1.Duration // Timeout (in duration) used while waiting for PV to reattach on new node PvReattachTimeout metav1.Duration + // Timeout (in duration) used while preserving a machine, + // beyond which preservation is stopped + MachinePreserveTimeout metav1.Duration // Timeout (in duration) for which the APIServer can be down before // declare the machine controller frozen by safety controller From b814d9314f931a22cfaf20c901eef9a7fd3f3a65 Mon Sep 17 00:00:00 2001 From: thiyyakat Date: Wed, 5 Nov 2025 10:38:38 +0530 Subject: [PATCH 02/43] Add MachinePreserveTimeout to SafetyOptions. --- pkg/util/provider/app/options/options.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/util/provider/app/options/options.go b/pkg/util/provider/app/options/options.go index 9e66b4b27..00e5ced7e 100644 --- a/pkg/util/provider/app/options/options.go +++ b/pkg/util/provider/app/options/options.go @@ -78,6 +78,7 @@ func NewMCServer() *MCServer { MachineSafetyOrphanVMsPeriod: metav1.Duration{Duration: 15 * time.Minute}, MachineSafetyAPIServerStatusCheckPeriod: metav1.Duration{Duration: 1 * time.Minute}, MachineSafetyAPIServerStatusCheckTimeout: metav1.Duration{Duration: 30 * time.Second}, + MachinePreserveTimeout: metav1.Duration{Duration: 3 * time.Hour}, }, }, } From f958786e54828636d5472eb9bd2bd66ae7713d46 Mon Sep 17 00:00:00 2001 From: thiyyakat Date: Wed, 5 Nov 2025 10:39:14 +0530 Subject: [PATCH 03/43] Add PreserveExpiryTime to `machine.Status.CurrentStatus`. --- pkg/apis/machine/types.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkg/apis/machine/types.go b/pkg/apis/machine/types.go index 4f6c6a8d5..03c09f9d9 100644 --- a/pkg/apis/machine/types.go +++ b/pkg/apis/machine/types.go @@ -161,6 +161,9 @@ type CurrentStatus struct { // Last update time of current status LastUpdateTime metav1.Time + + // PreserveExpiryTime is the time at which MCM will stop preserving the machine + PreserveExpiryTime metav1.Time } // MachineStatus holds the most recently observed status of Machine. From 86502b335b7a4678cecb472eab1354b2f77db12e Mon Sep 17 00:00:00 2001 From: thiyyakat Date: Wed, 5 Nov 2025 10:41:55 +0530 Subject: [PATCH 04/43] Remove `AutoPreserveFailedMachineCount` from machine set --- pkg/apis/machine/v1alpha1/machineset_types.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pkg/apis/machine/v1alpha1/machineset_types.go b/pkg/apis/machine/v1alpha1/machineset_types.go index b9ad20ec4..2e6eb1d6e 100644 --- a/pkg/apis/machine/v1alpha1/machineset_types.go +++ b/pkg/apis/machine/v1alpha1/machineset_types.go @@ -135,8 +135,4 @@ type MachineSetStatus struct { // FailedMachines has summary of machines on which lastOperation Failed // +optional FailedMachines *[]MachineSummary `json:"failedMachines,omitempty"` - - // AutoPreserveFailedMachineCount is the number of machines in the machine set that have been auto-preserved upon failure - // +optional - AutoPreserveFailedMachineCount int32 `json:"autoPreserveFailedMachineCount,omitempty"` } From b92cfb2253ba5104d2cd8358b5c8d897aab50b84 Mon Sep 17 00:00:00 2001 From: thiyyakat Date: Wed, 5 Nov 2025 10:42:31 +0530 Subject: [PATCH 05/43] Fix linting error --- pkg/util/provider/machineutils/utils.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/pkg/util/provider/machineutils/utils.go b/pkg/util/provider/machineutils/utils.go index 20ff53de2..ab6926dcf 100644 --- a/pkg/util/provider/machineutils/utils.go +++ b/pkg/util/provider/machineutils/utils.go @@ -143,8 +143,5 @@ func IsMachineTriggeredForDeletion(m *v1alpha1.Machine) bool { // IsMachinePreserved checks if machine is preserved by MCM func IsMachinePreserved(m *v1alpha1.Machine) bool { - if !m.Status.CurrentStatus.PreserveExpiryTime.IsZero() { - return true - } - return false + return !m.Status.CurrentStatus.PreserveExpiryTime.IsZero() } From 6dce99214ea3aace3036175aec7ebecb0f5bb223 Mon Sep 17 00:00:00 2001 From: thiyyakat Date: Wed, 5 Nov 2025 10:44:31 +0530 Subject: [PATCH 06/43] Add generated files --- docs/documents/apis.md | 39 +++++++++++++++++-- .../v1alpha1/zz_generated.conversion.go | 4 ++ .../machine/v1alpha1/zz_generated.deepcopy.go | 6 +++ pkg/apis/machine/zz_generated.deepcopy.go | 6 +++ pkg/openapi/api_violations.report | 1 + pkg/openapi/openapi_generated.go | 18 +++++++++ 6 files changed, 70 insertions(+), 4 deletions(-) diff --git a/docs/documents/apis.md b/docs/documents/apis.md index 1ed350d9e..a9be985cb 100644 --- a/docs/documents/apis.md +++ b/docs/documents/apis.md @@ -833,6 +833,21 @@ Kubernetes meta/v1.Time

Last update time of current status

+ + +preserveExpiryTime + + + + +Kubernetes meta/v1.Time + + + + +

PreserveExpiryTime is the time at which MCM will stop preserving the machine

+ +
@@ -1071,6 +1086,22 @@ Kubernetes meta/v1.Duration +preserveTimeout + + + + +Kubernetes meta/v1.Duration + + + + +(Optional) +

MachinePreserveTimeout is the timeout after the machine preservation is stopped

+ + + + disableHealthTimeout @@ -1543,8 +1574,8 @@ newest MachineSet.

- -[]*../../pkg/apis/machine/v1alpha1.MachineSummary + +[]*github.com/thiyyakat/machine-controller-manager/pkg/apis/machine/v1alpha1.MachineSummary @@ -1988,8 +2019,8 @@ LastOperation - -[]../../pkg/apis/machine/v1alpha1.MachineSummary + +[]github.com/thiyyakat/machine-controller-manager/pkg/apis/machine/v1alpha1.MachineSummary diff --git a/pkg/apis/machine/v1alpha1/zz_generated.conversion.go b/pkg/apis/machine/v1alpha1/zz_generated.conversion.go index 7d5d1b485..fcca5ee3f 100644 --- a/pkg/apis/machine/v1alpha1/zz_generated.conversion.go +++ b/pkg/apis/machine/v1alpha1/zz_generated.conversion.go @@ -348,6 +348,7 @@ func autoConvert_v1alpha1_CurrentStatus_To_machine_CurrentStatus(in *CurrentStat out.Phase = machine.MachinePhase(in.Phase) out.TimeoutActive = in.TimeoutActive out.LastUpdateTime = in.LastUpdateTime + out.PreserveExpiryTime = in.PreserveExpiryTime return nil } @@ -360,6 +361,7 @@ func autoConvert_machine_CurrentStatus_To_v1alpha1_CurrentStatus(in *machine.Cur out.Phase = MachinePhase(in.Phase) out.TimeoutActive = in.TimeoutActive out.LastUpdateTime = in.LastUpdateTime + out.PreserveExpiryTime = in.PreserveExpiryTime return nil } @@ -531,6 +533,7 @@ func autoConvert_v1alpha1_MachineConfiguration_To_machine_MachineConfiguration(i out.MachineHealthTimeout = (*metav1.Duration)(unsafe.Pointer(in.MachineHealthTimeout)) out.MachineCreationTimeout = (*metav1.Duration)(unsafe.Pointer(in.MachineCreationTimeout)) out.MachineInPlaceUpdateTimeout = (*metav1.Duration)(unsafe.Pointer(in.MachineInPlaceUpdateTimeout)) + out.MachinePreserveTimeout = (*metav1.Duration)(unsafe.Pointer(in.MachinePreserveTimeout)) out.DisableHealthTimeout = (*bool)(unsafe.Pointer(in.DisableHealthTimeout)) out.MaxEvictRetries = (*int32)(unsafe.Pointer(in.MaxEvictRetries)) out.NodeConditions = (*string)(unsafe.Pointer(in.NodeConditions)) @@ -547,6 +550,7 @@ func autoConvert_machine_MachineConfiguration_To_v1alpha1_MachineConfiguration(i out.MachineHealthTimeout = (*metav1.Duration)(unsafe.Pointer(in.MachineHealthTimeout)) out.MachineCreationTimeout = (*metav1.Duration)(unsafe.Pointer(in.MachineCreationTimeout)) out.MachineInPlaceUpdateTimeout = (*metav1.Duration)(unsafe.Pointer(in.MachineInPlaceUpdateTimeout)) + out.MachinePreserveTimeout = (*metav1.Duration)(unsafe.Pointer(in.MachinePreserveTimeout)) out.DisableHealthTimeout = (*bool)(unsafe.Pointer(in.DisableHealthTimeout)) out.MaxEvictRetries = (*int32)(unsafe.Pointer(in.MaxEvictRetries)) out.NodeConditions = (*string)(unsafe.Pointer(in.NodeConditions)) diff --git a/pkg/apis/machine/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/machine/v1alpha1/zz_generated.deepcopy.go index 2691557c9..13aab59e2 100644 --- a/pkg/apis/machine/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/machine/v1alpha1/zz_generated.deepcopy.go @@ -36,6 +36,7 @@ func (in *ClassSpec) DeepCopy() *ClassSpec { func (in *CurrentStatus) DeepCopyInto(out *CurrentStatus) { *out = *in in.LastUpdateTime.DeepCopyInto(&out.LastUpdateTime) + in.PreserveExpiryTime.DeepCopyInto(&out.PreserveExpiryTime) return } @@ -209,6 +210,11 @@ func (in *MachineConfiguration) DeepCopyInto(out *MachineConfiguration) { *out = new(metav1.Duration) **out = **in } + if in.MachinePreserveTimeout != nil { + in, out := &in.MachinePreserveTimeout, &out.MachinePreserveTimeout + *out = new(metav1.Duration) + **out = **in + } if in.DisableHealthTimeout != nil { in, out := &in.DisableHealthTimeout, &out.DisableHealthTimeout *out = new(bool) diff --git a/pkg/apis/machine/zz_generated.deepcopy.go b/pkg/apis/machine/zz_generated.deepcopy.go index 05c40b651..90aa57743 100644 --- a/pkg/apis/machine/zz_generated.deepcopy.go +++ b/pkg/apis/machine/zz_generated.deepcopy.go @@ -36,6 +36,7 @@ func (in *ClassSpec) DeepCopy() *ClassSpec { func (in *CurrentStatus) DeepCopyInto(out *CurrentStatus) { *out = *in in.LastUpdateTime.DeepCopyInto(&out.LastUpdateTime) + in.PreserveExpiryTime.DeepCopyInto(&out.PreserveExpiryTime) return } @@ -209,6 +210,11 @@ func (in *MachineConfiguration) DeepCopyInto(out *MachineConfiguration) { *out = new(metav1.Duration) **out = **in } + if in.MachinePreserveTimeout != nil { + in, out := &in.MachinePreserveTimeout, &out.MachinePreserveTimeout + *out = new(metav1.Duration) + **out = **in + } if in.DisableHealthTimeout != nil { in, out := &in.DisableHealthTimeout, &out.DisableHealthTimeout *out = new(bool) diff --git a/pkg/openapi/api_violations.report b/pkg/openapi/api_violations.report index 0861c8d4c..5cb955c9e 100644 --- a/pkg/openapi/api_violations.report +++ b/pkg/openapi/api_violations.report @@ -7,6 +7,7 @@ API rule violation: names_match,github.com/gardener/machine-controller-manager/p API rule violation: names_match,github.com/gardener/machine-controller-manager/pkg/apis/machine/v1alpha1,MachineConfiguration,MachineDrainTimeout API rule violation: names_match,github.com/gardener/machine-controller-manager/pkg/apis/machine/v1alpha1,MachineConfiguration,MachineHealthTimeout API rule violation: names_match,github.com/gardener/machine-controller-manager/pkg/apis/machine/v1alpha1,MachineConfiguration,MachineInPlaceUpdateTimeout +API rule violation: names_match,github.com/gardener/machine-controller-manager/pkg/apis/machine/v1alpha1,MachineConfiguration,MachinePreserveTimeout API rule violation: names_match,github.com/gardener/machine-controller-manager/pkg/apis/machine/v1alpha1,MachineSetStatus,Conditions API rule violation: names_match,github.com/gardener/machine-controller-manager/pkg/apis/machine/v1alpha1,MachineSpec,NodeTemplateSpec API rule violation: names_match,k8s.io/api/core/v1,AzureDiskVolumeSource,DataDiskURI diff --git a/pkg/openapi/openapi_generated.go b/pkg/openapi/openapi_generated.go index c4ee08c09..fe95775f3 100644 --- a/pkg/openapi/openapi_generated.go +++ b/pkg/openapi/openapi_generated.go @@ -394,6 +394,12 @@ func schema_pkg_apis_machine_v1alpha1_CurrentStatus(ref common.ReferenceCallback Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), }, }, + "preserveExpiryTime": { + SchemaProps: spec.SchemaProps{ + Description: "PreserveExpiryTime is the time at which MCM will stop preserving the machine", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), + }, + }, }, }, }, @@ -682,6 +688,12 @@ func schema_pkg_apis_machine_v1alpha1_MachineConfiguration(ref common.ReferenceC Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Duration"), }, }, + "preserveTimeout": { + SchemaProps: spec.SchemaProps{ + Description: "MachinePreserveTimeout is the timeout after the machine preservation is stopped", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Duration"), + }, + }, "disableHealthTimeout": { SchemaProps: spec.SchemaProps{ Description: "DisableHealthTimeout if set to true, health timeout will be ignored. Leading to machine never being declared failed. This is intended to be used only for in-place updates.", @@ -1462,6 +1474,12 @@ func schema_pkg_apis_machine_v1alpha1_MachineSpec(ref common.ReferenceCallback) Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Duration"), }, }, + "preserveTimeout": { + SchemaProps: spec.SchemaProps{ + Description: "MachinePreserveTimeout is the timeout after the machine preservation is stopped", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Duration"), + }, + }, "disableHealthTimeout": { SchemaProps: spec.SchemaProps{ Description: "DisableHealthTimeout if set to true, health timeout will be ignored. Leading to machine never being declared failed. This is intended to be used only for in-place updates.", From 1469138b90243a2f51e279f8e845825e8b21bfa6 Mon Sep 17 00:00:00 2001 From: thiyyakat Date: Wed, 5 Nov 2025 15:31:43 +0530 Subject: [PATCH 07/43] Add support for preserve=now on node and machine objects # Conflicts: # pkg/util/provider/machinecontroller/machine.go --- Makefile | 6 +- .../crds/machine.sapcloud.io_machinesets.yaml | 5 - .../provider/machinecontroller/machine.go | 28 ++-- .../machinecontroller/machine_util.go | 124 +++++++++++------- 4 files changed, 91 insertions(+), 72 deletions(-) diff --git a/Makefile b/Makefile index aba0236ac..6b0f4f913 100644 --- a/Makefile +++ b/Makefile @@ -172,9 +172,9 @@ test-clean: .PHONY: generate generate: $(VGOPATH) $(DEEPCOPY_GEN) $(DEFAULTER_GEN) $(CONVERSION_GEN) $(OPENAPI_GEN) $(CONTROLLER_GEN) $(GEN_CRD_API_REFERENCE_DOCS) - $(CONTROLLER_GEN) crd paths=./pkg/apis/machine/v1alpha1/... output:crd:dir=kubernetes/crds output:stdout - @./hack/generate-code - @./hack/api-reference/generate-spec-doc.sh + GOFLAGS="-buildvcs=false" $(CONTROLLER_GEN) crd paths=./pkg/apis/machine/v1alpha1/... output:crd:dir=kubernetes/crds output:stdout + @GOFLAGS="-buildvcs=false" ./hack/generate-code + @GOFLAGS="-buildvcs=false" ./hack/api-reference/generate-spec-doc.sh .PHONY: add-license-headers add-license-headers: $(GO_ADD_LICENSE) diff --git a/kubernetes/crds/machine.sapcloud.io_machinesets.yaml b/kubernetes/crds/machine.sapcloud.io_machinesets.yaml index 9a6f616fc..6dcc797c1 100644 --- a/kubernetes/crds/machine.sapcloud.io_machinesets.yaml +++ b/kubernetes/crds/machine.sapcloud.io_machinesets.yaml @@ -316,11 +316,6 @@ spec: description: MachineSetStatus holds the most recently observed status of MachineSet. properties: - autoPreserveFailedMachineCount: - description: AutoPreserveFailedMachineCount is the number of machines - in the machine set that have been auto-preserved upon failure - format: int32 - type: integer availableReplicas: description: The number of available replicas (ready for at least minReadySeconds) for this replica set. diff --git a/pkg/util/provider/machinecontroller/machine.go b/pkg/util/provider/machinecontroller/machine.go index 8df22e071..4fdbcf397 100644 --- a/pkg/util/provider/machinecontroller/machine.go +++ b/pkg/util/provider/machinecontroller/machine.go @@ -7,6 +7,7 @@ package controller import ( "context" + "errors" "fmt" "maps" "slices" @@ -16,6 +17,8 @@ import ( corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/selection" utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/client-go/tools/cache" @@ -58,9 +61,12 @@ func (c *controller) updateMachine(oldObj, newObj any) { klog.Errorf("couldn't convert to machine resource from object") return } + if preserveAnnotationsChanged(oldMachine.Annotations, newMachine.Annotations) { + c.enqueueMachine(newObj, "handling preserving machine object UPDATE event") + } if oldMachine.Generation == newMachine.Generation { - klog.V(3).Infof("Skipping non-spec updates for machine %s", oldMachine.Name) + klog.V(3).Infof("Skipping other non-spec updates for machine %s", oldMachine.Name) return } @@ -298,6 +304,11 @@ func (c *controller) reconcileClusterMachineTermination(key string) error { } return nil } +func preserveAnnotationsChanged(oldAnnotations, newAnnotations map[string]string) bool { + valueNew, existsInNew := newAnnotations[machineutils.PreserveMachineAnnotationKey] + valueOld, existsInOld := oldAnnotations[machineutils.PreserveMachineAnnotationKey] + return existsInOld != existsInNew || valueOld != valueNew +} /* SECTION @@ -732,26 +743,13 @@ func (c *controller) isCreationProcessing(machine *v1alpha1.Machine) bool { // Auto-preserve case will have to be handled where machine moved from Unknown to Failed func (c *controller) machinePreservation(ctx context.Context, machine *v1alpha1.Machine) (machineutils.RetryPeriod, error) { - // check if rolling update is ongoing, if yes, do nothing - machineDeployment, err := c.getMachineDeploymentForMachine(machine) - if err != nil { - klog.Errorf("Error getting machine deployment for machine %q: %s", machine.Name, err) - return machineutils.ShortRetry, err - } - for _, c := range machineDeployment.Status.Conditions { - if c.Type == v1alpha1.MachineDeploymentProgressing { - if c.Status == v1alpha1.ConditionTrue { - return machineutils.LongRetry, nil - } - break - } - } // check if machine needs to be preserved due to annotation isPreserved := machineutils.IsMachinePreserved(machine) value, exists := machine.Annotations[machineutils.PreserveMachineAnnotationKey] if !isPreserved && exists { switch value { case machineutils.PreserveMachineAnnotationValueNow: + klog.V(2).Infof("Machine %s has annotation %s", machine.Name, machineutils.PreserveMachineAnnotationKey) return c.preserveMachine(ctx, machine) case machineutils.PreserveMachineAnnotationValueWhenFailed: // check if machine is in Failed state diff --git a/pkg/util/provider/machinecontroller/machine_util.go b/pkg/util/provider/machinecontroller/machine_util.go index ef1a54a42..85aa08106 100644 --- a/pkg/util/provider/machinecontroller/machine_util.go +++ b/pkg/util/provider/machinecontroller/machine_util.go @@ -2058,6 +2058,17 @@ func (c *controller) getEffectiveInPlaceUpdateTimeout(machine *v1alpha1.Machine) return effectiveDependenciesUpdateTimeout } +// getEffectiveMachinePreserveTimeout returns the MachinePreserveTimeout set on the machine-object, otherwise returns the timeout set using the global-flag. +func (c *controller) getEffectiveMachinePreserveTimeout(machine *v1alpha1.Machine) *metav1.Duration { + var effectivePreserveTimeout *metav1.Duration + if machine.Spec.MachineConfiguration != nil && machine.Spec.MachineConfiguration.MachinePreserveTimeout != nil { + effectivePreserveTimeout = machine.Spec.MachineConfiguration.MachinePreserveTimeout + } else { + effectivePreserveTimeout = &c.safetyOptions.MachinePreserveTimeout + } + return effectivePreserveTimeout +} + // getEffectiveNodeConditions returns the nodeConditions set on the machine-object, otherwise returns the conditions set using the global-flag. func (c *controller) getEffectiveNodeConditions(machine *v1alpha1.Machine) *string { var effectiveNodeConditions *string @@ -2339,66 +2350,57 @@ func (c *controller) fetchMatchingNodeName(machineName string) (string, error) { func (c *controller) preserveMachine(ctx context.Context, machine *v1alpha1.Machine) (machineutils.RetryPeriod, error) { clone := machine.DeepCopy() - klog.V(2).Infof("Preserving machine %q", machine.Name) - clone.Status.LastOperation = v1alpha1.LastOperation{ - Description: "Preserving machine", - State: v1alpha1.MachineStateSuccessful, - Type: v1alpha1.MachineOperationPreserve, - LastUpdateTime: metav1.Now(), - } - clone.Status.CurrentStatus = v1alpha1.CurrentStatus{ - Phase: clone.Status.CurrentStatus.Phase, - LastUpdateTime: metav1.Now(), - PreserveExpiryTime: metav1.NewTime(metav1.Now().Add(c.getEffectiveMachinePreserveTimeout(machine).Duration)), - } + //klog.V(2).Infof("Preserving machine %q", machine.Name) // if backing node exists, add annotations to prevent scale down by autoscaler if machine.Labels[v1alpha1.NodeLabelKey] != "" { - clusterAutoscalerScaleDownAnnotations := make(map[string]string) - clusterAutoscalerScaleDownAnnotations[autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationKey] = autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationValue + preservationAnnotations := make(map[string]string) + // if preserve annotation not updated on node, we add it + preservationAnnotations[machineutils.PreserveMachineAnnotationKey] = machine.Annotations[machineutils.PreserveMachineAnnotationKey] + preservationAnnotations[autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationKey] = autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationValue // We do this to avoid accidentally deleting the user provided annotations. - clusterAutoscalerScaleDownAnnotations[autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationByMCMKey] = autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationByMCMValue + preservationAnnotations[autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationByMCMKey] = autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationByMCMValue nodeName := machine.Labels[v1alpha1.NodeLabelKey] node, err := c.nodeLister.Get(nodeName) if err != nil { - klog.Errorf("Error trying to get node %q: %v", nodeName, err) + klog.Errorf("error trying to get node %q: %v", nodeName, err) return machineutils.ShortRetry, err } - updatedNode, _, err := annotations.AddOrUpdateAnnotation(node, clusterAutoscalerScaleDownAnnotations) - if err != nil { - klog.Warningf("Adding annotation failed for node: %s, %s", machine.Labels[v1alpha1.NodeLabelKey], err) - } + // function never returns error, can be ignored + updatedNode, _, _ := annotations.AddOrUpdateAnnotation(node, preservationAnnotations) _, err = c.targetCoreClient.CoreV1().Nodes().Update(ctx, updatedNode, metav1.UpdateOptions{}) if err != nil { - klog.Errorf("Error trying to update node %q: %v", nodeName, err) + if apierrors.IsConflict(err) { + return machineutils.ConflictRetry, err + } + klog.Errorf("node UPDATE failed for machine %s with node %s. Retrying, error: %s", machine.Name, nodeName, err) return machineutils.ShortRetry, err } + klog.V(2).Infof("Updated node %s for machine %q successfully", node.Name, machine.Name) + } + clone.Status.CurrentStatus = v1alpha1.CurrentStatus{ + Phase: clone.Status.CurrentStatus.Phase, + LastUpdateTime: metav1.Now(), + PreserveExpiryTime: metav1.NewTime(metav1.Now().Add(c.getEffectiveMachinePreserveTimeout(machine).Duration)), } _, err := c.controlMachineClient.Machines(clone.Namespace).UpdateStatus(ctx, clone, metav1.UpdateOptions{}) if err != nil { - // Keep retrying until update goes through - klog.Errorf("Machine/status UPDATE failed for machine %q. Retrying, error: %s", machine.Name, err) - } else { - klog.V(2).Infof("Machine %q status updated to preserved ", machine.Name) - // Return error even when machine object is updated to ensure reconcilation is restarted - err = fmt.Errorf("machine preservation in process") - } - if apierrors.IsConflict(err) { - return machineutils.ConflictRetry, err + klog.Errorf("machine status UPDATE failed for machine %q. Retrying, error: %s", machine.Name, err) + if apierrors.IsConflict(err) { + return machineutils.ConflictRetry, err + } + return machineutils.ShortRetry, err } - return machineutils.ShortRetry, err + klog.V(2).Infof("Machine %q preserved.", machine.Name) + return machineutils.LongRetry, nil } func (c *controller) stopMachinePreservation(ctx context.Context, machine *v1alpha1.Machine) (machineutils.RetryPeriod, error) { - clone := machine.DeepCopy() - delete(clone.Annotations, autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationKey) - delete(clone.Annotations, autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationByMCMKey) - delete(clone.Annotations, machineutils.PreserveMachineAnnotationKey) // if backing node exists, remove annotations that would prevent scale down by autoscaler if machine.Labels[v1alpha1.NodeLabelKey] != "" { nodeName := machine.Labels[v1alpha1.NodeLabelKey] node, err := c.nodeLister.Get(nodeName) if err != nil { - klog.Errorf("Error trying to get node %q: %v", nodeName, err) + klog.Errorf("error trying to get node %q: %v", nodeName, err) return machineutils.ShortRetry, err } //remove annotations from node, values do not matter here @@ -2408,35 +2410,59 @@ func (c *controller) stopMachinePreservation(ctx context.Context, machine *v1alp preservationAnnotations[machineutils.PreserveMachineAnnotationKey] = "" updatedNode, _, err := annotations.RemoveAnnotation(node, preservationAnnotations) if err != nil { - klog.Warningf("Removing annotation failed for node: %s, %s", machine.Labels[v1alpha1.NodeLabelKey], err) + klog.Errorf("removing annotation failed for node: %s, %s", machine.Labels[v1alpha1.NodeLabelKey], err) + return machineutils.ShortRetry, err } _, err = c.targetCoreClient.CoreV1().Nodes().Update(ctx, updatedNode, metav1.UpdateOptions{}) if err != nil { - klog.Errorf("Error trying to update node %q: %v", nodeName, err) + klog.Errorf("error trying to update node %q: %v", nodeName, err) + if apierrors.IsConflict(err) { + return machineutils.ConflictRetry, err + } return machineutils.ShortRetry, err } } - clone.Status.CurrentStatus = v1alpha1.CurrentStatus{ - Phase: clone.Status.CurrentStatus.Phase, + clone := machine.DeepCopy() + delete(clone.Annotations, autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationKey) + delete(clone.Annotations, autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationByMCMKey) + delete(clone.Annotations, machineutils.PreserveMachineAnnotationKey) + updatedMachine, err := c.controlMachineClient.Machines(clone.Namespace).Update(ctx, clone, metav1.UpdateOptions{}) + if err != nil { + klog.Errorf("machine UPDATE failed for machine %q. Retrying, error: %s", machine.Name, err) + if apierrors.IsConflict(err) { + return machineutils.ConflictRetry, err + } + return machineutils.ShortRetry, err + } else { + klog.V(2).Infof("Machine %q updated to remove annotations ", machine.Name) + // Return error even when machine object is updated to ensure reconcilation is restarted + } + updatedMachine.Status.CurrentStatus = v1alpha1.CurrentStatus{ + Phase: updatedMachine.Status.CurrentStatus.Phase, LastUpdateTime: metav1.Now(), PreserveExpiryTime: metav1.Time{}, } - _, err := c.controlMachineClient.Machines(clone.Namespace).Update(ctx, clone, metav1.UpdateOptions{}) + _, err = c.controlMachineClient.Machines(updatedMachine.Namespace).UpdateStatus(ctx, updatedMachine, metav1.UpdateOptions{}) if err != nil { - // Keep retrying until update goes through - klog.Errorf("Machine UPDATE failed for machine %q. Retrying, error: %s", machine.Name, err) + klog.Errorf("Machine/status UPDATE failed for machine %q. Retrying, error: %s", updatedMachine.Name, err) + if apierrors.IsConflict(err) { + return machineutils.ConflictRetry, err + } return machineutils.ShortRetry, err - } else { - klog.V(2).Infof("Machine %q updated to stop preservation ", machine.Name) - // Return error even when machine object is updated to ensure reconcilation is restarted } + klog.V(2).Infof("Machine %q status updated to stop preservation ", updatedMachine.Name) + // if machine is in failed state transition to Terminating - if clone.Status.CurrentStatus.Phase == v1alpha1.MachineFailed { - err = c.controlMachineClient.Machines(c.namespace).Delete(ctx, machine.Name, metav1.DeleteOptions{}) + if updatedMachine.Status.CurrentStatus.Phase == v1alpha1.MachineFailed { + err = c.controlMachineClient.Machines(c.namespace).Delete(ctx, updatedMachine.Name, metav1.DeleteOptions{}) if err != nil { - klog.Errorf("Error trying to delete machine %q: %v", machine.Name, err) + klog.Errorf("error trying to delete machine %q: %v", updatedMachine.Name, err) + if apierrors.IsConflict(err) { + return machineutils.ConflictRetry, err + } return machineutils.ShortRetry, err } + klog.V(2).Infof("Machine %q marked for deletion", updatedMachine.Name) } return machineutils.LongRetry, nil } From 2bbb7e7466e5336adaa36ba92601827703f7f1ce Mon Sep 17 00:00:00 2001 From: thiyyakat Date: Wed, 5 Nov 2025 15:35:59 +0530 Subject: [PATCH 08/43] Update TODOs --- .../provider/machinecontroller/machine_util.go | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/pkg/util/provider/machinecontroller/machine_util.go b/pkg/util/provider/machinecontroller/machine_util.go index 85aa08106..3f55e2f55 100644 --- a/pkg/util/provider/machinecontroller/machine_util.go +++ b/pkg/util/provider/machinecontroller/machine_util.go @@ -2348,6 +2348,8 @@ func (c *controller) fetchMatchingNodeName(machineName string) (string, error) { return "", fmt.Errorf("machine %q not found in node lister for machine %q", machineName, machineName) } +// TODO:@thiyyakat - when-failed annotation should be added to the node as well. +// preserveMachine contains logic to start the preservation of a node func (c *controller) preserveMachine(ctx context.Context, machine *v1alpha1.Machine) (machineutils.RetryPeriod, error) { clone := machine.DeepCopy() //klog.V(2).Infof("Preserving machine %q", machine.Name) @@ -2357,8 +2359,9 @@ func (c *controller) preserveMachine(ctx context.Context, machine *v1alpha1.Mach // if preserve annotation not updated on node, we add it preservationAnnotations[machineutils.PreserveMachineAnnotationKey] = machine.Annotations[machineutils.PreserveMachineAnnotationKey] preservationAnnotations[autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationKey] = autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationValue - // We do this to avoid accidentally deleting the user provided annotations. - preservationAnnotations[autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationByMCMKey] = autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationByMCMValue + // TODO@thiyyakat: understand why ClusterAutoscalerScaleDownDisabledAnnotationByMCMKey is added + //// We do this to avoid accidentally deleting the user provided annotations. + //preservationAnnotations[autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationByMCMKey] = autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationByMCMValue nodeName := machine.Labels[v1alpha1.NodeLabelKey] node, err := c.nodeLister.Get(nodeName) if err != nil { @@ -2406,7 +2409,8 @@ func (c *controller) stopMachinePreservation(ctx context.Context, machine *v1alp //remove annotations from node, values do not matter here preservationAnnotations := make(map[string]string) preservationAnnotations[autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationKey] = "" - preservationAnnotations[autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationByMCMKey] = "" + // TODO@thiyyakat: understand why ClusterAutoscalerScaleDownDisabledAnnotationByMCMKey is added + //preservationAnnotations[autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationByMCMKey] = "" preservationAnnotations[machineutils.PreserveMachineAnnotationKey] = "" updatedNode, _, err := annotations.RemoveAnnotation(node, preservationAnnotations) if err != nil { @@ -2424,7 +2428,8 @@ func (c *controller) stopMachinePreservation(ctx context.Context, machine *v1alp } clone := machine.DeepCopy() delete(clone.Annotations, autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationKey) - delete(clone.Annotations, autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationByMCMKey) + // TODO@thiyyakat: understand why ClusterAutoscalerScaleDownDisabledAnnotationByMCMKey is added + //delete(clone.Annotations, autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationByMCMKey) delete(clone.Annotations, machineutils.PreserveMachineAnnotationKey) updatedMachine, err := c.controlMachineClient.Machines(clone.Namespace).Update(ctx, clone, metav1.UpdateOptions{}) if err != nil { @@ -2451,7 +2456,6 @@ func (c *controller) stopMachinePreservation(ctx context.Context, machine *v1alp return machineutils.ShortRetry, err } klog.V(2).Infof("Machine %q status updated to stop preservation ", updatedMachine.Name) - // if machine is in failed state transition to Terminating if updatedMachine.Status.CurrentStatus.Phase == v1alpha1.MachineFailed { err = c.controlMachineClient.Machines(c.namespace).Delete(ctx, updatedMachine.Name, metav1.DeleteOptions{}) From 59edd3bd9ed5fd00e5f43937c34a45a0d9aba521 Mon Sep 17 00:00:00 2001 From: thiyyakat Date: Mon, 10 Nov 2025 13:46:47 +0530 Subject: [PATCH 09/43] [WIP] Implement add/remove/update of node and machine annotations --- pkg/controller/machineset.go | 37 +++++- .../provider/machinecontroller/machine.go | 46 ++++---- .../machinecontroller/machine_util.go | 108 +++++++++++------- 3 files changed, 126 insertions(+), 65 deletions(-) diff --git a/pkg/controller/machineset.go b/pkg/controller/machineset.go index b445efef3..e404e52b6 100644 --- a/pkg/controller/machineset.go +++ b/pkg/controller/machineset.go @@ -27,6 +27,7 @@ import ( "errors" "fmt" "reflect" + "slices" "sort" "sync" "time" @@ -460,6 +461,18 @@ func (c *controller) manageReplicas(ctx context.Context, allMachines []*v1alpha1 logMachinesWithPriority1(activeMachines) machinesToDelete := getMachinesToDelete(activeMachines, diff) logMachinesToDelete(machinesToDelete) + //if machines are preserved, stop preservation + //for _, mc := range machinesToDelete { + // if machineutils.IsMachinePreserved(mc) { + // + // } + // + //}for _, mc := range machinesToDelete { + // if machineutils.IsMachinePreserved(mc) { + // + // } + // + //} // Snapshot the UIDs (ns/name) of the machines we're expecting to see // deleted, so we know to record their expectations exactly once either @@ -681,14 +694,34 @@ func getMachinesToDelete(filteredMachines []*v1alpha1.Machine, diff int) []*v1al // < scheduled, and pending < running. This ensures that we delete machines // in the earlier stages whenever possible. sort.Sort(ActiveMachines(filteredMachines)) + // machines in Preserved stage will be the last ones to be deleted + // at all times, replica count will be upheld, even if it means deletion of a pending machine + // TODO@thiyyakat: write unit test for this scenario + filteredMachines = prioritisePreservedMachines(filteredMachines) + + fmt.Printf("len(filteredMachines)=%d, diff=%d\n", len(filteredMachines), diff) + } return filteredMachines[:diff] } +func prioritisePreservedMachines(machines []*v1alpha1.Machine) []*v1alpha1.Machine { + pendingMachines := make([]*v1alpha1.Machine, 0, len(machines)) + otherMachines := make([]*v1alpha1.Machine, 0, len(machines)) + for _, mc := range machines { + if machineutils.IsMachinePreserved(mc) { + pendingMachines = append(pendingMachines, mc) + } else { + otherMachines = append(otherMachines, mc) + } + } + return slices.Concat(otherMachines, pendingMachines) +} + func getMachineKeys(machines []*v1alpha1.Machine) []string { machineKeys := make([]string, 0, len(machines)) - for _, machine := range machines { - machineKeys = append(machineKeys, MachineKey(machine)) + for _, mc := range machines { + machineKeys = append(machineKeys, MachineKey(mc)) } return machineKeys } diff --git a/pkg/util/provider/machinecontroller/machine.go b/pkg/util/provider/machinecontroller/machine.go index 4fdbcf397..6cc324a07 100644 --- a/pkg/util/provider/machinecontroller/machine.go +++ b/pkg/util/provider/machinecontroller/machine.go @@ -62,7 +62,8 @@ func (c *controller) updateMachine(oldObj, newObj any) { return } if preserveAnnotationsChanged(oldMachine.Annotations, newMachine.Annotations) { - c.enqueueMachine(newObj, "handling preserving machine object UPDATE event") + c.enqueueMachine(newObj, "handling machine object preservation related UPDATE event") + return } if oldMachine.Generation == newMachine.Generation { @@ -733,34 +734,39 @@ func (c *controller) isCreationProcessing(machine *v1alpha1.Machine) bool { // TODO@thiyyakat: check case where, preserved and annotated but times out. Not handled currently // possible cases: // 1. Annotated -// - already preserved, check for timeout -// - already preserved, check for explicit stop preservation -// - needs to be preserved on failure -// - needs to be preserved now +// - already preserved, check for timeout +// - already preserved, check for explicit stop preservation +// - needs to be preserved on failure +// - needs to be preserved now +// // 2. Unannotated -// - failed machine, autoPreserveMax not breached, must be preserved -// - failed machine, already preserved, check for timeout +// - failed machine, autoPreserveMax not breached, must be preserved +// - failed machine, already preserved, check for timeout +// // Auto-preserve case will have to be handled where machine moved from Unknown to Failed func (c *controller) machinePreservation(ctx context.Context, machine *v1alpha1.Machine) (machineutils.RetryPeriod, error) { // check if machine needs to be preserved due to annotation - isPreserved := machineutils.IsMachinePreserved(machine) value, exists := machine.Annotations[machineutils.PreserveMachineAnnotationKey] - if !isPreserved && exists { + klog.V(3).Infof("TEST: machine:%s annotation value: %s", machine.Name, value) + isPreserved := machineutils.IsMachinePreserved(machine) + if exists { switch value { - case machineutils.PreserveMachineAnnotationValueNow: - klog.V(2).Infof("Machine %s has annotation %s", machine.Name, machineutils.PreserveMachineAnnotationKey) - return c.preserveMachine(ctx, machine) - case machineutils.PreserveMachineAnnotationValueWhenFailed: - // check if machine is in Failed state - if machineutils.IsMachineFailed(machine) { - return c.preserveMachine(ctx, machine) + case machineutils.PreserveMachineAnnotationValueNow, machineutils.PreserveMachineAnnotationValueWhenFailed: + if !isPreserved { + return c.preserveMachine(ctx, machine, value) } + case machineutils.PreserveMachineAnnotationValueFalse: + klog.V(2).Infof("TEST: false annotation value set.") + if isPreserved { + return c.stopMachinePreservation(ctx, machine) + } + default: + klog.V(3).Infof("Annotation value %s not part of accepted values for preserve", value) + return machineutils.LongRetry, nil } - } else if isPreserved { - if value == machineutils.PreserveMachineAnnotationValueFalse || metav1.Now().After(machine.Status.CurrentStatus.PreserveExpiryTime.Time) { - return c.stopMachinePreservation(ctx, machine) - } + } else if isPreserved && metav1.Now().After(machine.Status.CurrentStatus.PreserveExpiryTime.Time) { + return c.stopMachinePreservation(ctx, machine) } // if the machine is neither preserved nor annotated, need not handle it here. Auto-preservation // handled on failure diff --git a/pkg/util/provider/machinecontroller/machine_util.go b/pkg/util/provider/machinecontroller/machine_util.go index 3f55e2f55..6b269c8e2 100644 --- a/pkg/util/provider/machinecontroller/machine_util.go +++ b/pkg/util/provider/machinecontroller/machine_util.go @@ -1096,11 +1096,18 @@ func (c *controller) reconcileMachineHealth(ctx context.Context, machine *v1alph timeOutDuration, machine.Status.Conditions, ) - machineDeployName := getMachineDeploymentName(machine) // creating lock for machineDeployment, if not allocated c.permitGiver.RegisterPermits(machineDeployName, 1) - return c.tryMarkingMachineFailed(ctx, machine, clone, machineDeployName, description, lockAcquireTimeout) + retry, err := c.tryMarkingMachineFailed(ctx, machine, clone, machineDeployName, description, lockAcquireTimeout) + if err != nil { + return retry, err + } + if value, exists := machine.Annotations[machineutils.PreserveMachineAnnotationKey]; exists && value == machineutils.PreserveMachineAnnotationValueWhenFailed { + klog.V(3).Infof("TEST:Preserving machine on failure due to annotation") + return c.preserveMachine(ctx, machine, machineutils.PreserveMachineAnnotationValueWhenFailed) + } + return retry, err } if isMachineInPlaceUpdating { @@ -1154,7 +1161,7 @@ func (c *controller) reconcileMachineHealth(ctx context.Context, machine *v1alph } if cloneDirty { - _, err = c.controlMachineClient.Machines(clone.Namespace).UpdateStatus(ctx, clone, metav1.UpdateOptions{}) + updatedMachine, err := c.controlMachineClient.Machines(clone.Namespace).UpdateStatus(ctx, clone, metav1.UpdateOptions{}) if err != nil { // Keep retrying across reconciles until update goes through klog.Errorf("Update of Phase/Conditions failed for machine %q. Retrying, error: %q", machine.Name, err) @@ -1163,6 +1170,10 @@ func (c *controller) reconcileMachineHealth(ctx context.Context, machine *v1alph } } else { klog.V(2).Infof("Machine Phase/Conditions have been updated for %q with providerID %q and are in sync with backing node %q", machine.Name, getProviderID(machine), getNodeName(machine)) + if updatedMachine.Status.CurrentStatus.Phase == v1alpha1.MachineFailed && updatedMachine.Annotations[machineutils.PreserveMachineAnnotationKey] == machineutils.PreserveMachineAnnotationValueWhenFailed { + klog.V(3).Infof("TEST:Preserving machine on failure due to annotation") + return c.preserveMachine(ctx, updatedMachine, machineutils.PreserveMachineAnnotationValueWhenFailed) + } // Return error to end the reconcile err = errSuccessfulPhaseUpdate } @@ -2348,26 +2359,30 @@ func (c *controller) fetchMatchingNodeName(machineName string) (string, error) { return "", fmt.Errorf("machine %q not found in node lister for machine %q", machineName, machineName) } -// TODO:@thiyyakat - when-failed annotation should be added to the node as well. -// preserveMachine contains logic to start the preservation of a node -func (c *controller) preserveMachine(ctx context.Context, machine *v1alpha1.Machine) (machineutils.RetryPeriod, error) { - clone := machine.DeepCopy() - //klog.V(2).Infof("Preserving machine %q", machine.Name) - // if backing node exists, add annotations to prevent scale down by autoscaler +// TODO@thiyyakat: check if node needs to be updated at all. +// TODO@thiyyakat: handle when annotation changed from when-failed to now and vice versa +// preserveMachine contains logic to start the preservation of a machine and node +func (c *controller) preserveMachine(ctx context.Context, machine *v1alpha1.Machine, preserveValue string) (machineutils.RetryPeriod, error) { + klog.V(3).Infof("TEST:Entering preserve machine flow") + isFailed := machineutils.IsMachineFailed(machine) + // machine needs to be preserved now if annotated with preserve=now or if annotated with preserve=when-failed and machine has failed + toBePreservedNow := preserveValue == machineutils.PreserveMachineAnnotationValueNow || preserveValue == machineutils.PreserveMachineAnnotationValueWhenFailed && isFailed + klog.V(3).Infof("TEST:machine: %s, tobepreservednow: %s", machine.Name, toBePreservedNow) + // TODO@thiyyakat: may need to change this check to machine.Spec.ProviderID if machine.Labels[v1alpha1.NodeLabelKey] != "" { preservationAnnotations := make(map[string]string) - // if preserve annotation not updated on node, we add it preservationAnnotations[machineutils.PreserveMachineAnnotationKey] = machine.Annotations[machineutils.PreserveMachineAnnotationKey] - preservationAnnotations[autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationKey] = autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationValue - // TODO@thiyyakat: understand why ClusterAutoscalerScaleDownDisabledAnnotationByMCMKey is added - //// We do this to avoid accidentally deleting the user provided annotations. - //preservationAnnotations[autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationByMCMKey] = autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationByMCMValue + if toBePreservedNow { + preservationAnnotations[autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationKey] = autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationValue + } nodeName := machine.Labels[v1alpha1.NodeLabelKey] node, err := c.nodeLister.Get(nodeName) if err != nil { klog.Errorf("error trying to get node %q: %v", nodeName, err) return machineutils.ShortRetry, err } + klog.V(3).Infof("TEST:preservationAnnotations on node : %s: %v, and machine: %s", node.Name, node.Annotations[machineutils.PreserveMachineAnnotationKey], machine.Annotations[machineutils.PreserveMachineAnnotationKey]) + // if preserve annotation not updated on node, we add it // function never returns error, can be ignored updatedNode, _, _ := annotations.AddOrUpdateAnnotation(node, preservationAnnotations) _, err = c.targetCoreClient.CoreV1().Nodes().Update(ctx, updatedNode, metav1.UpdateOptions{}) @@ -2378,8 +2393,12 @@ func (c *controller) preserveMachine(ctx context.Context, machine *v1alpha1.Mach klog.Errorf("node UPDATE failed for machine %s with node %s. Retrying, error: %s", machine.Name, nodeName, err) return machineutils.ShortRetry, err } - klog.V(2).Infof("Updated node %s for machine %q successfully", node.Name, machine.Name) + klog.V(2).Infof("Updated preservation annotations for node %s, for machine %q, successfully", node.Name, machine.Name) + if !toBePreservedNow { + return machineutils.LongRetry, nil + } } + clone := machine.DeepCopy() clone.Status.CurrentStatus = v1alpha1.CurrentStatus{ Phase: clone.Status.CurrentStatus.Phase, LastUpdateTime: metav1.Now(), @@ -2398,7 +2417,9 @@ func (c *controller) preserveMachine(ctx context.Context, machine *v1alpha1.Mach } func (c *controller) stopMachinePreservation(ctx context.Context, machine *v1alpha1.Machine) (machineutils.RetryPeriod, error) { + klog.V(3).Infof("TEST:Entering stopMachinePreservation on machine %q", machine.Name) // if backing node exists, remove annotations that would prevent scale down by autoscaler + // TODO@thiyyakat: may need to change this check to machine.Spec.ProviderID if machine.Labels[v1alpha1.NodeLabelKey] != "" { nodeName := machine.Labels[v1alpha1.NodeLabelKey] node, err := c.nodeLister.Get(nodeName) @@ -2406,16 +2427,15 @@ func (c *controller) stopMachinePreservation(ctx context.Context, machine *v1alp klog.Errorf("error trying to get node %q: %v", nodeName, err) return machineutils.ShortRetry, err } - //remove annotations from node, values do not matter here - preservationAnnotations := make(map[string]string) - preservationAnnotations[autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationKey] = "" - // TODO@thiyyakat: understand why ClusterAutoscalerScaleDownDisabledAnnotationByMCMKey is added - //preservationAnnotations[autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationByMCMKey] = "" - preservationAnnotations[machineutils.PreserveMachineAnnotationKey] = "" - updatedNode, _, err := annotations.RemoveAnnotation(node, preservationAnnotations) - if err != nil { - klog.Errorf("removing annotation failed for node: %s, %s", machine.Labels[v1alpha1.NodeLabelKey], err) - return machineutils.ShortRetry, err + // remove CA annotation from node, values do not matter here + CAAnnotations := make(map[string]string) + CAAnnotations[autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationKey] = "" + updatedNode, _, _ := annotations.RemoveAnnotation(node, CAAnnotations) // error can be ignored, always returns nil + // set preserve=false on node if it is set on machine + if machine.Annotations[machineutils.PreserveMachineAnnotationKey] == machineutils.PreserveMachineAnnotationValueFalse { + preserveAnnotations := make(map[string]string) + preserveAnnotations[machineutils.PreserveMachineAnnotationKey] = machineutils.PreserveMachineAnnotationValueFalse + updatedNode, _, _ = annotations.AddOrUpdateAnnotation(updatedNode, preserveAnnotations) // error can be ignored, always returns nil } _, err = c.targetCoreClient.CoreV1().Nodes().Update(ctx, updatedNode, metav1.UpdateOptions{}) if err != nil { @@ -2442,31 +2462,33 @@ func (c *controller) stopMachinePreservation(ctx context.Context, machine *v1alp klog.V(2).Infof("Machine %q updated to remove annotations ", machine.Name) // Return error even when machine object is updated to ensure reconcilation is restarted } - updatedMachine.Status.CurrentStatus = v1alpha1.CurrentStatus{ - Phase: updatedMachine.Status.CurrentStatus.Phase, - LastUpdateTime: metav1.Now(), - PreserveExpiryTime: metav1.Time{}, - } - _, err = c.controlMachineClient.Machines(updatedMachine.Namespace).UpdateStatus(ctx, updatedMachine, metav1.UpdateOptions{}) - if err != nil { - klog.Errorf("Machine/status UPDATE failed for machine %q. Retrying, error: %s", updatedMachine.Name, err) - if apierrors.IsConflict(err) { - return machineutils.ConflictRetry, err + if machineutils.IsMachinePreserved(machine) { + updatedMachine.Status.CurrentStatus = v1alpha1.CurrentStatus{ + Phase: updatedMachine.Status.CurrentStatus.Phase, + LastUpdateTime: metav1.Now(), + PreserveExpiryTime: metav1.Time{}, } - return machineutils.ShortRetry, err - } - klog.V(2).Infof("Machine %q status updated to stop preservation ", updatedMachine.Name) - // if machine is in failed state transition to Terminating - if updatedMachine.Status.CurrentStatus.Phase == v1alpha1.MachineFailed { - err = c.controlMachineClient.Machines(c.namespace).Delete(ctx, updatedMachine.Name, metav1.DeleteOptions{}) + _, err = c.controlMachineClient.Machines(updatedMachine.Namespace).UpdateStatus(ctx, updatedMachine, metav1.UpdateOptions{}) if err != nil { - klog.Errorf("error trying to delete machine %q: %v", updatedMachine.Name, err) + klog.Errorf("Machine/status UPDATE failed for machine %q. Retrying, error: %s", updatedMachine.Name, err) if apierrors.IsConflict(err) { return machineutils.ConflictRetry, err } return machineutils.ShortRetry, err } - klog.V(2).Infof("Machine %q marked for deletion", updatedMachine.Name) + klog.V(2).Infof("Machine %q status updated to stop preservation ", updatedMachine.Name) + // if machine is in failed state transition to Terminating + if updatedMachine.Status.CurrentStatus.Phase == v1alpha1.MachineFailed { + err = c.controlMachineClient.Machines(c.namespace).Delete(ctx, updatedMachine.Name, metav1.DeleteOptions{}) + if err != nil { + klog.Errorf("error trying to delete machine %q: %v", updatedMachine.Name, err) + if apierrors.IsConflict(err) { + return machineutils.ConflictRetry, err + } + return machineutils.ShortRetry, err + } + klog.V(2).Infof("Machine %q marked for deletion", updatedMachine.Name) + } } return machineutils.LongRetry, nil } From 7792fa346443c21d15f2d73e249339d119033387 Mon Sep 17 00:00:00 2001 From: thiyyakat Date: Thu, 13 Nov 2025 14:41:32 +0530 Subject: [PATCH 10/43] Update preserve logic to honour node annotations over machine --- .../provider/machinecontroller/machine.go | 89 ++++++++++++++----- .../machinecontroller/machine_util.go | 12 +-- 2 files changed, 74 insertions(+), 27 deletions(-) diff --git a/pkg/util/provider/machinecontroller/machine.go b/pkg/util/provider/machinecontroller/machine.go index 6cc324a07..17a4b65b3 100644 --- a/pkg/util/provider/machinecontroller/machine.go +++ b/pkg/util/provider/machinecontroller/machine.go @@ -746,33 +746,78 @@ func (c *controller) isCreationProcessing(machine *v1alpha1.Machine) bool { // Auto-preserve case will have to be handled where machine moved from Unknown to Failed func (c *controller) machinePreservation(ctx context.Context, machine *v1alpha1.Machine) (machineutils.RetryPeriod, error) { - // check if machine needs to be preserved due to annotation - value, exists := machine.Annotations[machineutils.PreserveMachineAnnotationKey] - klog.V(3).Infof("TEST: machine:%s annotation value: %s", machine.Name, value) - isPreserved := machineutils.IsMachinePreserved(machine) - if exists { - switch value { - case machineutils.PreserveMachineAnnotationValueNow, machineutils.PreserveMachineAnnotationValueWhenFailed: - if !isPreserved { - return c.preserveMachine(ctx, machine, value) - } - case machineutils.PreserveMachineAnnotationValueFalse: - klog.V(2).Infof("TEST: false annotation value set.") - if isPreserved { - return c.stopMachinePreservation(ctx, machine) - } - default: - klog.V(3).Infof("Annotation value %s not part of accepted values for preserve", value) - return machineutils.LongRetry, nil + // check effective preservation value based on node's and machine's annotations. + updatedMachine, preserveValue, err := c.syncEffectivePreserveAnnotationValue(ctx, machine) + if err != nil { + klog.Errorf("Error getting preserve annotation value for machine %q: %s", machine.Name, err) + return machineutils.ShortRetry, err + } + klog.V(3).Infof("TEST effective preservation value for machine %q: %s", updatedMachine.Name, preserveValue) + isPreserved := machineutils.IsMachinePreserved(updatedMachine) + switch preserveValue { + case machineutils.PreserveMachineAnnotationValueNow, machineutils.PreserveMachineAnnotationValueWhenFailed: + if !isPreserved { + return c.preserveMachine(ctx, machine, preserveValue) + } else if metav1.Now().After(machine.Status.CurrentStatus.PreserveExpiryTime.Time) { + return c.stopMachinePreservation(ctx, machine) } - } else if isPreserved && metav1.Now().After(machine.Status.CurrentStatus.PreserveExpiryTime.Time) { - return c.stopMachinePreservation(ctx, machine) + case machineutils.PreserveMachineAnnotationValueFalse: + if isPreserved { + return c.stopMachinePreservation(ctx, machine) + } + case "": + return machineutils.LongRetry, nil + default: + klog.V(3).Infof("Annotation value %s not part of accepted values for preserve", preserveValue) + return machineutils.LongRetry, nil } - // if the machine is neither preserved nor annotated, need not handle it here. Auto-preservation - // handled on failure return machineutils.LongRetry, nil } +func (c *controller) syncEffectivePreserveAnnotationValue(ctx context.Context, machine *v1alpha1.Machine) (*v1alpha1.Machine, string, error) { + var effectivePreserveAnnotationValue string + mAnnotationValue, mExists := machine.Annotations[machineutils.PreserveMachineAnnotationKey] + // node annotation value, if exists, will always override and overwrite machine annotation value for preserve + if machine.Labels[v1alpha1.NodeLabelKey] != "" { + nodeName := machine.Labels[v1alpha1.NodeLabelKey] + node, err := c.nodeLister.Get(nodeName) + if err != nil { + klog.Errorf("error trying to get node %q: %v", nodeName, err) + return machine, "", err + } + nAnnotationValue, nExists := node.Annotations[machineutils.PreserveMachineAnnotationKey] + switch { + case nExists && mExists: + if nAnnotationValue == mAnnotationValue { + return machine, nAnnotationValue, nil + } + effectivePreserveAnnotationValue = nAnnotationValue + case nExists && !mExists: + effectivePreserveAnnotationValue = nAnnotationValue + case mExists && !nExists: + return machine, mAnnotationValue, nil + case !nExists && !mExists: + return machine, "", nil + } + clone := machine.DeepCopy() + if clone.Annotations == nil { + clone.Annotations = make(map[string]string) + } + clone.Annotations[machineutils.PreserveMachineAnnotationKey] = effectivePreserveAnnotationValue + updatedMachine, err := c.controlMachineClient.Machines(c.namespace).Update(ctx, clone, metav1.UpdateOptions{}) + if err != nil { + klog.Errorf("error updating machine with preserve annotations %q: %v", machine.Name, err) + return machine, "", err + } + return updatedMachine, effectivePreserveAnnotationValue, nil + } + //if no backing node + if mExists { + return machine, mAnnotationValue, nil + } + return machine, "", nil +} + // getMachineDeploymentForMachine returns the machine deployment for a given machine func (c *controller) getMachineDeploymentForMachine(machine *v1alpha1.Machine) (*v1alpha1.MachineDeployment, error) { machineDeploymentName := getMachineDeploymentName(machine) diff --git a/pkg/util/provider/machinecontroller/machine_util.go b/pkg/util/provider/machinecontroller/machine_util.go index 6b269c8e2..9efc51d5a 100644 --- a/pkg/util/provider/machinecontroller/machine_util.go +++ b/pkg/util/provider/machinecontroller/machine_util.go @@ -2359,15 +2359,12 @@ func (c *controller) fetchMatchingNodeName(machineName string) (string, error) { return "", fmt.Errorf("machine %q not found in node lister for machine %q", machineName, machineName) } -// TODO@thiyyakat: check if node needs to be updated at all. // TODO@thiyyakat: handle when annotation changed from when-failed to now and vice versa // preserveMachine contains logic to start the preservation of a machine and node func (c *controller) preserveMachine(ctx context.Context, machine *v1alpha1.Machine, preserveValue string) (machineutils.RetryPeriod, error) { klog.V(3).Infof("TEST:Entering preserve machine flow") - isFailed := machineutils.IsMachineFailed(machine) - // machine needs to be preserved now if annotated with preserve=now or if annotated with preserve=when-failed and machine has failed - toBePreservedNow := preserveValue == machineutils.PreserveMachineAnnotationValueNow || preserveValue == machineutils.PreserveMachineAnnotationValueWhenFailed && isFailed - klog.V(3).Infof("TEST:machine: %s, tobepreservednow: %s", machine.Name, toBePreservedNow) + toBePreservedNow := shouldMachineBePreservedNow(machine, preserveValue) + klog.V(3).Infof("TEST:machine: %s, tobepreservednow: %v", machine.Name, toBePreservedNow) // TODO@thiyyakat: may need to change this check to machine.Spec.ProviderID if machine.Labels[v1alpha1.NodeLabelKey] != "" { preservationAnnotations := make(map[string]string) @@ -2416,6 +2413,11 @@ func (c *controller) preserveMachine(ctx context.Context, machine *v1alpha1.Mach return machineutils.LongRetry, nil } +func shouldMachineBePreservedNow(machine *v1alpha1.Machine, preserveValue string) bool { + isFailed := machineutils.IsMachineFailed(machine) + return preserveValue == machineutils.PreserveMachineAnnotationValueNow || preserveValue == machineutils.PreserveMachineAnnotationValueWhenFailed && isFailed +} + func (c *controller) stopMachinePreservation(ctx context.Context, machine *v1alpha1.Machine) (machineutils.RetryPeriod, error) { klog.V(3).Infof("TEST:Entering stopMachinePreservation on machine %q", machine.Name) // if backing node exists, remove annotations that would prevent scale down by autoscaler From 5796f51c1560644eadec2cf235c60a612c8087ed Mon Sep 17 00:00:00 2001 From: thiyyakat Date: Wed, 19 Nov 2025 08:06:01 +0530 Subject: [PATCH 11/43] Add preservation logic in machineset controller. TODO: remove debug logs --- pkg/apis/machine/v1alpha1/machine_types.go | 5 + pkg/controller/machineset.go | 17 +- .../provider/machinecontroller/machine.go | 14 +- .../machinecontroller/machine_util.go | 173 +++++++++--------- pkg/util/provider/machineutils/utils.go | 32 +++- 5 files changed, 141 insertions(+), 100 deletions(-) diff --git a/pkg/apis/machine/v1alpha1/machine_types.go b/pkg/apis/machine/v1alpha1/machine_types.go index 72ac95880..eee38e3a5 100644 --- a/pkg/apis/machine/v1alpha1/machine_types.go +++ b/pkg/apis/machine/v1alpha1/machine_types.go @@ -247,6 +247,11 @@ const ( UpdateFailed string = "UpdateFailed" ) +const ( + // NodePreserved is a node condition type for preservation of machines to allow end-user to know that a node is preserved + NodePreserved corev1.NodeConditionType = "NodePreserved" +) + // CurrentStatus contains information about the current status of Machine. type CurrentStatus struct { Phase MachinePhase `json:"phase,omitempty"` diff --git a/pkg/controller/machineset.go b/pkg/controller/machineset.go index e404e52b6..f6b55347b 100644 --- a/pkg/controller/machineset.go +++ b/pkg/controller/machineset.go @@ -344,8 +344,13 @@ func (c *controller) manageReplicas(ctx context.Context, allMachines []*v1alpha1 machinesWithUpdateSuccessfulLabel = append(machinesWithUpdateSuccessfulLabel, m) continue } - if machineutils.IsMachineFailed(m) || machineutils.IsMachineTriggeredForDeletion(m) { + klog.V(3).Infof("TEST: machine:%s, annot:%s, expirytimeset:%v, has timeout: %v", m.Name, m.Annotations[machineutils.PreserveMachineAnnotationKey], m.Status.CurrentStatus.PreserveExpiryTime, machineutils.HasPreservationTimedOut(m)) + if machineutils.IsPreserveExpiryTimeSet(m) && !machineutils.HasPreservationTimedOut(m) { + klog.V(2).Infof("Machine %s currently preserved, not adding to stale machines", m.Name) + activeMachines = append(activeMachines, m) + continue + } staleMachines = append(staleMachines, m) } else if machineutils.IsMachineActive(m) { activeMachines = append(activeMachines, m) @@ -463,12 +468,12 @@ func (c *controller) manageReplicas(ctx context.Context, allMachines []*v1alpha1 logMachinesToDelete(machinesToDelete) //if machines are preserved, stop preservation //for _, mc := range machinesToDelete { - // if machineutils.IsMachinePreserved(mc) { + // if machineutils.IsPreserveExpiryTimeSet(mc) { // // } // //}for _, mc := range machinesToDelete { - // if machineutils.IsMachinePreserved(mc) { + // if machineutils.IsPreserveExpiryTimeSet(mc) { // // } // @@ -709,7 +714,7 @@ func prioritisePreservedMachines(machines []*v1alpha1.Machine) []*v1alpha1.Machi pendingMachines := make([]*v1alpha1.Machine, 0, len(machines)) otherMachines := make([]*v1alpha1.Machine, 0, len(machines)) for _, mc := range machines { - if machineutils.IsMachinePreserved(mc) { + if machineutils.IsPreserveExpiryTimeSet(mc) { pendingMachines = append(pendingMachines, mc) } else { otherMachines = append(otherMachines, mc) @@ -784,8 +789,8 @@ func (c *controller) terminateMachines(ctx context.Context, inactiveMachines []* defer close(errCh) wg.Add(numOfInactiveMachines) - for _, machine := range inactiveMachines { - go c.prepareMachineForDeletion(ctx, machine, machineSet, &wg, errCh) + for _, m := range inactiveMachines { + go c.prepareMachineForDeletion(ctx, m, machineSet, &wg, errCh) } wg.Wait() diff --git a/pkg/util/provider/machinecontroller/machine.go b/pkg/util/provider/machinecontroller/machine.go index 17a4b65b3..975a9abd0 100644 --- a/pkg/util/provider/machinecontroller/machine.go +++ b/pkg/util/provider/machinecontroller/machine.go @@ -753,17 +753,17 @@ func (c *controller) machinePreservation(ctx context.Context, machine *v1alpha1. return machineutils.ShortRetry, err } klog.V(3).Infof("TEST effective preservation value for machine %q: %s", updatedMachine.Name, preserveValue) - isPreserved := machineutils.IsMachinePreserved(updatedMachine) + preserveExpiryTimeSet := machineutils.IsPreserveExpiryTimeSet(updatedMachine) switch preserveValue { case machineutils.PreserveMachineAnnotationValueNow, machineutils.PreserveMachineAnnotationValueWhenFailed: - if !isPreserved { - return c.preserveMachine(ctx, machine, preserveValue) - } else if metav1.Now().After(machine.Status.CurrentStatus.PreserveExpiryTime.Time) { - return c.stopMachinePreservation(ctx, machine) + if !preserveExpiryTimeSet { + return c.preserveMachine(ctx, updatedMachine, preserveValue) + } else if metav1.Now().After(updatedMachine.Status.CurrentStatus.PreserveExpiryTime.Time) { + return c.stopMachinePreservation(ctx, updatedMachine) } case machineutils.PreserveMachineAnnotationValueFalse: - if isPreserved { - return c.stopMachinePreservation(ctx, machine) + if preserveExpiryTimeSet { + return c.stopMachinePreservation(ctx, updatedMachine) } case "": return machineutils.LongRetry, nil diff --git a/pkg/util/provider/machinecontroller/machine_util.go b/pkg/util/provider/machinecontroller/machine_util.go index 9efc51d5a..6ecc22965 100644 --- a/pkg/util/provider/machinecontroller/machine_util.go +++ b/pkg/util/provider/machinecontroller/machine_util.go @@ -943,8 +943,9 @@ func (c *controller) reconcileMachineHealth(ctx context.Context, machine *v1alph klog.Warning(description) clone.Status.CurrentStatus = v1alpha1.CurrentStatus{ - Phase: v1alpha1.MachineUnknown, - LastUpdateTime: metav1.Now(), + Phase: v1alpha1.MachineUnknown, + LastUpdateTime: metav1.Now(), + PreserveExpiryTime: machine.Status.CurrentStatus.PreserveExpiryTime, } clone.Status.LastOperation = v1alpha1.LastOperation{ Description: description, @@ -997,7 +998,8 @@ func (c *controller) reconcileMachineHealth(ctx context.Context, machine *v1alph clone.Status.CurrentStatus = v1alpha1.CurrentStatus{ Phase: v1alpha1.MachineRunning, // TimeoutActive: false, - LastUpdateTime: metav1.Now(), + LastUpdateTime: metav1.Now(), + PreserveExpiryTime: machine.Status.CurrentStatus.PreserveExpiryTime, } cloneDirty = true } @@ -1087,7 +1089,7 @@ func (c *controller) reconcileMachineHealth(ctx context.Context, machine *v1alph } if timeElapsed > timeOutDuration { // Machine health timeout occurred while joining or rejoining of machine - + klog.V(2).Infof("TEST: timeout has occurred %s", machine.Name) if !isMachinePending && !isMachineInPlaceUpdating && !disableHealthTimeout { // Timeout occurred due to machine being unhealthy for too long description = fmt.Sprintf( @@ -1103,9 +1105,9 @@ func (c *controller) reconcileMachineHealth(ctx context.Context, machine *v1alph if err != nil { return retry, err } - if value, exists := machine.Annotations[machineutils.PreserveMachineAnnotationKey]; exists && value == machineutils.PreserveMachineAnnotationValueWhenFailed { - klog.V(3).Infof("TEST:Preserving machine on failure due to annotation") - return c.preserveMachine(ctx, machine, machineutils.PreserveMachineAnnotationValueWhenFailed) + if val, exists := machine.Annotations[machineutils.PreserveMachineAnnotationKey]; exists && val == machineutils.PreserveMachineAnnotationValueWhenFailed { + klog.V(2).Infof("TEST: timeout has occurred, preserve machine %s", machine.Name) + return c.preserveMachine(ctx, machine, val) } return retry, err } @@ -1147,8 +1149,9 @@ func (c *controller) reconcileMachineHealth(ctx context.Context, machine *v1alph LastUpdateTime: metav1.Now(), } clone.Status.CurrentStatus = v1alpha1.CurrentStatus{ - Phase: v1alpha1.MachineFailed, - LastUpdateTime: metav1.Now(), + Phase: v1alpha1.MachineFailed, + LastUpdateTime: metav1.Now(), + PreserveExpiryTime: machine.Status.CurrentStatus.PreserveExpiryTime, } cloneDirty = true } @@ -1168,17 +1171,17 @@ func (c *controller) reconcileMachineHealth(ctx context.Context, machine *v1alph if apierrors.IsConflict(err) { return machineutils.ConflictRetry, err } - } else { - klog.V(2).Infof("Machine Phase/Conditions have been updated for %q with providerID %q and are in sync with backing node %q", machine.Name, getProviderID(machine), getNodeName(machine)) - if updatedMachine.Status.CurrentStatus.Phase == v1alpha1.MachineFailed && updatedMachine.Annotations[machineutils.PreserveMachineAnnotationKey] == machineutils.PreserveMachineAnnotationValueWhenFailed { - klog.V(3).Infof("TEST:Preserving machine on failure due to annotation") - return c.preserveMachine(ctx, updatedMachine, machineutils.PreserveMachineAnnotationValueWhenFailed) - } - // Return error to end the reconcile - err = errSuccessfulPhaseUpdate + return machineutils.ShortRetry, err } - return machineutils.ShortRetry, err + klog.V(2).Infof("Machine Phase/Conditions have been updated for %q with providerID %q and are in sync with backing node %q", updatedMachine.Name, getProviderID(updatedMachine), getNodeName(updatedMachine)) + if val, exists := updatedMachine.Annotations[machineutils.PreserveMachineAnnotationKey]; exists && val == machineutils.PreserveMachineAnnotationValueWhenFailed && (updatedMachine.Status.CurrentStatus.Phase != v1alpha1.MachineInPlaceUpdating) { + klog.V(2).Infof("TEST: timeout has occurred, preserve machine") + return c.preserveMachine(ctx, updatedMachine, machineutils.PreserveMachineAnnotationValueWhenFailed) + } + // TODO@thiyyakat: fix this. check earlier code. + // Return error to end the reconcile + err = errSuccessfulPhaseUpdate } return machineutils.LongRetry, nil @@ -2359,29 +2362,28 @@ func (c *controller) fetchMatchingNodeName(machineName string) (string, error) { return "", fmt.Errorf("machine %q not found in node lister for machine %q", machineName, machineName) } -// TODO@thiyyakat: handle when annotation changed from when-failed to now and vice versa -// preserveMachine contains logic to start the preservation of a machine and node +// preserveMachine contains logic to start the preservation of a machine and node. It syncs node annotations to the machine if the backing node exists, +// or has an annotation related to preservation. +// it does not sync preserve annotation values from machine to node to prevent bi-directional syncing issues. func (c *controller) preserveMachine(ctx context.Context, machine *v1alpha1.Machine, preserveValue string) (machineutils.RetryPeriod, error) { + if !machineutils.ShouldMachineBePreservedNow(machine, preserveValue) { + return machineutils.LongRetry, nil + } klog.V(3).Infof("TEST:Entering preserve machine flow") - toBePreservedNow := shouldMachineBePreservedNow(machine, preserveValue) - klog.V(3).Infof("TEST:machine: %s, tobepreservednow: %v", machine.Name, toBePreservedNow) // TODO@thiyyakat: may need to change this check to machine.Spec.ProviderID if machine.Labels[v1alpha1.NodeLabelKey] != "" { - preservationAnnotations := make(map[string]string) - preservationAnnotations[machineutils.PreserveMachineAnnotationKey] = machine.Annotations[machineutils.PreserveMachineAnnotationKey] - if toBePreservedNow { - preservationAnnotations[autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationKey] = autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationValue - } nodeName := machine.Labels[v1alpha1.NodeLabelKey] node, err := c.nodeLister.Get(nodeName) if err != nil { klog.Errorf("error trying to get node %q: %v", nodeName, err) return machineutils.ShortRetry, err } - klog.V(3).Infof("TEST:preservationAnnotations on node : %s: %v, and machine: %s", node.Name, node.Annotations[machineutils.PreserveMachineAnnotationKey], machine.Annotations[machineutils.PreserveMachineAnnotationKey]) - // if preserve annotation not updated on node, we add it + // not updating node's preserve annotations here in case operator is manipulating machine annotations only + // if node annotation is updated, machine annotation will be overwritten with this value even if operator wants it to change // function never returns error, can be ignored - updatedNode, _, _ := annotations.AddOrUpdateAnnotation(node, preservationAnnotations) + CAScaleDownAnnotation := make(map[string]string) + CAScaleDownAnnotation[autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationKey] = autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationValue + updatedNode, _, _ := annotations.AddOrUpdateAnnotation(node, CAScaleDownAnnotation) _, err = c.targetCoreClient.CoreV1().Nodes().Update(ctx, updatedNode, metav1.UpdateOptions{}) if err != nil { if apierrors.IsConflict(err) { @@ -2390,18 +2392,32 @@ func (c *controller) preserveMachine(ctx context.Context, machine *v1alpha1.Mach klog.Errorf("node UPDATE failed for machine %s with node %s. Retrying, error: %s", machine.Name, nodeName, err) return machineutils.ShortRetry, err } - klog.V(2).Infof("Updated preservation annotations for node %s, for machine %q, successfully", node.Name, machine.Name) - if !toBePreservedNow { - return machineutils.LongRetry, nil + klog.V(2).Infof("Updated CA annotations for node %s, for machine %q, successfully", node.Name, machine.Name) + + preservedCondition := v1.NodeCondition{ + Type: v1alpha1.NodePreserved, + Status: v1.ConditionTrue, + LastTransitionTime: metav1.Now(), + } + updatedNode = nodeops.AddOrUpdateCondition(updatedNode, preservedCondition) + _, err = c.targetCoreClient.CoreV1().Nodes().UpdateStatus(ctx, updatedNode, metav1.UpdateOptions{}) + if err != nil { + if apierrors.IsConflict(err) { + return machineutils.ConflictRetry, err + } + klog.Errorf("Node Status UPDATE failed for machine %s with node %s. Retrying, error: %s", machine.Name, nodeName, err) + return machineutils.ShortRetry, err } + klog.V(2).Infof("Updated Node Condition NodePreserved for node %s, for machine %q, successfully", node.Name, machine.Name) } + clone := machine.DeepCopy() clone.Status.CurrentStatus = v1alpha1.CurrentStatus{ Phase: clone.Status.CurrentStatus.Phase, LastUpdateTime: metav1.Now(), PreserveExpiryTime: metav1.NewTime(metav1.Now().Add(c.getEffectiveMachinePreserveTimeout(machine).Duration)), } - _, err := c.controlMachineClient.Machines(clone.Namespace).UpdateStatus(ctx, clone, metav1.UpdateOptions{}) + updatedMachine, err := c.controlMachineClient.Machines(clone.Namespace).UpdateStatus(ctx, clone, metav1.UpdateOptions{}) if err != nil { klog.Errorf("machine status UPDATE failed for machine %q. Retrying, error: %s", machine.Name, err) if apierrors.IsConflict(err) { @@ -2409,20 +2425,13 @@ func (c *controller) preserveMachine(ctx context.Context, machine *v1alpha1.Mach } return machineutils.ShortRetry, err } - klog.V(2).Infof("Machine %q preserved.", machine.Name) + klog.V(2).Infof("Machine %q preserved till %v.", machine.Name, updatedMachine.Status.CurrentStatus.PreserveExpiryTime) return machineutils.LongRetry, nil } - -func shouldMachineBePreservedNow(machine *v1alpha1.Machine, preserveValue string) bool { - isFailed := machineutils.IsMachineFailed(machine) - return preserveValue == machineutils.PreserveMachineAnnotationValueNow || preserveValue == machineutils.PreserveMachineAnnotationValueWhenFailed && isFailed -} - func (c *controller) stopMachinePreservation(ctx context.Context, machine *v1alpha1.Machine) (machineutils.RetryPeriod, error) { klog.V(3).Infof("TEST:Entering stopMachinePreservation on machine %q", machine.Name) // if backing node exists, remove annotations that would prevent scale down by autoscaler - // TODO@thiyyakat: may need to change this check to machine.Spec.ProviderID - if machine.Labels[v1alpha1.NodeLabelKey] != "" { + if machine.Labels[v1alpha1.NodeLabelKey] != "" { // TODO@thiyyakat: may need to change this check to machine.Spec.ProviderID nodeName := machine.Labels[v1alpha1.NodeLabelKey] node, err := c.nodeLister.Get(nodeName) if err != nil { @@ -2433,12 +2442,6 @@ func (c *controller) stopMachinePreservation(ctx context.Context, machine *v1alp CAAnnotations := make(map[string]string) CAAnnotations[autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationKey] = "" updatedNode, _, _ := annotations.RemoveAnnotation(node, CAAnnotations) // error can be ignored, always returns nil - // set preserve=false on node if it is set on machine - if machine.Annotations[machineutils.PreserveMachineAnnotationKey] == machineutils.PreserveMachineAnnotationValueFalse { - preserveAnnotations := make(map[string]string) - preserveAnnotations[machineutils.PreserveMachineAnnotationKey] = machineutils.PreserveMachineAnnotationValueFalse - updatedNode, _, _ = annotations.AddOrUpdateAnnotation(updatedNode, preserveAnnotations) // error can be ignored, always returns nil - } _, err = c.targetCoreClient.CoreV1().Nodes().Update(ctx, updatedNode, metav1.UpdateOptions{}) if err != nil { klog.Errorf("error trying to update node %q: %v", nodeName, err) @@ -2447,50 +2450,50 @@ func (c *controller) stopMachinePreservation(ctx context.Context, machine *v1alp } return machineutils.ShortRetry, err } - } - clone := machine.DeepCopy() - delete(clone.Annotations, autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationKey) - // TODO@thiyyakat: understand why ClusterAutoscalerScaleDownDisabledAnnotationByMCMKey is added - //delete(clone.Annotations, autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationByMCMKey) - delete(clone.Annotations, machineutils.PreserveMachineAnnotationKey) - updatedMachine, err := c.controlMachineClient.Machines(clone.Namespace).Update(ctx, clone, metav1.UpdateOptions{}) - if err != nil { - klog.Errorf("machine UPDATE failed for machine %q. Retrying, error: %s", machine.Name, err) - if apierrors.IsConflict(err) { - return machineutils.ConflictRetry, err - } - return machineutils.ShortRetry, err - } else { - klog.V(2).Infof("Machine %q updated to remove annotations ", machine.Name) - // Return error even when machine object is updated to ensure reconcilation is restarted - } - if machineutils.IsMachinePreserved(machine) { - updatedMachine.Status.CurrentStatus = v1alpha1.CurrentStatus{ - Phase: updatedMachine.Status.CurrentStatus.Phase, - LastUpdateTime: metav1.Now(), - PreserveExpiryTime: metav1.Time{}, + preservedCondition := v1.NodeCondition{ + Type: v1alpha1.NodePreserved, + Status: v1.ConditionFalse, + LastTransitionTime: metav1.Now(), } - _, err = c.controlMachineClient.Machines(updatedMachine.Namespace).UpdateStatus(ctx, updatedMachine, metav1.UpdateOptions{}) + updatedNode = nodeops.AddOrUpdateCondition(updatedNode, preservedCondition) + _, err = c.targetCoreClient.CoreV1().Nodes().UpdateStatus(ctx, updatedNode, metav1.UpdateOptions{}) if err != nil { - klog.Errorf("Machine/status UPDATE failed for machine %q. Retrying, error: %s", updatedMachine.Name, err) if apierrors.IsConflict(err) { return machineutils.ConflictRetry, err } + klog.Errorf("Node Status UPDATE failed for machine %s with node %s. Retrying, error: %s", machine.Name, nodeName, err) return machineutils.ShortRetry, err } - klog.V(2).Infof("Machine %q status updated to stop preservation ", updatedMachine.Name) - // if machine is in failed state transition to Terminating - if updatedMachine.Status.CurrentStatus.Phase == v1alpha1.MachineFailed { - err = c.controlMachineClient.Machines(c.namespace).Delete(ctx, updatedMachine.Name, metav1.DeleteOptions{}) - if err != nil { - klog.Errorf("error trying to delete machine %q: %v", updatedMachine.Name, err) - if apierrors.IsConflict(err) { - return machineutils.ConflictRetry, err - } - return machineutils.ShortRetry, err - } - klog.V(2).Infof("Machine %q marked for deletion", updatedMachine.Name) + klog.V(2).Infof("Updated Node Condition NodePreserved for node %s, for machine %q, successfully", node.Name, machine.Name) + } + clone := machine.DeepCopy() + clone.Status.CurrentStatus = v1alpha1.CurrentStatus{ + Phase: machine.Status.CurrentStatus.Phase, + LastUpdateTime: metav1.Now(), + PreserveExpiryTime: metav1.Time{}, + } + updatedMachine, err := c.controlMachineClient.Machines(clone.Namespace).UpdateStatus(ctx, clone, metav1.UpdateOptions{}) + if err != nil { + klog.Errorf("Machine/status UPDATE failed for machine %q. Retrying, error: %s", clone.Name, err) + if apierrors.IsConflict(err) { + return machineutils.ConflictRetry, err } + return machineutils.ShortRetry, err } + klog.V(2).Infof("Machine %q status updated to stop preservation ", updatedMachine.Name) + // TODO@thiyyakat: if machine was in failed state and machinehealthtimeout has not expired, then it should + // continue to be in Failed. Normal flow is not changed. + //// if machine is in failed state transition to Terminating + //if updatedMachine.Status.CurrentStatus.Phase == v1alpha1.MachineFailed { + // err = c.controlMachineClient.Machines(c.namespace).Delete(ctx, updatedMachine.Name, metav1.DeleteOptions{}) + // if err != nil { + // klog.Errorf("error trying to delete machine %q: %v", updatedMachine.Name, err) + // if apierrors.IsConflict(err) { + // return machineutils.ConflictRetry, err + // } + // return machineutils.ShortRetry, err + // } + // klog.V(2).Infof("Machine %q marked for deletion", updatedMachine.Name) + //} return machineutils.LongRetry, nil } diff --git a/pkg/util/provider/machineutils/utils.go b/pkg/util/provider/machineutils/utils.go index ab6926dcf..c20f62706 100644 --- a/pkg/util/provider/machineutils/utils.go +++ b/pkg/util/provider/machineutils/utils.go @@ -141,7 +141,35 @@ func IsMachineTriggeredForDeletion(m *v1alpha1.Machine) bool { return m.Annotations[MachinePriority] == "1" || m.Annotations[TriggerDeletionByMCM] == "true" } -// IsMachinePreserved checks if machine is preserved by MCM -func IsMachinePreserved(m *v1alpha1.Machine) bool { +// IsPreserveExpiryTimeSet checks if machine is preserved by MCM +func IsPreserveExpiryTimeSet(m *v1alpha1.Machine) bool { return !m.Status.CurrentStatus.PreserveExpiryTime.IsZero() } + +// HasPreservationTimedOut checks if the Status.CurrentStatus.PreserveExpiryTime has not yet passed +func HasPreservationTimedOut(m *v1alpha1.Machine) bool { + if m.Status.CurrentStatus.PreserveExpiryTime.IsZero() { + return true + } else if m.Status.CurrentStatus.PreserveExpiryTime.After(time.Now()) { + return false + } + return true +} + +func ShouldMachineBePreservedNow(machine *v1alpha1.Machine, preserveValue string) bool { + isFailed := IsMachineFailed(machine) + return preserveValue == PreserveMachineAnnotationValueNow || preserveValue == PreserveMachineAnnotationValueWhenFailed && isFailed +} + +//func IsMachinePreserved(machine *v1alpha1.Machine) bool { +// val, exists := machine.Annotations[PreserveMachineAnnotationKey] +// if !exists { +// return false +// } else { +// if val == PreserveMachineAnnotationValueNow && machine.Status.CurrentStatus.PreserveExpiryTime.After(time.Now()) { +// return true +// } else if val == PreserveMachineAnnotationValueWhenFailed && IsMachineFailed(machine) { +// return true +// } +// } +//} From 1636aceb3f8997e2fbb6f237c5d1717d96acf79a Mon Sep 17 00:00:00 2001 From: thiyyakat Date: Wed, 19 Nov 2025 14:53:20 +0530 Subject: [PATCH 12/43] Add drain logic post preservation of failed machine --- pkg/controller/machineset.go | 16 +- .../provider/machinecontroller/machine.go | 1 - .../machinecontroller/machine_util.go | 160 ++++++++++-------- pkg/util/provider/machineutils/utils.go | 5 + 4 files changed, 105 insertions(+), 77 deletions(-) diff --git a/pkg/controller/machineset.go b/pkg/controller/machineset.go index f6b55347b..f856dbed5 100644 --- a/pkg/controller/machineset.go +++ b/pkg/controller/machineset.go @@ -345,13 +345,25 @@ func (c *controller) manageReplicas(ctx context.Context, allMachines []*v1alpha1 continue } if machineutils.IsMachineFailed(m) || machineutils.IsMachineTriggeredForDeletion(m) { - klog.V(3).Infof("TEST: machine:%s, annot:%s, expirytimeset:%v, has timeout: %v", m.Name, m.Annotations[machineutils.PreserveMachineAnnotationKey], m.Status.CurrentStatus.PreserveExpiryTime, machineutils.HasPreservationTimedOut(m)) + //klog.V(3).Infof("TEST: machine:%s, annot:%s, expirytimeset:%v, val: %v, has timeout: %v", m.Name, m.Annotations[machineutils.PreserveMachineAnnotationKey], m.Status.CurrentStatus.PreserveExpiryTime, machineutils.HasPreservationTimedOut(m), machineutils.HasPreservationTimedOut(m)) + //klog.V(3).Infof("TEST: machine:%s, annot:%s, expirytimeset:%v (IsSet=%v), has timed out: %v", + // m.Name, + // m.Annotations[machineutils.PreserveMachineAnnotationKey], + // m.Status.CurrentStatus.PreserveExpiryTime, + // machineutils.IsPreserveExpiryTimeSet(m), // ← Actually call the function! + // machineutils.HasPreservationTimedOut(m)) if machineutils.IsPreserveExpiryTimeSet(m) && !machineutils.HasPreservationTimedOut(m) { klog.V(2).Infof("Machine %s currently preserved, not adding to stale machines", m.Name) activeMachines = append(activeMachines, m) continue + } else if val, exists := m.Annotations[machineutils.PreserveMachineAnnotationKey]; exists && val == machineutils.PreserveMachineAnnotationValueWhenFailed { // this is the case where the machine controller has not had a chance to update the preserve expiry time on failure of machine causing a race condition + klog.V(2).Infof("Machine %s currently preserved, not adding to stale machines", m.Name) + activeMachines = append(activeMachines, m) + + } else { + staleMachines = append(staleMachines, m) } - staleMachines = append(staleMachines, m) + } else if machineutils.IsMachineActive(m) { activeMachines = append(activeMachines, m) } diff --git a/pkg/util/provider/machinecontroller/machine.go b/pkg/util/provider/machinecontroller/machine.go index 975a9abd0..eb6d76021 100644 --- a/pkg/util/provider/machinecontroller/machine.go +++ b/pkg/util/provider/machinecontroller/machine.go @@ -752,7 +752,6 @@ func (c *controller) machinePreservation(ctx context.Context, machine *v1alpha1. klog.Errorf("Error getting preserve annotation value for machine %q: %s", machine.Name, err) return machineutils.ShortRetry, err } - klog.V(3).Infof("TEST effective preservation value for machine %q: %s", updatedMachine.Name, preserveValue) preserveExpiryTimeSet := machineutils.IsPreserveExpiryTimeSet(updatedMachine) switch preserveValue { case machineutils.PreserveMachineAnnotationValueNow, machineutils.PreserveMachineAnnotationValueWhenFailed: diff --git a/pkg/util/provider/machinecontroller/machine_util.go b/pkg/util/provider/machinecontroller/machine_util.go index 6ecc22965..985cf3275 100644 --- a/pkg/util/provider/machinecontroller/machine_util.go +++ b/pkg/util/provider/machinecontroller/machine_util.go @@ -1089,7 +1089,6 @@ func (c *controller) reconcileMachineHealth(ctx context.Context, machine *v1alph } if timeElapsed > timeOutDuration { // Machine health timeout occurred while joining or rejoining of machine - klog.V(2).Infof("TEST: timeout has occurred %s", machine.Name) if !isMachinePending && !isMachineInPlaceUpdating && !disableHealthTimeout { // Timeout occurred due to machine being unhealthy for too long description = fmt.Sprintf( @@ -1106,7 +1105,6 @@ func (c *controller) reconcileMachineHealth(ctx context.Context, machine *v1alph return retry, err } if val, exists := machine.Annotations[machineutils.PreserveMachineAnnotationKey]; exists && val == machineutils.PreserveMachineAnnotationValueWhenFailed { - klog.V(2).Infof("TEST: timeout has occurred, preserve machine %s", machine.Name) return c.preserveMachine(ctx, machine, val) } return retry, err @@ -1176,7 +1174,6 @@ func (c *controller) reconcileMachineHealth(ctx context.Context, machine *v1alph klog.V(2).Infof("Machine Phase/Conditions have been updated for %q with providerID %q and are in sync with backing node %q", updatedMachine.Name, getProviderID(updatedMachine), getNodeName(updatedMachine)) if val, exists := updatedMachine.Annotations[machineutils.PreserveMachineAnnotationKey]; exists && val == machineutils.PreserveMachineAnnotationValueWhenFailed && (updatedMachine.Status.CurrentStatus.Phase != v1alpha1.MachineInPlaceUpdating) { - klog.V(2).Infof("TEST: timeout has occurred, preserve machine") return c.preserveMachine(ctx, updatedMachine, machineutils.PreserveMachineAnnotationValueWhenFailed) } // TODO@thiyyakat: fix this. check earlier code. @@ -1635,8 +1632,15 @@ func (c *controller) drainNode(ctx context.Context, deleteMachineRequest *driver if skipDrain { state = v1alpha1.MachineStateProcessing } else { - timeOutOccurred = utiltime.HasTimeOutOccurred(*machine.DeletionTimestamp, timeOutDuration) - + if machineutils.IsPreserveExpiryTimeSet(machine) { + preserveStartTime := machine.Status.CurrentStatus.PreserveExpiryTime.Time.Add(-c.getEffectiveMachinePreserveTimeout(machine).Duration) + timeOutOccurred = utiltime.HasTimeOutOccurred( + metav1.Time{Time: preserveStartTime}, + timeOutDuration, + ) + } else { + timeOutOccurred = utiltime.HasTimeOutOccurred(*machine.DeletionTimestamp, timeOutDuration) + } if forceDeleteLabelPresent || timeOutOccurred { // To perform forceful machine drain/delete either one of the below conditions must be satified // 1. force-deletion: "True" label must be present @@ -1717,7 +1721,12 @@ func (c *controller) drainNode(ctx context.Context, deleteMachineRequest *driver if forceDeletePods { description = fmt.Sprintf("Force Drain successful. %s", machineutils.DelVolumesAttachments) } else { // regular drain already waits for vol detach and attach for another node. - description = fmt.Sprintf("Drain successful. %s", machineutils.InitiateVMDeletion) + if machineutils.IsPreserveExpiryTimeSet(machine) { + description = fmt.Sprintf("Drain successful. Machine preserved.") + } else { + description = fmt.Sprintf("Drain successful. %s", machineutils.InitiateVMDeletion) + } + } err = fmt.Errorf("%s", description) state = v1alpha1.MachineStateProcessing @@ -2369,7 +2378,40 @@ func (c *controller) preserveMachine(ctx context.Context, machine *v1alpha1.Mach if !machineutils.ShouldMachineBePreservedNow(machine, preserveValue) { return machineutils.LongRetry, nil } - klog.V(3).Infof("TEST:Entering preserve machine flow") + clone := machine.DeepCopy() + clone.Status.CurrentStatus = v1alpha1.CurrentStatus{ + Phase: clone.Status.CurrentStatus.Phase, + LastUpdateTime: metav1.Now(), + PreserveExpiryTime: metav1.NewTime(metav1.Now().Add(c.getEffectiveMachinePreserveTimeout(machine).Duration)), + } + updatedMachine, err := c.controlMachineClient.Machines(clone.Namespace).UpdateStatus(ctx, clone, metav1.UpdateOptions{}) + if err != nil { + klog.Errorf("machine status UPDATE failed for machine %q. Retrying, error: %s", machine.Name, err) + if apierrors.IsConflict(err) { + return machineutils.ConflictRetry, err + } + return machineutils.ShortRetry, err + } + klog.V(2).Infof("Machine %q preserved till %v.", machine.Name, updatedMachine.Status.CurrentStatus.PreserveExpiryTime) + if updatedMachine.Status.CurrentStatus.Phase == v1alpha1.MachineFailed { + // Validate MachineClass + machineClass, secretData, retry, err := c.ValidateMachineClass(ctx, &machine.Spec.Class) + if err != nil { + klog.Errorf("cannot reconcile machine %s: %s", machine.Name, err) + return retry, err + } + + deleteMachineRequest := &driver.DeleteMachineRequest{ + Machine: updatedMachine, + MachineClass: machineClass, + Secret: &v1.Secret{Data: secretData}, + } + retry, err = c.drainNode(ctx, deleteMachineRequest) + if err != nil { + klog.Errorf("error draining node backing machine: %s, error:%s", updatedMachine.Name, err) + return retry, err + } + } // TODO@thiyyakat: may need to change this check to machine.Spec.ProviderID if machine.Labels[v1alpha1.NodeLabelKey] != "" { nodeName := machine.Labels[v1alpha1.NodeLabelKey] @@ -2378,28 +2420,13 @@ func (c *controller) preserveMachine(ctx context.Context, machine *v1alpha1.Mach klog.Errorf("error trying to get node %q: %v", nodeName, err) return machineutils.ShortRetry, err } - // not updating node's preserve annotations here in case operator is manipulating machine annotations only - // if node annotation is updated, machine annotation will be overwritten with this value even if operator wants it to change - // function never returns error, can be ignored - CAScaleDownAnnotation := make(map[string]string) - CAScaleDownAnnotation[autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationKey] = autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationValue - updatedNode, _, _ := annotations.AddOrUpdateAnnotation(node, CAScaleDownAnnotation) - _, err = c.targetCoreClient.CoreV1().Nodes().Update(ctx, updatedNode, metav1.UpdateOptions{}) - if err != nil { - if apierrors.IsConflict(err) { - return machineutils.ConflictRetry, err - } - klog.Errorf("node UPDATE failed for machine %s with node %s. Retrying, error: %s", machine.Name, nodeName, err) - return machineutils.ShortRetry, err - } - klog.V(2).Infof("Updated CA annotations for node %s, for machine %q, successfully", node.Name, machine.Name) preservedCondition := v1.NodeCondition{ Type: v1alpha1.NodePreserved, Status: v1.ConditionTrue, LastTransitionTime: metav1.Now(), } - updatedNode = nodeops.AddOrUpdateCondition(updatedNode, preservedCondition) + updatedNode := nodeops.AddOrUpdateCondition(node, preservedCondition) _, err = c.targetCoreClient.CoreV1().Nodes().UpdateStatus(ctx, updatedNode, metav1.UpdateOptions{}) if err != nil { if apierrors.IsConflict(err) { @@ -2409,27 +2436,41 @@ func (c *controller) preserveMachine(ctx context.Context, machine *v1alpha1.Mach return machineutils.ShortRetry, err } klog.V(2).Infof("Updated Node Condition NodePreserved for node %s, for machine %q, successfully", node.Name, machine.Name) - } + // not updating node's preserve annotations here in case operator is manipulating machine annotations only + // if node annotation is updated, machine annotation will be overwritten with this value even if operator wants it to change + // function never returns error, can be ignored + CAScaleDownAnnotation := make(map[string]string) + CAScaleDownAnnotation[autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationKey] = autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationValue + updatedNode, _, _ = annotations.AddOrUpdateAnnotation(node, CAScaleDownAnnotation) + updatedNode, err = c.targetCoreClient.CoreV1().Nodes().Update(ctx, updatedNode, metav1.UpdateOptions{}) + if err != nil { + if apierrors.IsConflict(err) { + return machineutils.ConflictRetry, err + } + klog.Errorf("node UPDATE failed for machine %s with node %s. Retrying, error: %s", machine.Name, nodeName, err) + return machineutils.ShortRetry, err + } + klog.V(2).Infof("Updated CA annotations for node %s, for machine %q, successfully", node.Name, machine.Name) + } + return machineutils.LongRetry, nil +} +func (c *controller) stopMachinePreservation(ctx context.Context, machine *v1alpha1.Machine) (machineutils.RetryPeriod, error) { clone := machine.DeepCopy() clone.Status.CurrentStatus = v1alpha1.CurrentStatus{ - Phase: clone.Status.CurrentStatus.Phase, + Phase: machine.Status.CurrentStatus.Phase, LastUpdateTime: metav1.Now(), - PreserveExpiryTime: metav1.NewTime(metav1.Now().Add(c.getEffectiveMachinePreserveTimeout(machine).Duration)), + PreserveExpiryTime: metav1.Time{}, } updatedMachine, err := c.controlMachineClient.Machines(clone.Namespace).UpdateStatus(ctx, clone, metav1.UpdateOptions{}) if err != nil { - klog.Errorf("machine status UPDATE failed for machine %q. Retrying, error: %s", machine.Name, err) + klog.Errorf("Machine/status UPDATE failed for machine %q. Retrying, error: %s", clone.Name, err) if apierrors.IsConflict(err) { return machineutils.ConflictRetry, err } return machineutils.ShortRetry, err } - klog.V(2).Infof("Machine %q preserved till %v.", machine.Name, updatedMachine.Status.CurrentStatus.PreserveExpiryTime) - return machineutils.LongRetry, nil -} -func (c *controller) stopMachinePreservation(ctx context.Context, machine *v1alpha1.Machine) (machineutils.RetryPeriod, error) { - klog.V(3).Infof("TEST:Entering stopMachinePreservation on machine %q", machine.Name) + klog.V(2).Infof("Machine %q status updated to stop preservation ", updatedMachine.Name) // if backing node exists, remove annotations that would prevent scale down by autoscaler if machine.Labels[v1alpha1.NodeLabelKey] != "" { // TODO@thiyyakat: may need to change this check to machine.Spec.ProviderID nodeName := machine.Labels[v1alpha1.NodeLabelKey] @@ -2438,25 +2479,13 @@ func (c *controller) stopMachinePreservation(ctx context.Context, machine *v1alp klog.Errorf("error trying to get node %q: %v", nodeName, err) return machineutils.ShortRetry, err } - // remove CA annotation from node, values do not matter here - CAAnnotations := make(map[string]string) - CAAnnotations[autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationKey] = "" - updatedNode, _, _ := annotations.RemoveAnnotation(node, CAAnnotations) // error can be ignored, always returns nil - _, err = c.targetCoreClient.CoreV1().Nodes().Update(ctx, updatedNode, metav1.UpdateOptions{}) - if err != nil { - klog.Errorf("error trying to update node %q: %v", nodeName, err) - if apierrors.IsConflict(err) { - return machineutils.ConflictRetry, err - } - return machineutils.ShortRetry, err - } preservedCondition := v1.NodeCondition{ Type: v1alpha1.NodePreserved, Status: v1.ConditionFalse, LastTransitionTime: metav1.Now(), } - updatedNode = nodeops.AddOrUpdateCondition(updatedNode, preservedCondition) - _, err = c.targetCoreClient.CoreV1().Nodes().UpdateStatus(ctx, updatedNode, metav1.UpdateOptions{}) + updatedNode := nodeops.AddOrUpdateCondition(node, preservedCondition) + updatedNode, err = c.targetCoreClient.CoreV1().Nodes().UpdateStatus(ctx, updatedNode, metav1.UpdateOptions{}) if err != nil { if apierrors.IsConflict(err) { return machineutils.ConflictRetry, err @@ -2465,35 +2494,18 @@ func (c *controller) stopMachinePreservation(ctx context.Context, machine *v1alp return machineutils.ShortRetry, err } klog.V(2).Infof("Updated Node Condition NodePreserved for node %s, for machine %q, successfully", node.Name, machine.Name) - } - clone := machine.DeepCopy() - clone.Status.CurrentStatus = v1alpha1.CurrentStatus{ - Phase: machine.Status.CurrentStatus.Phase, - LastUpdateTime: metav1.Now(), - PreserveExpiryTime: metav1.Time{}, - } - updatedMachine, err := c.controlMachineClient.Machines(clone.Namespace).UpdateStatus(ctx, clone, metav1.UpdateOptions{}) - if err != nil { - klog.Errorf("Machine/status UPDATE failed for machine %q. Retrying, error: %s", clone.Name, err) - if apierrors.IsConflict(err) { - return machineutils.ConflictRetry, err + // remove CA annotation from node, values do not matter here + CAAnnotations := make(map[string]string) + CAAnnotations[autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationKey] = "" + updatedNode, _, _ = annotations.RemoveAnnotation(updatedNode, CAAnnotations) // error can be ignored, always returns nil + _, err = c.targetCoreClient.CoreV1().Nodes().Update(ctx, updatedNode, metav1.UpdateOptions{}) + if err != nil { + klog.Errorf("error trying to update node %q: %v", nodeName, err) + if apierrors.IsConflict(err) { + return machineutils.ConflictRetry, err + } + return machineutils.ShortRetry, err } - return machineutils.ShortRetry, err } - klog.V(2).Infof("Machine %q status updated to stop preservation ", updatedMachine.Name) - // TODO@thiyyakat: if machine was in failed state and machinehealthtimeout has not expired, then it should - // continue to be in Failed. Normal flow is not changed. - //// if machine is in failed state transition to Terminating - //if updatedMachine.Status.CurrentStatus.Phase == v1alpha1.MachineFailed { - // err = c.controlMachineClient.Machines(c.namespace).Delete(ctx, updatedMachine.Name, metav1.DeleteOptions{}) - // if err != nil { - // klog.Errorf("error trying to delete machine %q: %v", updatedMachine.Name, err) - // if apierrors.IsConflict(err) { - // return machineutils.ConflictRetry, err - // } - // return machineutils.ShortRetry, err - // } - // klog.V(2).Infof("Machine %q marked for deletion", updatedMachine.Name) - //} return machineutils.LongRetry, nil } diff --git a/pkg/util/provider/machineutils/utils.go b/pkg/util/provider/machineutils/utils.go index c20f62706..c6ae70efa 100644 --- a/pkg/util/provider/machineutils/utils.go +++ b/pkg/util/provider/machineutils/utils.go @@ -143,6 +143,11 @@ func IsMachineTriggeredForDeletion(m *v1alpha1.Machine) bool { // IsPreserveExpiryTimeSet checks if machine is preserved by MCM func IsPreserveExpiryTimeSet(m *v1alpha1.Machine) bool { + //klog.V(3).Infof("DEBUG: machine:%s, time=%v, IsZero=%v, Unix=%d", + // m.Name, + // m.Status.CurrentStatus.PreserveExpiryTime, + // m.Status.CurrentStatus.PreserveExpiryTime.IsZero(), + // m.Status.CurrentStatus.PreserveExpiryTime.Unix()) return !m.Status.CurrentStatus.PreserveExpiryTime.IsZero() } From ee1afa2eabb7ef9b1d98289a6f1d316f11526c42 Mon Sep 17 00:00:00 2001 From: thiyyakat Date: Wed, 19 Nov 2025 15:27:15 +0530 Subject: [PATCH 13/43] Fix return for reconcileMachineHealth. Unit tests passing --- pkg/apis/machine/types.go | 2 +- pkg/apis/machine/v1alpha1/machine_types.go | 3 --- pkg/apis/machine/v1alpha1/shared_types.go | 2 +- pkg/controller/machineset.go | 20 ------------------- .../machinecontroller/machine_util.go | 17 +++++++++------- 5 files changed, 12 insertions(+), 32 deletions(-) diff --git a/pkg/apis/machine/types.go b/pkg/apis/machine/types.go index 03c09f9d9..d0cf1de77 100644 --- a/pkg/apis/machine/types.go +++ b/pkg/apis/machine/types.go @@ -97,7 +97,7 @@ type MachineConfiguration struct { // MachineInPlaceUpdateTimeout is the timeout after which in-place update is declared failed. MachineInPlaceUpdateTimeout *metav1.Duration - // MachinePreserveTimeout is the timeout after the machine preservation is stopped + // MachinePreserveTimeout is the timeout after which the machine preservation is stopped // +optional MachinePreserveTimeout *metav1.Duration `json:"preserveTimeout,omitempty"` // DisableHealthTimeout if set to true, health timeout will be ignored. Leading to machine never being declared failed. diff --git a/pkg/apis/machine/v1alpha1/machine_types.go b/pkg/apis/machine/v1alpha1/machine_types.go index eee38e3a5..49753259f 100644 --- a/pkg/apis/machine/v1alpha1/machine_types.go +++ b/pkg/apis/machine/v1alpha1/machine_types.go @@ -204,9 +204,6 @@ const ( // MachineOperationDelete indicates that the operation was a delete MachineOperationDelete MachineOperationType = "Delete" - - // MachineOperationPreserve indicates that the operation was a preserve - MachineOperationPreserve MachineOperationType = "Preserve" ) // The below types are used by kube_client and api_server. diff --git a/pkg/apis/machine/v1alpha1/shared_types.go b/pkg/apis/machine/v1alpha1/shared_types.go index 832254149..1a673b79f 100644 --- a/pkg/apis/machine/v1alpha1/shared_types.go +++ b/pkg/apis/machine/v1alpha1/shared_types.go @@ -44,7 +44,7 @@ type MachineConfiguration struct { // +optional MachineInPlaceUpdateTimeout *metav1.Duration `json:"inPlaceUpdateTimeout,omitempty"` - // MachinePreserveTimeout is the timeout after the machine preservation is stopped + // MachinePreserveTimeout is the timeout after which the machine preservation is stopped // +optional MachinePreserveTimeout *metav1.Duration `json:"preserveTimeout,omitempty"` diff --git a/pkg/controller/machineset.go b/pkg/controller/machineset.go index f856dbed5..d50b97ec4 100644 --- a/pkg/controller/machineset.go +++ b/pkg/controller/machineset.go @@ -345,13 +345,6 @@ func (c *controller) manageReplicas(ctx context.Context, allMachines []*v1alpha1 continue } if machineutils.IsMachineFailed(m) || machineutils.IsMachineTriggeredForDeletion(m) { - //klog.V(3).Infof("TEST: machine:%s, annot:%s, expirytimeset:%v, val: %v, has timeout: %v", m.Name, m.Annotations[machineutils.PreserveMachineAnnotationKey], m.Status.CurrentStatus.PreserveExpiryTime, machineutils.HasPreservationTimedOut(m), machineutils.HasPreservationTimedOut(m)) - //klog.V(3).Infof("TEST: machine:%s, annot:%s, expirytimeset:%v (IsSet=%v), has timed out: %v", - // m.Name, - // m.Annotations[machineutils.PreserveMachineAnnotationKey], - // m.Status.CurrentStatus.PreserveExpiryTime, - // machineutils.IsPreserveExpiryTimeSet(m), // ← Actually call the function! - // machineutils.HasPreservationTimedOut(m)) if machineutils.IsPreserveExpiryTimeSet(m) && !machineutils.HasPreservationTimedOut(m) { klog.V(2).Infof("Machine %s currently preserved, not adding to stale machines", m.Name) activeMachines = append(activeMachines, m) @@ -478,18 +471,6 @@ func (c *controller) manageReplicas(ctx context.Context, allMachines []*v1alpha1 logMachinesWithPriority1(activeMachines) machinesToDelete := getMachinesToDelete(activeMachines, diff) logMachinesToDelete(machinesToDelete) - //if machines are preserved, stop preservation - //for _, mc := range machinesToDelete { - // if machineutils.IsPreserveExpiryTimeSet(mc) { - // - // } - // - //}for _, mc := range machinesToDelete { - // if machineutils.IsPreserveExpiryTimeSet(mc) { - // - // } - // - //} // Snapshot the UIDs (ns/name) of the machines we're expecting to see // deleted, so we know to record their expectations exactly once either @@ -702,7 +683,6 @@ func slowStartBatch(count int, initialBatchSize int, fn func() error) (int, erro return successes, nil } -// TODO@thiyyakat: ensure preserved machines are the last to be deleted func getMachinesToDelete(filteredMachines []*v1alpha1.Machine, diff int) []*v1alpha1.Machine { // No need to sort machines if we are about to delete all of them. // diff will always be <= len(filteredMachines), so not need to handle > case. diff --git a/pkg/util/provider/machinecontroller/machine_util.go b/pkg/util/provider/machinecontroller/machine_util.go index 985cf3275..7a2a75b0e 100644 --- a/pkg/util/provider/machinecontroller/machine_util.go +++ b/pkg/util/provider/machinecontroller/machine_util.go @@ -1170,17 +1170,20 @@ func (c *controller) reconcileMachineHealth(ctx context.Context, machine *v1alph return machineutils.ConflictRetry, err } return machineutils.ShortRetry, err + } else { + klog.V(2).Infof("Machine Phase/Conditions have been updated for %q with providerID %q and are in sync with backing node %q", updatedMachine.Name, getProviderID(updatedMachine), getNodeName(updatedMachine)) + if val, exists := updatedMachine.Annotations[machineutils.PreserveMachineAnnotationKey]; exists && val == machineutils.PreserveMachineAnnotationValueWhenFailed && (updatedMachine.Status.CurrentStatus.Phase != v1alpha1.MachineInPlaceUpdating) { + retry, err := c.preserveMachine(ctx, updatedMachine, machineutils.PreserveMachineAnnotationValueWhenFailed) + if err != nil { + return retry, err + } + } + err = errSuccessfulPhaseUpdate } - - klog.V(2).Infof("Machine Phase/Conditions have been updated for %q with providerID %q and are in sync with backing node %q", updatedMachine.Name, getProviderID(updatedMachine), getNodeName(updatedMachine)) - if val, exists := updatedMachine.Annotations[machineutils.PreserveMachineAnnotationKey]; exists && val == machineutils.PreserveMachineAnnotationValueWhenFailed && (updatedMachine.Status.CurrentStatus.Phase != v1alpha1.MachineInPlaceUpdating) { - return c.preserveMachine(ctx, updatedMachine, machineutils.PreserveMachineAnnotationValueWhenFailed) - } + return machineutils.ShortRetry, err // TODO@thiyyakat: fix this. check earlier code. // Return error to end the reconcile - err = errSuccessfulPhaseUpdate } - return machineutils.LongRetry, nil } From bb515d9fc877579e5fe4e71ca03b27e593877aff Mon Sep 17 00:00:00 2001 From: thiyyakat Date: Wed, 19 Nov 2025 15:30:33 +0530 Subject: [PATCH 14/43] Update CRDs --- docs/documents/apis.md | 2 +- kubernetes/crds/machine.sapcloud.io_machinedeployments.yaml | 4 ++-- kubernetes/crds/machine.sapcloud.io_machines.yaml | 4 ++-- kubernetes/crds/machine.sapcloud.io_machinesets.yaml | 4 ++-- pkg/openapi/openapi_generated.go | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/documents/apis.md b/docs/documents/apis.md index a9be985cb..f629c3f8b 100644 --- a/docs/documents/apis.md +++ b/docs/documents/apis.md @@ -1097,7 +1097,7 @@ Kubernetes meta/v1.Duration (Optional) -

MachinePreserveTimeout is the timeout after the machine preservation is stopped

+

MachinePreserveTimeout is the timeout after which the machine preservation is stopped

diff --git a/kubernetes/crds/machine.sapcloud.io_machinedeployments.yaml b/kubernetes/crds/machine.sapcloud.io_machinedeployments.yaml index 848dc96ce..39c59908d 100644 --- a/kubernetes/crds/machine.sapcloud.io_machinedeployments.yaml +++ b/kubernetes/crds/machine.sapcloud.io_machinedeployments.yaml @@ -420,8 +420,8 @@ spec: type: object type: object preserveTimeout: - description: MachinePreserveTimeout is the timeout after the - machine preservation is stopped + description: MachinePreserveTimeout is the timeout after which + the machine preservation is stopped type: string providerID: description: ProviderID represents the provider's unique ID diff --git a/kubernetes/crds/machine.sapcloud.io_machines.yaml b/kubernetes/crds/machine.sapcloud.io_machines.yaml index 1d9150c4d..6e75f1441 100644 --- a/kubernetes/crds/machine.sapcloud.io_machines.yaml +++ b/kubernetes/crds/machine.sapcloud.io_machines.yaml @@ -217,8 +217,8 @@ spec: type: object type: object preserveTimeout: - description: MachinePreserveTimeout is the timeout after the machine - preservation is stopped + description: MachinePreserveTimeout is the timeout after which the + machine preservation is stopped type: string providerID: description: ProviderID represents the provider's unique ID given diff --git a/kubernetes/crds/machine.sapcloud.io_machinesets.yaml b/kubernetes/crds/machine.sapcloud.io_machinesets.yaml index 6dcc797c1..4f7d82cd4 100644 --- a/kubernetes/crds/machine.sapcloud.io_machinesets.yaml +++ b/kubernetes/crds/machine.sapcloud.io_machinesets.yaml @@ -302,8 +302,8 @@ spec: type: object type: object preserveTimeout: - description: MachinePreserveTimeout is the timeout after the - machine preservation is stopped + description: MachinePreserveTimeout is the timeout after which + the machine preservation is stopped type: string providerID: description: ProviderID represents the provider's unique ID diff --git a/pkg/openapi/openapi_generated.go b/pkg/openapi/openapi_generated.go index fe95775f3..60a1d1fb0 100644 --- a/pkg/openapi/openapi_generated.go +++ b/pkg/openapi/openapi_generated.go @@ -690,7 +690,7 @@ func schema_pkg_apis_machine_v1alpha1_MachineConfiguration(ref common.ReferenceC }, "preserveTimeout": { SchemaProps: spec.SchemaProps{ - Description: "MachinePreserveTimeout is the timeout after the machine preservation is stopped", + Description: "MachinePreserveTimeout is the timeout after which the machine preservation is stopped", Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Duration"), }, }, @@ -1476,7 +1476,7 @@ func schema_pkg_apis_machine_v1alpha1_MachineSpec(ref common.ReferenceCallback) }, "preserveTimeout": { SchemaProps: spec.SchemaProps{ - Description: "MachinePreserveTimeout is the timeout after the machine preservation is stopped", + Description: "MachinePreserveTimeout is the timeout after which the machine preservation is stopped", Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Duration"), }, }, From f462f8f99bd7d497251f1bcea4c043c51ad081cf Mon Sep 17 00:00:00 2001 From: thiyyakat Date: Mon, 24 Nov 2025 16:17:51 +0530 Subject: [PATCH 15/43] Fix bug causing repeated requeuing --- pkg/apis/machine/v1alpha1/machine_types.go | 2 + pkg/controller/machineset.go | 1 - .../provider/machinecontroller/machine.go | 46 ++- .../machinecontroller/machine_util.go | 276 ++++++++++++------ pkg/util/provider/machineutils/utils.go | 23 -- 5 files changed, 217 insertions(+), 131 deletions(-) diff --git a/pkg/apis/machine/v1alpha1/machine_types.go b/pkg/apis/machine/v1alpha1/machine_types.go index 49753259f..057fd95f1 100644 --- a/pkg/apis/machine/v1alpha1/machine_types.go +++ b/pkg/apis/machine/v1alpha1/machine_types.go @@ -247,6 +247,8 @@ const ( const ( // NodePreserved is a node condition type for preservation of machines to allow end-user to know that a node is preserved NodePreserved corev1.NodeConditionType = "NodePreserved" + + // ) // CurrentStatus contains information about the current status of Machine. diff --git a/pkg/controller/machineset.go b/pkg/controller/machineset.go index d50b97ec4..aee35d059 100644 --- a/pkg/controller/machineset.go +++ b/pkg/controller/machineset.go @@ -352,7 +352,6 @@ func (c *controller) manageReplicas(ctx context.Context, allMachines []*v1alpha1 } else if val, exists := m.Annotations[machineutils.PreserveMachineAnnotationKey]; exists && val == machineutils.PreserveMachineAnnotationValueWhenFailed { // this is the case where the machine controller has not had a chance to update the preserve expiry time on failure of machine causing a race condition klog.V(2).Infof("Machine %s currently preserved, not adding to stale machines", m.Name) activeMachines = append(activeMachines, m) - } else { staleMachines = append(staleMachines, m) } diff --git a/pkg/util/provider/machinecontroller/machine.go b/pkg/util/provider/machinecontroller/machine.go index eb6d76021..d61606f90 100644 --- a/pkg/util/provider/machinecontroller/machine.go +++ b/pkg/util/provider/machinecontroller/machine.go @@ -9,6 +9,7 @@ import ( "context" "errors" "fmt" + "github.com/gardener/machine-controller-manager/pkg/util/nodeops" "maps" "slices" "strings" @@ -744,7 +745,6 @@ func (c *controller) isCreationProcessing(machine *v1alpha1.Machine) bool { // - failed machine, already preserved, check for timeout // // Auto-preserve case will have to be handled where machine moved from Unknown to Failed - func (c *controller) machinePreservation(ctx context.Context, machine *v1alpha1.Machine) (machineutils.RetryPeriod, error) { // check effective preservation value based on node's and machine's annotations. updatedMachine, preserveValue, err := c.syncEffectivePreserveAnnotationValue(ctx, machine) @@ -752,23 +752,27 @@ func (c *controller) machinePreservation(ctx context.Context, machine *v1alpha1. klog.Errorf("Error getting preserve annotation value for machine %q: %s", machine.Name, err) return machineutils.ShortRetry, err } - preserveExpiryTimeSet := machineutils.IsPreserveExpiryTimeSet(updatedMachine) switch preserveValue { case machineutils.PreserveMachineAnnotationValueNow, machineutils.PreserveMachineAnnotationValueWhenFailed: - if !preserveExpiryTimeSet { - return c.preserveMachine(ctx, updatedMachine, preserveValue) - } else if metav1.Now().After(updatedMachine.Status.CurrentStatus.PreserveExpiryTime.Time) { - return c.stopMachinePreservation(ctx, updatedMachine) + if preserveValue == machineutils.PreserveMachineAnnotationValueWhenFailed && !machineutils.IsMachineFailed(updatedMachine) { + return machineutils.LongRetry, nil } - case machineutils.PreserveMachineAnnotationValueFalse: - if preserveExpiryTimeSet { + isComplete, err := c.isMachinePreservationComplete(ctx, machine) + if err != nil { + return machineutils.ShortRetry, err + } + if !isComplete { + return c.preserveMachine(ctx, machine) + } + if hasMachinePreservationTimedOut(machine) { return c.stopMachinePreservation(ctx, updatedMachine) } + case machineutils.PreserveMachineAnnotationValueFalse: + return c.stopMachinePreservation(ctx, updatedMachine) case "": return machineutils.LongRetry, nil default: - klog.V(3).Infof("Annotation value %s not part of accepted values for preserve", preserveValue) - return machineutils.LongRetry, nil + klog.Warningf("Preserve annotation value %s on machine %s is invalid", preserveValue, machine.Name) } return machineutils.LongRetry, nil } @@ -817,6 +821,28 @@ func (c *controller) syncEffectivePreserveAnnotationValue(ctx context.Context, m return machine, "", nil } +func (c *controller) isMachinePreservationComplete(ctx context.Context, machine *v1alpha1.Machine) (bool, error) { + // if preservetime is set and machine is not failed, then yes, + // if preservetime is set and machine is failed, the node condition must be there saying drain successful + // if preserve time is not set, then no + if !machineutils.IsPreserveExpiryTimeSet(machine) { + return false, nil + } else if machineutils.IsMachineFailed(machine) { + node, err := c.nodeLister.Get(getNodeName(machine)) + if err != nil { + klog.Errorf("error trying to get node %q: %v", getNodeName(machine), err) + return false, err + } + if cond := nodeops.GetCondition(node, v1alpha1.NodePreserved); cond != nil { + if cond.Reason == v1alpha1.DrainSuccessful { + return true, nil + } + } + return false, nil + } + return true, nil +} + // getMachineDeploymentForMachine returns the machine deployment for a given machine func (c *controller) getMachineDeploymentForMachine(machine *v1alpha1.Machine) (*v1alpha1.MachineDeployment, error) { machineDeploymentName := getMachineDeploymentName(machine) diff --git a/pkg/util/provider/machinecontroller/machine_util.go b/pkg/util/provider/machinecontroller/machine_util.go index 7a2a75b0e..ac31d5411 100644 --- a/pkg/util/provider/machinecontroller/machine_util.go +++ b/pkg/util/provider/machinecontroller/machine_util.go @@ -212,6 +212,7 @@ func nodeConditionsHaveChanged(oldConditions []v1.NodeCondition, newConditions [ if !exists || (oldC.Status != c.Status) || (c.Type == v1alpha1.NodeInPlaceUpdate && oldC.Reason != c.Reason) { addedOrUpdatedConditions = append(addedOrUpdatedConditions, c) } + } // checking for any deleted condition @@ -1104,9 +1105,9 @@ func (c *controller) reconcileMachineHealth(ctx context.Context, machine *v1alph if err != nil { return retry, err } - if val, exists := machine.Annotations[machineutils.PreserveMachineAnnotationKey]; exists && val == machineutils.PreserveMachineAnnotationValueWhenFailed { - return c.preserveMachine(ctx, machine, val) - } + //if attemptMachinePreservation(machine) && !machineutils.IsPreserveExpiryTimeSet(machine) { + // return c.preserveMachine(ctx, machine) + //} return retry, err } @@ -1172,12 +1173,6 @@ func (c *controller) reconcileMachineHealth(ctx context.Context, machine *v1alph return machineutils.ShortRetry, err } else { klog.V(2).Infof("Machine Phase/Conditions have been updated for %q with providerID %q and are in sync with backing node %q", updatedMachine.Name, getProviderID(updatedMachine), getNodeName(updatedMachine)) - if val, exists := updatedMachine.Annotations[machineutils.PreserveMachineAnnotationKey]; exists && val == machineutils.PreserveMachineAnnotationValueWhenFailed && (updatedMachine.Status.CurrentStatus.Phase != v1alpha1.MachineInPlaceUpdating) { - retry, err := c.preserveMachine(ctx, updatedMachine, machineutils.PreserveMachineAnnotationValueWhenFailed) - if err != nil { - return retry, err - } - } err = errSuccessfulPhaseUpdate } return machineutils.ShortRetry, err @@ -1635,15 +1630,8 @@ func (c *controller) drainNode(ctx context.Context, deleteMachineRequest *driver if skipDrain { state = v1alpha1.MachineStateProcessing } else { - if machineutils.IsPreserveExpiryTimeSet(machine) { - preserveStartTime := machine.Status.CurrentStatus.PreserveExpiryTime.Time.Add(-c.getEffectiveMachinePreserveTimeout(machine).Duration) - timeOutOccurred = utiltime.HasTimeOutOccurred( - metav1.Time{Time: preserveStartTime}, - timeOutDuration, - ) - } else { - timeOutOccurred = utiltime.HasTimeOutOccurred(*machine.DeletionTimestamp, timeOutDuration) - } + timeOutOccurred = utiltime.HasTimeOutOccurred(*machine.DeletionTimestamp, timeOutDuration) + if forceDeleteLabelPresent || timeOutOccurred { // To perform forceful machine drain/delete either one of the below conditions must be satified // 1. force-deletion: "True" label must be present @@ -1724,12 +1712,7 @@ func (c *controller) drainNode(ctx context.Context, deleteMachineRequest *driver if forceDeletePods { description = fmt.Sprintf("Force Drain successful. %s", machineutils.DelVolumesAttachments) } else { // regular drain already waits for vol detach and attach for another node. - if machineutils.IsPreserveExpiryTimeSet(machine) { - description = fmt.Sprintf("Drain successful. Machine preserved.") - } else { - description = fmt.Sprintf("Drain successful. %s", machineutils.InitiateVMDeletion) - } - + description = fmt.Sprintf("Drain successful. %s", machineutils.InitiateVMDeletion) } err = fmt.Errorf("%s", description) state = v1alpha1.MachineStateProcessing @@ -2377,45 +2360,22 @@ func (c *controller) fetchMatchingNodeName(machineName string) (string, error) { // preserveMachine contains logic to start the preservation of a machine and node. It syncs node annotations to the machine if the backing node exists, // or has an annotation related to preservation. // it does not sync preserve annotation values from machine to node to prevent bi-directional syncing issues. -func (c *controller) preserveMachine(ctx context.Context, machine *v1alpha1.Machine, preserveValue string) (machineutils.RetryPeriod, error) { - if !machineutils.ShouldMachineBePreservedNow(machine, preserveValue) { - return machineutils.LongRetry, nil - } - clone := machine.DeepCopy() - clone.Status.CurrentStatus = v1alpha1.CurrentStatus{ - Phase: clone.Status.CurrentStatus.Phase, - LastUpdateTime: metav1.Now(), - PreserveExpiryTime: metav1.NewTime(metav1.Now().Add(c.getEffectiveMachinePreserveTimeout(machine).Duration)), - } - updatedMachine, err := c.controlMachineClient.Machines(clone.Namespace).UpdateStatus(ctx, clone, metav1.UpdateOptions{}) - if err != nil { - klog.Errorf("machine status UPDATE failed for machine %q. Retrying, error: %s", machine.Name, err) - if apierrors.IsConflict(err) { - return machineutils.ConflictRetry, err - } - return machineutils.ShortRetry, err - } - klog.V(2).Infof("Machine %q preserved till %v.", machine.Name, updatedMachine.Status.CurrentStatus.PreserveExpiryTime) - if updatedMachine.Status.CurrentStatus.Phase == v1alpha1.MachineFailed { - // Validate MachineClass - machineClass, secretData, retry, err := c.ValidateMachineClass(ctx, &machine.Spec.Class) +func (c *controller) preserveMachine(ctx context.Context, machine *v1alpha1.Machine) (machineutils.RetryPeriod, error) { + klog.V(3).Infof("Entering preserve machine") + if !machineutils.IsPreserveExpiryTimeSet(machine) { + preservedCurrentStatus := v1alpha1.CurrentStatus{ + Phase: machine.Status.CurrentStatus.Phase, + LastUpdateTime: metav1.Now(), + PreserveExpiryTime: metav1.NewTime(metav1.Now().Add(c.getEffectiveMachinePreserveTimeout(machine).Duration)), + } + retry, err := c.machineStatusUpdate(ctx, machine, machine.Status.LastOperation, preservedCurrentStatus, machine.Status.LastKnownState) if err != nil { - klog.Errorf("cannot reconcile machine %s: %s", machine.Name, err) - return retry, err - } - - deleteMachineRequest := &driver.DeleteMachineRequest{ - Machine: updatedMachine, - MachineClass: machineClass, - Secret: &v1.Secret{Data: secretData}, - } - retry, err = c.drainNode(ctx, deleteMachineRequest) - if err != nil { - klog.Errorf("error draining node backing machine: %s, error:%s", updatedMachine.Name, err) + klog.Errorf("machine PreserveExpiryTime UPDATE failed for machine %q. Retrying, error: %s", machine.Name, err) return retry, err } + klog.V(2).Infof("Machine %q preserved till %v.", machine.Name, preservedCurrentStatus.PreserveExpiryTime) } - // TODO@thiyyakat: may need to change this check to machine.Spec.ProviderID + if machine.Labels[v1alpha1.NodeLabelKey] != "" { nodeName := machine.Labels[v1alpha1.NodeLabelKey] node, err := c.nodeLister.Get(nodeName) @@ -2423,57 +2383,73 @@ func (c *controller) preserveMachine(ctx context.Context, machine *v1alpha1.Mach klog.Errorf("error trying to get node %q: %v", nodeName, err) return machineutils.ShortRetry, err } - - preservedCondition := v1.NodeCondition{ + nodeCopy := node.DeepCopy() + // not updating node's preserve annotations here in case operator is manipulating machine annotations only + // if node annotation is updated, machine annotation will be overwritten with this value even if operator wants it to change + // function never returns error, can be ignored + if nodeCopy.Annotations[autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationKey] != autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationValue { + CAScaleDownAnnotation := make(map[string]string) + CAScaleDownAnnotation[autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationKey] = autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationValue + updatedNode, _, _ := annotations.AddOrUpdateAnnotation(nodeCopy, CAScaleDownAnnotation) + updatedNode, err = c.targetCoreClient.CoreV1().Nodes().Update(ctx, updatedNode, metav1.UpdateOptions{}) + if err != nil { + if apierrors.IsConflict(err) { + return machineutils.ConflictRetry, err + } + klog.Errorf("node UPDATE failed for machine %s with node %s. Retrying, error: %s", machine.Name, nodeName, err) + return machineutils.ShortRetry, err + } + klog.V(2).Infof("Updated CA annotations for node %s, for machine %q, successfully", nodeCopy.Name, machine.Name) + } + newNodePreservedCondition := v1.NodeCondition{ Type: v1alpha1.NodePreserved, Status: v1.ConditionTrue, LastTransitionTime: metav1.Now(), } - updatedNode := nodeops.AddOrUpdateCondition(node, preservedCondition) - _, err = c.targetCoreClient.CoreV1().Nodes().UpdateStatus(ctx, updatedNode, metav1.UpdateOptions{}) - if err != nil { - if apierrors.IsConflict(err) { - return machineutils.ConflictRetry, err + // drain node only if machine has failed + if machine.Status.CurrentStatus.Phase == v1alpha1.MachineFailed { + existingNodePreservedCondition, err := nodeops.GetNodeCondition(ctx, c.targetCoreClient, getNodeName(machine), v1alpha1.NodePreserved) + if err != nil { + klog.V(3).Infof("Error trying to get node preserved condition for machine %s: %v", machine.Name, err) + return machineutils.ShortRetry, err } - klog.Errorf("Node Status UPDATE failed for machine %s with node %s. Retrying, error: %s", machine.Name, nodeName, err) - return machineutils.ShortRetry, err - } - klog.V(2).Infof("Updated Node Condition NodePreserved for node %s, for machine %q, successfully", node.Name, machine.Name) - // not updating node's preserve annotations here in case operator is manipulating machine annotations only - // if node annotation is updated, machine annotation will be overwritten with this value even if operator wants it to change - // function never returns error, can be ignored - CAScaleDownAnnotation := make(map[string]string) - CAScaleDownAnnotation[autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationKey] = autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationValue - updatedNode, _, _ = annotations.AddOrUpdateAnnotation(node, CAScaleDownAnnotation) - updatedNode, err = c.targetCoreClient.CoreV1().Nodes().Update(ctx, updatedNode, metav1.UpdateOptions{}) - if err != nil { - if apierrors.IsConflict(err) { - return machineutils.ConflictRetry, err + if existingNodePreservedCondition == nil || existingNodePreservedCondition.Reason != v1alpha1.DrainSuccessful { + + err = c.drainPreservedNode(ctx, machine) + if err != nil { + klog.V(3).Infof("TEST: drain failed with error:%s", err) + // drain not successful, retry + // if node condition of NodePreserved is not set, set it: + newNodePreservedCondition.Status = v1.ConditionUnknown + if existingNodePreservedCondition == nil { + if err = nodeops.AddOrUpdateConditionsOnNode(ctx, c.targetCoreClient, getNodeName(machine), newNodePreservedCondition); err != nil { + klog.V(3).Infof("TEST: updating node with preserved condition failed: %s", err) + return machineutils.ShortRetry, err + } + } + return machineutils.ShortRetry, err + } + newNodePreservedCondition.Reason = v1alpha1.DrainSuccessful + } else { + klog.V(3).Infof("TEST: unnecessary entry into preserved machine %s", machine.Name) + return machineutils.LongRetry, nil } - klog.Errorf("node UPDATE failed for machine %s with node %s. Retrying, error: %s", machine.Name, nodeName, err) + } + klog.V(2).Infof("TEST: drainPreservedNode Successful %s", machine.Name) + if err = nodeops.AddOrUpdateConditionsOnNode(ctx, c.targetCoreClient, getNodeName(machine), newNodePreservedCondition); err != nil { + klog.V(3).Infof("TEST: updating node with preserved condition failed: %s", err) return machineutils.ShortRetry, err } - klog.V(2).Infof("Updated CA annotations for node %s, for machine %q, successfully", node.Name, machine.Name) - + klog.V(2).Infof("TEST: update drain condition %s, Successful %s", newNodePreservedCondition.Reason, machine.Name) } return machineutils.LongRetry, nil } + func (c *controller) stopMachinePreservation(ctx context.Context, machine *v1alpha1.Machine) (machineutils.RetryPeriod, error) { - clone := machine.DeepCopy() - clone.Status.CurrentStatus = v1alpha1.CurrentStatus{ - Phase: machine.Status.CurrentStatus.Phase, - LastUpdateTime: metav1.Now(), - PreserveExpiryTime: metav1.Time{}, - } - updatedMachine, err := c.controlMachineClient.Machines(clone.Namespace).UpdateStatus(ctx, clone, metav1.UpdateOptions{}) - if err != nil { - klog.Errorf("Machine/status UPDATE failed for machine %q. Retrying, error: %s", clone.Name, err) - if apierrors.IsConflict(err) { - return machineutils.ConflictRetry, err - } - return machineutils.ShortRetry, err + // check if preserveExpiryTime is set, if not, no need to do anything + if !machineutils.IsPreserveExpiryTimeSet(machine) { + return machineutils.LongRetry, nil } - klog.V(2).Infof("Machine %q status updated to stop preservation ", updatedMachine.Name) // if backing node exists, remove annotations that would prevent scale down by autoscaler if machine.Labels[v1alpha1.NodeLabelKey] != "" { // TODO@thiyyakat: may need to change this check to machine.Spec.ProviderID nodeName := machine.Labels[v1alpha1.NodeLabelKey] @@ -2510,5 +2486,111 @@ func (c *controller) stopMachinePreservation(ctx context.Context, machine *v1alp return machineutils.ShortRetry, err } } + clone := machine.DeepCopy() + clone.Status.CurrentStatus = v1alpha1.CurrentStatus{ + Phase: machine.Status.CurrentStatus.Phase, + LastUpdateTime: metav1.Now(), + PreserveExpiryTime: metav1.Time{}, + } + updatedMachine, err := c.controlMachineClient.Machines(clone.Namespace).UpdateStatus(ctx, clone, metav1.UpdateOptions{}) + if err != nil { + klog.Errorf("Machine/status UPDATE failed for machine %q. Retrying, error: %s", clone.Name, err) + if apierrors.IsConflict(err) { + return machineutils.ConflictRetry, err + } + return machineutils.ShortRetry, err + } + klog.V(2).Infof("Machine %q status updated to stop preservation ", updatedMachine.Name) return machineutils.LongRetry, nil } + +// drainPreservedNode attempts to drain the node backing a preserved machine +func (c *controller) drainPreservedNode(ctx context.Context, machine *v1alpha1.Machine) error { + var ( + // Declarations + err error + timeOutOccurred bool + forceDeletePods bool + // Initialization + maxEvictRetries = int32(math.Min(float64(*c.getEffectiveMaxEvictRetries(machine)), c.getEffectiveDrainTimeout(machine).Seconds()/drain.PodEvictionRetryInterval.Seconds())) + pvDetachTimeOut = c.safetyOptions.PvDetachTimeout.Duration + pvReattachTimeOut = c.safetyOptions.PvReattachTimeout.Duration + timeOutDuration = c.getEffectiveDrainTimeout(machine).Duration + nodeName = machine.Labels[v1alpha1.NodeLabelKey] + ) + + // verify and log node object's existence + if _, err := c.nodeLister.Get(nodeName); err == nil { + klog.V(3).Infof("(drainNode) For node %q, machine %q", nodeName, machine.Name) + } else if apierrors.IsNotFound(err) { + klog.Warningf("(drainNode) Node %q for machine %q doesn't exist, so drain will finish instantly", nodeName, machine.Name) + } + // TODO@thiyyakat: how to calculate timeout? In the case of preserve=now, preserveexpirytime will not coincide with time of failure in which case pods will et force + // drained. + timeOutOccurred = utiltime.HasTimeOutOccurred(machine.Status.CurrentStatus.PreserveExpiryTime, timeOutDuration) + if timeOutOccurred { + forceDeletePods = true + timeOutDuration = 1 * time.Minute + maxEvictRetries = 1 + klog.V(2).Infof( + "Force delete/drain has been triggerred for machine %q with providerID %q and backing node %q due to timeout:%t", + machine.Name, + getProviderID(machine), + getNodeName(machine), + timeOutOccurred, + ) + } else { + klog.V(2).Infof( + "Drain has been triggerred for preserved machine %q with providerID %q and backing node %q with drain-timeout:%v & maxEvictRetries:%d", + machine.Name, + getProviderID(machine), + getNodeName(machine), + timeOutDuration, + maxEvictRetries, + ) + } + + buf := bytes.NewBuffer([]byte{}) + errBuf := bytes.NewBuffer([]byte{}) + + drainOptions := drain.NewDrainOptions( + c.targetCoreClient, + c.targetKubernetesVersion, + timeOutDuration, + maxEvictRetries, + pvDetachTimeOut, + pvReattachTimeOut, + nodeName, + -1, + forceDeletePods, + true, + true, + true, + buf, + errBuf, + c.driver, + c.pvcLister, + c.pvLister, + c.pdbLister, + c.nodeLister, + c.podLister, + c.volumeAttachmentHandler, + c.podSynced, + ) + klog.V(3).Infof("(drainNode) Invoking RunDrain, timeOutDuration: %s", timeOutDuration) + err = drainOptions.RunDrain(ctx) + if err != nil { + klog.Warningf("Drain failed for machine %q , providerID %q ,backing node %q. \nBuf:%v \nErrBuf:%v \nErr-Message:%v", machine.Name, getProviderID(machine), getNodeName(machine), buf, errBuf, err) + return err + } + if forceDeletePods { + klog.V(3).Infof("Force drain successful for machine %q , providerID %q ,backing node %q.", machine.Name, getProviderID(machine), getNodeName(machine)) + } else { + klog.V(3).Infof("Drain successful for machine %q , providerID %q ,backing node %q.", machine.Name, getProviderID(machine), getNodeName(machine)) + } + return nil +} + +func hasMachinePreservationTimedOut(machine *v1alpha1.Machine) bool { + return machineutils.IsPreserveExpiryTimeSet(machine) && metav1.Now().After(machine.Status.CurrentStatus.PreserveExpiryTime.Time) +} diff --git a/pkg/util/provider/machineutils/utils.go b/pkg/util/provider/machineutils/utils.go index c6ae70efa..84719cff4 100644 --- a/pkg/util/provider/machineutils/utils.go +++ b/pkg/util/provider/machineutils/utils.go @@ -143,11 +143,6 @@ func IsMachineTriggeredForDeletion(m *v1alpha1.Machine) bool { // IsPreserveExpiryTimeSet checks if machine is preserved by MCM func IsPreserveExpiryTimeSet(m *v1alpha1.Machine) bool { - //klog.V(3).Infof("DEBUG: machine:%s, time=%v, IsZero=%v, Unix=%d", - // m.Name, - // m.Status.CurrentStatus.PreserveExpiryTime, - // m.Status.CurrentStatus.PreserveExpiryTime.IsZero(), - // m.Status.CurrentStatus.PreserveExpiryTime.Unix()) return !m.Status.CurrentStatus.PreserveExpiryTime.IsZero() } @@ -160,21 +155,3 @@ func HasPreservationTimedOut(m *v1alpha1.Machine) bool { } return true } - -func ShouldMachineBePreservedNow(machine *v1alpha1.Machine, preserveValue string) bool { - isFailed := IsMachineFailed(machine) - return preserveValue == PreserveMachineAnnotationValueNow || preserveValue == PreserveMachineAnnotationValueWhenFailed && isFailed -} - -//func IsMachinePreserved(machine *v1alpha1.Machine) bool { -// val, exists := machine.Annotations[PreserveMachineAnnotationKey] -// if !exists { -// return false -// } else { -// if val == PreserveMachineAnnotationValueNow && machine.Status.CurrentStatus.PreserveExpiryTime.After(time.Now()) { -// return true -// } else if val == PreserveMachineAnnotationValueWhenFailed && IsMachineFailed(machine) { -// return true -// } -// } -//} From da2427c9b534ac19106c181ea424d5a9bef4aa6d Mon Sep 17 00:00:00 2001 From: thiyyakat Date: Wed, 26 Nov 2025 16:14:38 +0530 Subject: [PATCH 16/43] Fix drain logic in machine preservation for Unknown->Failed case: * remove use of machineStatusUpdate in machine preservation code since it uses a similarity check * introduce check of phase change in updateMachine() to initiate drain of preserved machine on failure. This check is only for preserved machines --- pkg/controller/machineset.go | 4 +- .../provider/machinecontroller/machine.go | 68 ++++++++--- .../machinecontroller/machine_util.go | 114 +++++++++++------- pkg/util/provider/machineutils/utils.go | 2 + 4 files changed, 124 insertions(+), 64 deletions(-) diff --git a/pkg/controller/machineset.go b/pkg/controller/machineset.go index aee35d059..b885f2bd8 100644 --- a/pkg/controller/machineset.go +++ b/pkg/controller/machineset.go @@ -345,11 +345,11 @@ func (c *controller) manageReplicas(ctx context.Context, allMachines []*v1alpha1 continue } if machineutils.IsMachineFailed(m) || machineutils.IsMachineTriggeredForDeletion(m) { + klog.V(2).Infof("TEST: machineutils.IsPreserveExpiryTimeSet(m): %v,machineutils.HasPreservationTimedOut(m):%v", machineutils.IsPreserveExpiryTimeSet(m), machineutils.HasPreservationTimedOut(m)) if machineutils.IsPreserveExpiryTimeSet(m) && !machineutils.HasPreservationTimedOut(m) { klog.V(2).Infof("Machine %s currently preserved, not adding to stale machines", m.Name) activeMachines = append(activeMachines, m) - continue - } else if val, exists := m.Annotations[machineutils.PreserveMachineAnnotationKey]; exists && val == machineutils.PreserveMachineAnnotationValueWhenFailed { // this is the case where the machine controller has not had a chance to update the preserve expiry time on failure of machine causing a race condition + } else if val, exists := m.Annotations[machineutils.PreserveMachineAnnotationKey]; exists && val == machineutils.PreserveMachineAnnotationValueWhenFailed { // this is in case preservation process is not complete yet klog.V(2).Infof("Machine %s currently preserved, not adding to stale machines", m.Name) activeMachines = append(activeMachines, m) } else { diff --git a/pkg/util/provider/machinecontroller/machine.go b/pkg/util/provider/machinecontroller/machine.go index d61606f90..b5034ef60 100644 --- a/pkg/util/provider/machinecontroller/machine.go +++ b/pkg/util/provider/machinecontroller/machine.go @@ -62,11 +62,20 @@ func (c *controller) updateMachine(oldObj, newObj any) { klog.Errorf("couldn't convert to machine resource from object") return } + { // TODO@thiyyakat: remove after testing + if newMachine.Labels["test-failed"] != oldMachine.Labels["test-failed"] { + c.enqueueMachine(newObj, "TEST: handling machine failure simulation UPDATE event") + } + } if preserveAnnotationsChanged(oldMachine.Annotations, newMachine.Annotations) { c.enqueueMachine(newObj, "handling machine object preservation related UPDATE event") return } + if _, exists := newMachine.Annotations[machineutils.PreserveMachineAnnotationKey]; exists && newMachine.Status.CurrentStatus.Phase == v1alpha1.MachineFailed && oldMachine.Status.CurrentStatus.Phase != newMachine.Status.CurrentStatus.Phase { + c.enqueueMachine(newObj, "handling preserved machine phase update") + } + if oldMachine.Generation == newMachine.Generation { klog.V(3).Infof("Skipping other non-spec updates for machine %s", oldMachine.Name) return @@ -213,7 +222,30 @@ func (c *controller) reconcileClusterMachine(ctx context.Context, machine *v1alp klog.Errorf("cannot reconcile machine %s: %s", machine.Name, err) return retry, err } + { //TODO@thiyyakat: remove after drain + //insert condition changing code here + if machine.Labels["test-failed"] == "true" { + node, err := c.nodeLister.Get(getNodeName(machine)) + if err != nil { + klog.V(3).Infof("TEST:Machine %q: Failed to get node %q: %v", machine.Name, machine.Name, err) + return machineutils.ShortRetry, err + } + if cond := nodeops.GetCondition(node, corev1.NodeNetworkUnavailable); cond.Status != corev1.ConditionTrue { + cond := corev1.NodeCondition{Type: corev1.NodeNetworkUnavailable, Status: corev1.ConditionTrue} + err = nodeops.AddOrUpdateConditionsOnNode(ctx, c.targetCoreClient, getNodeName(machine), cond) + if err != nil { + klog.V(2).Infof("TEST:Machine %q: Failed to change node condition %q: %v", machine.Name, machine.Name, err) + return machineutils.ShortRetry, err + } + klog.V(2).Infof("TEST:Machine %q: updated node %q condition", machine.Name, machine.Name) + } + } + } + retry, err = c.manageMachinePreservation(ctx, machine) + if err != nil { + return retry, err + } if machine.Labels[v1alpha1.NodeLabelKey] != "" && machine.Status.CurrentStatus.Phase != "" { // If reference to node object exists execute the below retry, err := c.reconcileMachineHealth(ctx, machine) @@ -745,13 +777,18 @@ func (c *controller) isCreationProcessing(machine *v1alpha1.Machine) bool { // - failed machine, already preserved, check for timeout // // Auto-preserve case will have to be handled where machine moved from Unknown to Failed -func (c *controller) machinePreservation(ctx context.Context, machine *v1alpha1.Machine) (machineutils.RetryPeriod, error) { +func (c *controller) manageMachinePreservation(ctx context.Context, machine *v1alpha1.Machine) (machineutils.RetryPeriod, error) { + klog.V(3).Infof("TEST: entering manageMachinePreservation ") // check effective preservation value based on node's and machine's annotations. - updatedMachine, preserveValue, err := c.syncEffectivePreserveAnnotationValue(ctx, machine) + updatedMachine, preserveValue, exists, err := c.syncEffectivePreserveAnnotationValue(ctx, machine) if err != nil { klog.Errorf("Error getting preserve annotation value for machine %q: %s", machine.Name, err) return machineutils.ShortRetry, err } + if !exists { + return machineutils.LongRetry, nil + } + klog.V(3).Infof("TEST: preserve:%s", preserveValue) switch preserveValue { case machineutils.PreserveMachineAnnotationValueNow, machineutils.PreserveMachineAnnotationValueWhenFailed: if preserveValue == machineutils.PreserveMachineAnnotationValueWhenFailed && !machineutils.IsMachineFailed(updatedMachine) { @@ -773,11 +810,12 @@ func (c *controller) machinePreservation(ctx context.Context, machine *v1alpha1. return machineutils.LongRetry, nil default: klog.Warningf("Preserve annotation value %s on machine %s is invalid", preserveValue, machine.Name) + return machineutils.LongRetry, nil } return machineutils.LongRetry, nil } -func (c *controller) syncEffectivePreserveAnnotationValue(ctx context.Context, machine *v1alpha1.Machine) (*v1alpha1.Machine, string, error) { +func (c *controller) syncEffectivePreserveAnnotationValue(ctx context.Context, machine *v1alpha1.Machine) (*v1alpha1.Machine, string, bool, error) { var effectivePreserveAnnotationValue string mAnnotationValue, mExists := machine.Annotations[machineutils.PreserveMachineAnnotationKey] // node annotation value, if exists, will always override and overwrite machine annotation value for preserve @@ -786,21 +824,21 @@ func (c *controller) syncEffectivePreserveAnnotationValue(ctx context.Context, m node, err := c.nodeLister.Get(nodeName) if err != nil { klog.Errorf("error trying to get node %q: %v", nodeName, err) - return machine, "", err + return machine, "", false, err } nAnnotationValue, nExists := node.Annotations[machineutils.PreserveMachineAnnotationKey] switch { case nExists && mExists: if nAnnotationValue == mAnnotationValue { - return machine, nAnnotationValue, nil + return machine, nAnnotationValue, true, nil } effectivePreserveAnnotationValue = nAnnotationValue case nExists && !mExists: effectivePreserveAnnotationValue = nAnnotationValue case mExists && !nExists: - return machine, mAnnotationValue, nil + return machine, mAnnotationValue, true, nil case !nExists && !mExists: - return machine, "", nil + return machine, "", false, nil } clone := machine.DeepCopy() if clone.Annotations == nil { @@ -810,21 +848,17 @@ func (c *controller) syncEffectivePreserveAnnotationValue(ctx context.Context, m updatedMachine, err := c.controlMachineClient.Machines(c.namespace).Update(ctx, clone, metav1.UpdateOptions{}) if err != nil { klog.Errorf("error updating machine with preserve annotations %q: %v", machine.Name, err) - return machine, "", err + return machine, "", true, err } - return updatedMachine, effectivePreserveAnnotationValue, nil - } - //if no backing node - if mExists { - return machine, mAnnotationValue, nil + return updatedMachine, effectivePreserveAnnotationValue, true, nil } - return machine, "", nil + return machine, mAnnotationValue, mExists, nil } func (c *controller) isMachinePreservationComplete(ctx context.Context, machine *v1alpha1.Machine) (bool, error) { - // if preservetime is set and machine is not failed, then yes, - // if preservetime is set and machine is failed, the node condition must be there saying drain successful - // if preserve time is not set, then no + // if PreserveExpiryTime is set and machine has not failed, then yes, + // if PreserveExpiryTime is set and machine has failed, the node condition must be there saying drain successful + // if PreserveExpiryTime is not set, then no if !machineutils.IsPreserveExpiryTimeSet(machine) { return false, nil } else if machineutils.IsMachineFailed(machine) { diff --git a/pkg/util/provider/machinecontroller/machine_util.go b/pkg/util/provider/machinecontroller/machine_util.go index ac31d5411..c2cd0804a 100644 --- a/pkg/util/provider/machinecontroller/machine_util.go +++ b/pkg/util/provider/machinecontroller/machine_util.go @@ -1014,7 +1014,8 @@ func (c *controller) reconcileMachineHealth(ctx context.Context, machine *v1alph clone.Status.CurrentStatus = v1alpha1.CurrentStatus{ Phase: v1alpha1.MachineUnknown, // TimeoutActive: true, - LastUpdateTime: metav1.Now(), + LastUpdateTime: metav1.Now(), + PreserveExpiryTime: machine.Status.CurrentStatus.PreserveExpiryTime, } clone.Status.LastOperation = v1alpha1.LastOperation{ Description: description, @@ -1105,9 +1106,6 @@ func (c *controller) reconcileMachineHealth(ctx context.Context, machine *v1alph if err != nil { return retry, err } - //if attemptMachinePreservation(machine) && !machineutils.IsPreserveExpiryTimeSet(machine) { - // return c.preserveMachine(ctx, machine) - //} return retry, err } @@ -1176,7 +1174,6 @@ func (c *controller) reconcileMachineHealth(ctx context.Context, machine *v1alph err = errSuccessfulPhaseUpdate } return machineutils.ShortRetry, err - // TODO@thiyyakat: fix this. check earlier code. // Return error to end the reconcile } return machineutils.LongRetry, nil @@ -2141,7 +2138,8 @@ func (c *controller) updateMachineToFailedState(ctx context.Context, description clone.Status.CurrentStatus = v1alpha1.CurrentStatus{ Phase: v1alpha1.MachineFailed, // TimeoutActive: false, - LastUpdateTime: metav1.Now(), + LastUpdateTime: metav1.Now(), + PreserveExpiryTime: machine.Status.CurrentStatus.PreserveExpiryTime, } _, err := c.controlMachineClient.Machines(clone.Namespace).UpdateStatus(ctx, clone, metav1.UpdateOptions{}) @@ -2361,21 +2359,23 @@ func (c *controller) fetchMatchingNodeName(machineName string) (string, error) { // or has an annotation related to preservation. // it does not sync preserve annotation values from machine to node to prevent bi-directional syncing issues. func (c *controller) preserveMachine(ctx context.Context, machine *v1alpha1.Machine) (machineutils.RetryPeriod, error) { - klog.V(3).Infof("Entering preserve machine") + klog.V(3).Infof("TEST: Entering preserve machine flow") if !machineutils.IsPreserveExpiryTimeSet(machine) { preservedCurrentStatus := v1alpha1.CurrentStatus{ Phase: machine.Status.CurrentStatus.Phase, LastUpdateTime: metav1.Now(), PreserveExpiryTime: metav1.NewTime(metav1.Now().Add(c.getEffectiveMachinePreserveTimeout(machine).Duration)), } - retry, err := c.machineStatusUpdate(ctx, machine, machine.Status.LastOperation, preservedCurrentStatus, machine.Status.LastKnownState) + clone := machine.DeepCopy() + clone.Status.CurrentStatus = preservedCurrentStatus + _, err := c.controlMachineClient.Machines(clone.Namespace).UpdateStatus(ctx, clone, metav1.UpdateOptions{}) if err != nil { - klog.Errorf("machine PreserveExpiryTime UPDATE failed for machine %q. Retrying, error: %s", machine.Name, err) - return retry, err + klog.Warningf("Machine/status UPDATE failed for machine %q. Retrying, error: %s", machine.Name, err) + return machineutils.ConflictRetry, err } - klog.V(2).Infof("Machine %q preserved till %v.", machine.Name, preservedCurrentStatus.PreserveExpiryTime) + klog.V(3).Infof("Machine %q preserved till %v.", machine.Name, preservedCurrentStatus.PreserveExpiryTime) } - + klog.V(3).Infof("TEST: preserveexpiry set for machine %q", machine.Name) if machine.Labels[v1alpha1.NodeLabelKey] != "" { nodeName := machine.Labels[v1alpha1.NodeLabelKey] node, err := c.nodeLister.Get(nodeName) @@ -2414,13 +2414,11 @@ func (c *controller) preserveMachine(ctx context.Context, machine *v1alpha1.Mach return machineutils.ShortRetry, err } if existingNodePreservedCondition == nil || existingNodePreservedCondition.Reason != v1alpha1.DrainSuccessful { - err = c.drainPreservedNode(ctx, machine) if err != nil { klog.V(3).Infof("TEST: drain failed with error:%s", err) // drain not successful, retry // if node condition of NodePreserved is not set, set it: - newNodePreservedCondition.Status = v1.ConditionUnknown if existingNodePreservedCondition == nil { if err = nodeops.AddOrUpdateConditionsOnNode(ctx, c.targetCoreClient, getNodeName(machine), newNodePreservedCondition); err != nil { klog.V(3).Infof("TEST: updating node with preserved condition failed: %s", err) @@ -2429,18 +2427,18 @@ func (c *controller) preserveMachine(ctx context.Context, machine *v1alpha1.Mach } return machineutils.ShortRetry, err } + klog.V(2).Infof("TEST: drainPreservedNode Successful %s", machine.Name) newNodePreservedCondition.Reason = v1alpha1.DrainSuccessful } else { klog.V(3).Infof("TEST: unnecessary entry into preserved machine %s", machine.Name) return machineutils.LongRetry, nil } } - klog.V(2).Infof("TEST: drainPreservedNode Successful %s", machine.Name) if err = nodeops.AddOrUpdateConditionsOnNode(ctx, c.targetCoreClient, getNodeName(machine), newNodePreservedCondition); err != nil { klog.V(3).Infof("TEST: updating node with preserved condition failed: %s", err) return machineutils.ShortRetry, err } - klog.V(2).Infof("TEST: update drain condition %s, Successful %s", newNodePreservedCondition.Reason, machine.Name) + klog.V(3).Infof("TEST: updating machine %q with new node condition was successful", machine.Name) } return machineutils.LongRetry, nil } @@ -2451,11 +2449,11 @@ func (c *controller) stopMachinePreservation(ctx context.Context, machine *v1alp return machineutils.LongRetry, nil } // if backing node exists, remove annotations that would prevent scale down by autoscaler - if machine.Labels[v1alpha1.NodeLabelKey] != "" { // TODO@thiyyakat: may need to change this check to machine.Spec.ProviderID + if machine.Labels[v1alpha1.NodeLabelKey] != "" { nodeName := machine.Labels[v1alpha1.NodeLabelKey] node, err := c.nodeLister.Get(nodeName) if err != nil { - klog.Errorf("error trying to get node %q: %v", nodeName, err) + klog.Errorf("error trying to get backing node %q for machine %s. error: %v", nodeName, machine.Name, err) return machineutils.ShortRetry, err } preservedCondition := v1.NodeCondition{ @@ -2463,23 +2461,25 @@ func (c *controller) stopMachinePreservation(ctx context.Context, machine *v1alp Status: v1.ConditionFalse, LastTransitionTime: metav1.Now(), } - updatedNode := nodeops.AddOrUpdateCondition(node, preservedCondition) - updatedNode, err = c.targetCoreClient.CoreV1().Nodes().UpdateStatus(ctx, updatedNode, metav1.UpdateOptions{}) + err = nodeops.AddOrUpdateConditionsOnNode(ctx, c.targetCoreClient, getNodeName(machine), preservedCondition) if err != nil { - if apierrors.IsConflict(err) { - return machineutils.ConflictRetry, err - } - klog.Errorf("Node Status UPDATE failed for machine %s with node %s. Retrying, error: %s", machine.Name, nodeName, err) + klog.Warningf("Node/status UPDATE failed for machine %q. Retrying, error: %s", machine.Name, err) return machineutils.ShortRetry, err } - klog.V(2).Infof("Updated Node Condition NodePreserved for node %s, for machine %q, successfully", node.Name, machine.Name) + klog.V(3).Infof("Updated Node Condition NodePreserved for node %s, for machine %q, successfully", node.Name, machine.Name) // remove CA annotation from node, values do not matter here CAAnnotations := make(map[string]string) CAAnnotations[autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationKey] = "" - updatedNode, _, _ = annotations.RemoveAnnotation(updatedNode, CAAnnotations) // error can be ignored, always returns nil - _, err = c.targetCoreClient.CoreV1().Nodes().Update(ctx, updatedNode, metav1.UpdateOptions{}) + latestNode, err := c.targetCoreClient.CoreV1().Nodes().Get(ctx, nodeName, metav1.GetOptions{}) if err != nil { - klog.Errorf("error trying to update node %q: %v", nodeName, err) + klog.Errorf("error trying to get backing node %q for machine %s. error: %v", nodeName, machine.Name, err) + return machineutils.ShortRetry, err + } + latestNodeCopy := latestNode.DeepCopy() + latestNodeCopy, _, _ = annotations.RemoveAnnotation(latestNodeCopy, CAAnnotations) // error can be ignored, always returns nil + _, err = c.targetCoreClient.CoreV1().Nodes().Update(ctx, latestNodeCopy, metav1.UpdateOptions{}) + if err != nil { + klog.Warningf("Node UPDATE failed for machine %q. Retrying, error: %s", machine.Name, err) if apierrors.IsConflict(err) { return machineutils.ConflictRetry, err } @@ -2492,15 +2492,12 @@ func (c *controller) stopMachinePreservation(ctx context.Context, machine *v1alp LastUpdateTime: metav1.Now(), PreserveExpiryTime: metav1.Time{}, } - updatedMachine, err := c.controlMachineClient.Machines(clone.Namespace).UpdateStatus(ctx, clone, metav1.UpdateOptions{}) + _, err := c.controlMachineClient.Machines(clone.Namespace).UpdateStatus(ctx, clone, metav1.UpdateOptions{}) if err != nil { - klog.Errorf("Machine/status UPDATE failed for machine %q. Retrying, error: %s", clone.Name, err) - if apierrors.IsConflict(err) { - return machineutils.ConflictRetry, err - } - return machineutils.ShortRetry, err + klog.Warningf("Machine/status UPDATE failed for machine %q. Retrying, error: %s", machine.Name, err) + return machineutils.ConflictRetry, err } - klog.V(2).Infof("Machine %q status updated to stop preservation ", updatedMachine.Name) + klog.V(3).Infof("Machine status updated to stop preservation for machine %q", clone.Name) return machineutils.LongRetry, nil } @@ -2508,16 +2505,29 @@ func (c *controller) stopMachinePreservation(ctx context.Context, machine *v1alp func (c *controller) drainPreservedNode(ctx context.Context, machine *v1alpha1.Machine) error { var ( // Declarations - err error - timeOutOccurred bool - forceDeletePods bool + err error + forceDeletePods bool + timeOutOccurred bool + description string + readOnlyFileSystemCondition, nodeReadyCondition v1.NodeCondition + // Initialization - maxEvictRetries = int32(math.Min(float64(*c.getEffectiveMaxEvictRetries(machine)), c.getEffectiveDrainTimeout(machine).Seconds()/drain.PodEvictionRetryInterval.Seconds())) - pvDetachTimeOut = c.safetyOptions.PvDetachTimeout.Duration - pvReattachTimeOut = c.safetyOptions.PvReattachTimeout.Duration - timeOutDuration = c.getEffectiveDrainTimeout(machine).Duration - nodeName = machine.Labels[v1alpha1.NodeLabelKey] + maxEvictRetries = int32(math.Min(float64(*c.getEffectiveMaxEvictRetries(machine)), c.getEffectiveDrainTimeout(machine).Seconds()/drain.PodEvictionRetryInterval.Seconds())) + pvDetachTimeOut = c.safetyOptions.PvDetachTimeout.Duration + pvReattachTimeOut = c.safetyOptions.PvReattachTimeout.Duration + timeOutDuration = c.getEffectiveDrainTimeout(machine).Duration + forceDrainLabelPresent = machine.Labels["force-drain"] == "True" + nodeName = machine.Labels[v1alpha1.NodeLabelKey] + nodeNotReadyDuration = 5 * time.Minute + ReadonlyFilesystem v1.NodeConditionType = "ReadonlyFilesystem" ) + for _, condition := range machine.Status.Conditions { + if condition.Type == v1.NodeReady { + nodeReadyCondition = condition + } else if condition.Type == ReadonlyFilesystem { + readOnlyFileSystemCondition = condition + } + } // verify and log node object's existence if _, err := c.nodeLister.Get(nodeName); err == nil { @@ -2525,10 +2535,24 @@ func (c *controller) drainPreservedNode(ctx context.Context, machine *v1alpha1.M } else if apierrors.IsNotFound(err) { klog.Warningf("(drainNode) Node %q for machine %q doesn't exist, so drain will finish instantly", nodeName, machine.Name) } + + if !isConditionEmpty(nodeReadyCondition) && (nodeReadyCondition.Status != v1.ConditionTrue) && (time.Since(nodeReadyCondition.LastTransitionTime.Time) > nodeNotReadyDuration) { + message := "Setting forceDeletePods to true for drain as machine is NotReady for over 5min" + forceDeletePods = true + printLogInitError(message, &err, &description, machine, true) + } else if !isConditionEmpty(readOnlyFileSystemCondition) && (readOnlyFileSystemCondition.Status != v1.ConditionFalse) && (time.Since(readOnlyFileSystemCondition.LastTransitionTime.Time) > nodeNotReadyDuration) { + message := "Setting forceDeletePods to true for drain as machine is in ReadonlyFilesystem for over 5min" + forceDeletePods = true + printLogInitError(message, &err, &description, machine, true) + } + // TODO@thiyyakat: how to calculate timeout? In the case of preserve=now, preserveexpirytime will not coincide with time of failure in which case pods will et force // drained. - timeOutOccurred = utiltime.HasTimeOutOccurred(machine.Status.CurrentStatus.PreserveExpiryTime, timeOutDuration) - if timeOutOccurred { + // current solution: since we want to know when machine transitioned to Failed, using lastupdatetime. + // in the case of preserve=now, preserveExpiryTime is set from the time the annotation is added, and can't tell us when + // machine moved to Failed + timeOutOccurred = utiltime.HasTimeOutOccurred(machine.Status.CurrentStatus.LastUpdateTime, timeOutDuration) + if forceDrainLabelPresent || timeOutOccurred { forceDeletePods = true timeOutDuration = 1 * time.Minute maxEvictRetries = 1 diff --git a/pkg/util/provider/machineutils/utils.go b/pkg/util/provider/machineutils/utils.go index 84719cff4..b00c01fce 100644 --- a/pkg/util/provider/machineutils/utils.go +++ b/pkg/util/provider/machineutils/utils.go @@ -6,6 +6,7 @@ package machineutils import ( + "k8s.io/klog/v2" "time" v1 "k8s.io/api/core/v1" @@ -143,6 +144,7 @@ func IsMachineTriggeredForDeletion(m *v1alpha1.Machine) bool { // IsPreserveExpiryTimeSet checks if machine is preserved by MCM func IsPreserveExpiryTimeSet(m *v1alpha1.Machine) bool { + klog.V(3).Infof("Preserve Expiry Time: %v, machine: %s", m.Status.CurrentStatus.PreserveExpiryTime, m.Name) return !m.Status.CurrentStatus.PreserveExpiryTime.IsZero() } From 0cdfc4fc087079ef6bc5e466833cb4da769543b9 Mon Sep 17 00:00:00 2001 From: thiyyakat Date: Thu, 27 Nov 2025 16:11:38 +0530 Subject: [PATCH 17/43] Fix toggle between now and when-failed when machine has not failed. --- pkg/controller/machineset.go | 5 +++-- pkg/util/provider/machinecontroller/machine.go | 4 ++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/pkg/controller/machineset.go b/pkg/controller/machineset.go index b885f2bd8..cdd863918 100644 --- a/pkg/controller/machineset.go +++ b/pkg/controller/machineset.go @@ -344,7 +344,7 @@ func (c *controller) manageReplicas(ctx context.Context, allMachines []*v1alpha1 machinesWithUpdateSuccessfulLabel = append(machinesWithUpdateSuccessfulLabel, m) continue } - if machineutils.IsMachineFailed(m) || machineutils.IsMachineTriggeredForDeletion(m) { + if machineutils.IsMachineFailed(m) { klog.V(2).Infof("TEST: machineutils.IsPreserveExpiryTimeSet(m): %v,machineutils.HasPreservationTimedOut(m):%v", machineutils.IsPreserveExpiryTimeSet(m), machineutils.HasPreservationTimedOut(m)) if machineutils.IsPreserveExpiryTimeSet(m) && !machineutils.HasPreservationTimedOut(m) { klog.V(2).Infof("Machine %s currently preserved, not adding to stale machines", m.Name) @@ -355,7 +355,8 @@ func (c *controller) manageReplicas(ctx context.Context, allMachines []*v1alpha1 } else { staleMachines = append(staleMachines, m) } - + } else if machineutils.IsMachineTriggeredForDeletion(m) { + staleMachines = append(staleMachines, m) } else if machineutils.IsMachineActive(m) { activeMachines = append(activeMachines, m) } diff --git a/pkg/util/provider/machinecontroller/machine.go b/pkg/util/provider/machinecontroller/machine.go index b5034ef60..849fcba11 100644 --- a/pkg/util/provider/machinecontroller/machine.go +++ b/pkg/util/provider/machinecontroller/machine.go @@ -791,7 +791,11 @@ func (c *controller) manageMachinePreservation(ctx context.Context, machine *v1a klog.V(3).Infof("TEST: preserve:%s", preserveValue) switch preserveValue { case machineutils.PreserveMachineAnnotationValueNow, machineutils.PreserveMachineAnnotationValueWhenFailed: + // if preserve annotation value has switched from now to when-failed, then stop preservation if preserveValue == machineutils.PreserveMachineAnnotationValueWhenFailed && !machineutils.IsMachineFailed(updatedMachine) { + if machineutils.IsPreserveExpiryTimeSet(updatedMachine) { + return c.stopMachinePreservation(ctx, updatedMachine) + } return machineutils.LongRetry, nil } isComplete, err := c.isMachinePreservationComplete(ctx, machine) From dd0c04d624caaa6a8be0652d3bcf37fa0f29d6e5 Mon Sep 17 00:00:00 2001 From: thiyyakat Date: Thu, 4 Dec 2025 11:43:22 +0530 Subject: [PATCH 18/43] Refactor changes to support auto-preservation of failed machines * Introduce new annotation value for preservation `PreserveMachineAnnotationValuePreservedByMCM` * Update Condition.Reason and Condition.Message to reflect preservation by user and auto-preservation * Update Machine Deployment Spec to include AutoPreservedFailedMachineMax * Modify MachineSet controller to update status with count of auto-preserved machines * Add updated CRDs and generated code --- docs/documents/apis.md | 70 +++++++++++++++++++ ...achine.sapcloud.io_machinedeployments.yaml | 6 ++ .../crds/machine.sapcloud.io_machinesets.yaml | 8 +++ pkg/apis/machine/types.go | 9 +++ pkg/apis/machine/v1alpha1/machine_types.go | 9 ++- .../v1alpha1/machinedeployment_types.go | 5 ++ pkg/apis/machine/v1alpha1/machineset_types.go | 7 ++ .../v1alpha1/zz_generated.conversion.go | 6 ++ pkg/controller/deployment_machineset_util.go | 8 +++ pkg/controller/deployment_sync.go | 9 +-- pkg/controller/machineset.go | 33 +++++++-- pkg/openapi/openapi_generated.go | 20 ++++++ .../machinecontroller/machine_util.go | 11 ++- pkg/util/provider/machineutils/utils.go | 4 ++ 14 files changed, 192 insertions(+), 13 deletions(-) diff --git a/docs/documents/apis.md b/docs/documents/apis.md index f629c3f8b..c6f19d3e3 100644 --- a/docs/documents/apis.md +++ b/docs/documents/apis.md @@ -513,6 +513,21 @@ not be estimated during the time a MachineDeployment is paused. This is not set by default, which is treated as infinite deadline.

+ + +autoPreserveFailedMachineMax + + + +int32 + + + +(Optional) +

The maximum number of machines in the machine deployment that will be auto-preserved. +In the gardener context, this number is derived from the AutoPreserveFailedMachineMax set at the worker level, distributed amongst the worker’s machine deployments

+ + @@ -678,6 +693,19 @@ int32 (Optional) + + +autoPreserveFailedMachineMax + + + +int32 + + + +(Optional) + + @@ -1429,6 +1457,21 @@ not be estimated during the time a MachineDeployment is paused. This is not set by default, which is treated as infinite deadline.

+ + +autoPreserveFailedMachineMax + + + +int32 + + + +(Optional) +

The maximum number of machines in the machine deployment that will be auto-preserved. +In the gardener context, this number is derived from the AutoPreserveFailedMachineMax set at the worker level, distributed amongst the worker’s machine deployments

+ +
@@ -1891,6 +1934,19 @@ int32 (Optional) + + +autoPreserveFailedMachineMax + + + +int32 + + + +(Optional) + +
@@ -2029,6 +2085,20 @@ LastOperation

FailedMachines has summary of machines on which lastOperation Failed

+ + +autoPreservedFailedMachineCount + + + +int32 + + + +(Optional) +

AutoPreservedFailedMachineCount has a count of the number of failed machines in the machineset that have been auto-preserved

+ +
diff --git a/kubernetes/crds/machine.sapcloud.io_machinedeployments.yaml b/kubernetes/crds/machine.sapcloud.io_machinedeployments.yaml index 39c59908d..555d898c4 100644 --- a/kubernetes/crds/machine.sapcloud.io_machinedeployments.yaml +++ b/kubernetes/crds/machine.sapcloud.io_machinedeployments.yaml @@ -67,6 +67,12 @@ spec: spec: description: Specification of the desired behavior of the MachineDeployment. properties: + autoPreserveFailedMachineMax: + description: |- + The maximum number of machines in the machine deployment that will be auto-preserved. + In the gardener context, this number is derived from the AutoPreserveFailedMachineMax set at the worker level, distributed amongst the worker's machine deployments + format: int32 + type: integer minReadySeconds: description: |- Minimum number of seconds for which a newly created machine should be ready diff --git a/kubernetes/crds/machine.sapcloud.io_machinesets.yaml b/kubernetes/crds/machine.sapcloud.io_machinesets.yaml index 4f7d82cd4..b76c22cc3 100644 --- a/kubernetes/crds/machine.sapcloud.io_machinesets.yaml +++ b/kubernetes/crds/machine.sapcloud.io_machinesets.yaml @@ -60,6 +60,9 @@ spec: spec: description: MachineSetSpec is the specification of a MachineSet. properties: + autoPreserveFailedMachineMax: + format: int32 + type: integer machineClass: description: ClassSpec is the class specification of machine properties: @@ -316,6 +319,11 @@ spec: description: MachineSetStatus holds the most recently observed status of MachineSet. properties: + autoPreservedFailedMachineCount: + description: AutoPreservedFailedMachineCount has a count of the number + of failed machines in the machineset that have been auto-preserved + format: int32 + type: integer availableReplicas: description: The number of available replicas (ready for at least minReadySeconds) for this replica set. diff --git a/pkg/apis/machine/types.go b/pkg/apis/machine/types.go index d0cf1de77..6c6487d78 100644 --- a/pkg/apis/machine/types.go +++ b/pkg/apis/machine/types.go @@ -357,6 +357,8 @@ type MachineSetSpec struct { Template MachineTemplateSpec MinReadySeconds int32 + + AutoPreserveFailedMachineMax int32 } // MachineSetConditionType is the condition on machineset object @@ -415,6 +417,9 @@ type MachineSetStatus struct { // FailedMachines has summary of machines on which lastOperation Failed FailedMachines *[]MachineSummary + + // AutoPreservedFailedMachineCount has a count of the number of failed machines in the machineset that have been auto-preserved + AutoPreservedFailedMachineCount int32 } // MachineSummary store the summary of machine. @@ -493,6 +498,10 @@ type MachineDeploymentSpec struct { // not be estimated during the time a MachineDeployment is paused. This is not set // by default. ProgressDeadlineSeconds *int32 + + // The maximum number of machines in the machine deployment that will be auto-preserved. + // In the gardener context, this number is derived from the AutoPreserveFailedMachineMax set at the worker level, distributed amongst the worker's machine deployments + AutoPreserveFailedMachineMax int32 } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object diff --git a/pkg/apis/machine/v1alpha1/machine_types.go b/pkg/apis/machine/v1alpha1/machine_types.go index 057fd95f1..57a532949 100644 --- a/pkg/apis/machine/v1alpha1/machine_types.go +++ b/pkg/apis/machine/v1alpha1/machine_types.go @@ -248,7 +248,14 @@ const ( // NodePreserved is a node condition type for preservation of machines to allow end-user to know that a node is preserved NodePreserved corev1.NodeConditionType = "NodePreserved" - // + // NodePreservedByMCM is a node condition reason for preservation of machines to indicate that the node is auto-preserved by MCM + NodePreservedByMCM string = "PreservedByMCM" + + //NodePreservedByUser is a node condition reason to indicate that a machine/node has been preserved due to explicit annotation by user + NodePreservedByUser string = "PreservedByUser" + + //PreservedNodeDrainSuccessful is a constant for the message in condition that indicates that the preserved node's drain is successful + PreservedNodeDrainSuccessful string = "PreservedNodeDrainSuccessful" ) // CurrentStatus contains information about the current status of Machine. diff --git a/pkg/apis/machine/v1alpha1/machinedeployment_types.go b/pkg/apis/machine/v1alpha1/machinedeployment_types.go index 1839ad866..6cebcd1a1 100644 --- a/pkg/apis/machine/v1alpha1/machinedeployment_types.go +++ b/pkg/apis/machine/v1alpha1/machinedeployment_types.go @@ -91,6 +91,11 @@ type MachineDeploymentSpec struct { // by default, which is treated as infinite deadline. // +optional ProgressDeadlineSeconds *int32 `json:"progressDeadlineSeconds,omitempty"` + + // The maximum number of machines in the machine deployment that will be auto-preserved. + // In the gardener context, this number is derived from the AutoPreserveFailedMachineMax set at the worker level, distributed amongst the worker's machine deployments + // +optional + AutoPreserveFailedMachineMax int32 `json:"autoPreserveFailedMachineMax,omitempty"` } const ( diff --git a/pkg/apis/machine/v1alpha1/machineset_types.go b/pkg/apis/machine/v1alpha1/machineset_types.go index 2e6eb1d6e..6e8cf1f03 100644 --- a/pkg/apis/machine/v1alpha1/machineset_types.go +++ b/pkg/apis/machine/v1alpha1/machineset_types.go @@ -68,6 +68,9 @@ type MachineSetSpec struct { // +optional MinReadySeconds int32 `json:"minReadySeconds,omitempty"` + + // +optional + AutoPreserveFailedMachineMax int32 `json:"autoPreserveFailedMachineMax,omitempty"` } // MachineSetConditionType is the condition on machineset object @@ -135,4 +138,8 @@ type MachineSetStatus struct { // FailedMachines has summary of machines on which lastOperation Failed // +optional FailedMachines *[]MachineSummary `json:"failedMachines,omitempty"` + + // AutoPreservedFailedMachineCount has a count of the number of failed machines in the machineset that have been auto-preserved + // +optional + AutoPreservedFailedMachineCount int32 `json:"autoPreservedFailedMachineCount,omitempty"` } diff --git a/pkg/apis/machine/v1alpha1/zz_generated.conversion.go b/pkg/apis/machine/v1alpha1/zz_generated.conversion.go index fcca5ee3f..8286caba6 100644 --- a/pkg/apis/machine/v1alpha1/zz_generated.conversion.go +++ b/pkg/apis/machine/v1alpha1/zz_generated.conversion.go @@ -660,6 +660,7 @@ func autoConvert_v1alpha1_MachineDeploymentSpec_To_machine_MachineDeploymentSpec out.Paused = in.Paused out.RollbackTo = (*machine.RollbackConfig)(unsafe.Pointer(in.RollbackTo)) out.ProgressDeadlineSeconds = (*int32)(unsafe.Pointer(in.ProgressDeadlineSeconds)) + out.AutoPreserveFailedMachineMax = in.AutoPreserveFailedMachineMax return nil } @@ -682,6 +683,7 @@ func autoConvert_machine_MachineDeploymentSpec_To_v1alpha1_MachineDeploymentSpec out.Paused = in.Paused out.RollbackTo = (*RollbackConfig)(unsafe.Pointer(in.RollbackTo)) out.ProgressDeadlineSeconds = (*int32)(unsafe.Pointer(in.ProgressDeadlineSeconds)) + out.AutoPreserveFailedMachineMax = in.AutoPreserveFailedMachineMax return nil } @@ -864,6 +866,7 @@ func autoConvert_v1alpha1_MachineSetSpec_To_machine_MachineSetSpec(in *MachineSe return err } out.MinReadySeconds = in.MinReadySeconds + out.AutoPreserveFailedMachineMax = in.AutoPreserveFailedMachineMax return nil } @@ -882,6 +885,7 @@ func autoConvert_machine_MachineSetSpec_To_v1alpha1_MachineSetSpec(in *machine.M return err } out.MinReadySeconds = in.MinReadySeconds + out.AutoPreserveFailedMachineMax = in.AutoPreserveFailedMachineMax return nil } @@ -901,6 +905,7 @@ func autoConvert_v1alpha1_MachineSetStatus_To_machine_MachineSetStatus(in *Machi return err } out.FailedMachines = (*[]machine.MachineSummary)(unsafe.Pointer(in.FailedMachines)) + out.AutoPreservedFailedMachineCount = in.AutoPreservedFailedMachineCount return nil } @@ -920,6 +925,7 @@ func autoConvert_machine_MachineSetStatus_To_v1alpha1_MachineSetStatus(in *machi return err } out.FailedMachines = (*[]MachineSummary)(unsafe.Pointer(in.FailedMachines)) + out.AutoPreservedFailedMachineCount = in.AutoPreservedFailedMachineCount return nil } diff --git a/pkg/controller/deployment_machineset_util.go b/pkg/controller/deployment_machineset_util.go index ee2250451..b41220916 100644 --- a/pkg/controller/deployment_machineset_util.go +++ b/pkg/controller/deployment_machineset_util.go @@ -99,6 +99,7 @@ func calculateMachineSetStatus(is *v1alpha1.MachineSet, filteredMachines []*v1al fullyLabeledReplicasCount := 0 readyReplicasCount := 0 availableReplicasCount := 0 + autoPreservedFailedMachineCount := 0 failedMachines := []v1alpha1.MachineSummary{} var machineSummary v1alpha1.MachineSummary @@ -124,6 +125,11 @@ func calculateMachineSetStatus(is *v1alpha1.MachineSet, filteredMachines []*v1al } failedMachines = append(failedMachines, machineSummary) } + if cond := getMachineCondition(machine, v1alpha1.NodePreserved); cond != nil { + if cond.Reason == v1alpha1.NodePreservedByMCM { + autoPreservedFailedMachineCount++ + } + } } // Update the FailedMachines field when we see new failures @@ -146,6 +152,7 @@ func calculateMachineSetStatus(is *v1alpha1.MachineSet, filteredMachines []*v1al SetCondition(&newStatus, cond) } else if manageReplicasErr == nil && failureCond != nil { RemoveCondition(&newStatus, v1alpha1.MachineSetReplicaFailure) + } else if manageReplicasErr != nil { } newStatus.Replicas = int32(len(filteredMachines)) // #nosec G115 (CWE-190) -- number of machines will not exceed MaxInt32 @@ -153,6 +160,7 @@ func calculateMachineSetStatus(is *v1alpha1.MachineSet, filteredMachines []*v1al newStatus.ReadyReplicas = int32(readyReplicasCount) // #nosec G115 (CWE-190) -- number of machines will not exceed MaxInt32 newStatus.AvailableReplicas = int32(availableReplicasCount) // #nosec G115 (CWE-190) -- number of machines will not exceed MaxInt32 newStatus.LastOperation.LastUpdateTime = metav1.Now() + newStatus.AutoPreservedFailedMachineCount = int32(autoPreservedFailedMachineCount) // #nosec G115 (CWE-190) -- number of machines will not exceed MaxInt32 return newStatus } diff --git a/pkg/controller/deployment_sync.go b/pkg/controller/deployment_sync.go index b0f13d440..e5079c393 100644 --- a/pkg/controller/deployment_sync.go +++ b/pkg/controller/deployment_sync.go @@ -311,10 +311,11 @@ func (dc *controller) getNewMachineSet(ctx context.Context, d *v1alpha1.MachineD Labels: newISTemplate.Labels, }, Spec: v1alpha1.MachineSetSpec{ - Replicas: 0, - MinReadySeconds: d.Spec.MinReadySeconds, - Selector: newISSelector, - Template: newISTemplate, + Replicas: 0, + MinReadySeconds: d.Spec.MinReadySeconds, + Selector: newISSelector, + Template: newISTemplate, + AutoPreserveFailedMachineMax: d.Spec.AutoPreserveFailedMachineMax, }, } allISs := append(oldISs, &newIS) diff --git a/pkg/controller/machineset.go b/pkg/controller/machineset.go index cdd863918..c25b4dd70 100644 --- a/pkg/controller/machineset.go +++ b/pkg/controller/machineset.go @@ -344,19 +344,26 @@ func (c *controller) manageReplicas(ctx context.Context, allMachines []*v1alpha1 machinesWithUpdateSuccessfulLabel = append(machinesWithUpdateSuccessfulLabel, m) continue } - if machineutils.IsMachineFailed(m) { + if machineutils.IsMachineTriggeredForDeletion(m) { + staleMachines = append(staleMachines, m) + } else if machineutils.IsMachineFailed(m) { klog.V(2).Infof("TEST: machineutils.IsPreserveExpiryTimeSet(m): %v,machineutils.HasPreservationTimedOut(m):%v", machineutils.IsPreserveExpiryTimeSet(m), machineutils.HasPreservationTimedOut(m)) if machineutils.IsPreserveExpiryTimeSet(m) && !machineutils.HasPreservationTimedOut(m) { - klog.V(2).Infof("Machine %s currently preserved, not adding to stale machines", m.Name) + klog.V(3).Infof("Machine %s is preserved until %v, not adding to stale machines", m.Name, m.Status.CurrentStatus.PreserveExpiryTime) activeMachines = append(activeMachines, m) } else if val, exists := m.Annotations[machineutils.PreserveMachineAnnotationKey]; exists && val == machineutils.PreserveMachineAnnotationValueWhenFailed { // this is in case preservation process is not complete yet - klog.V(2).Infof("Machine %s currently preserved, not adding to stale machines", m.Name) + klog.V(3).Infof("Machine %s is preserved until %v, not adding to stale machines", m.Name, m.Status.CurrentStatus.PreserveExpiryTime) activeMachines = append(activeMachines, m) + } else if machineSet.Status.AutoPreservedFailedMachineCount < machineSet.Spec.AutoPreserveFailedMachineMax { + klog.V(2).Infof("TEST:marking machine %s for autopreservation", m.Name) + updatedMachine, err := c.annotateMachineForAutoPreservation(ctx, m) + if err != nil { + return err + } + activeMachines = append(activeMachines, updatedMachine) } else { staleMachines = append(staleMachines, m) } - } else if machineutils.IsMachineTriggeredForDeletion(m) { - staleMachines = append(staleMachines, m) } else if machineutils.IsMachineActive(m) { activeMachines = append(activeMachines, m) } @@ -934,3 +941,19 @@ func UpdateMachineWithRetries(ctx context.Context, machineClient v1alpha1client. return machine, retryErr } + +func (dc *controller) annotateMachineForAutoPreservation(ctx context.Context, m *v1alpha1.Machine) (*v1alpha1.Machine, error) { + updatedMachine, err := UpdateMachineWithRetries(ctx, dc.controlMachineClient.Machines(m.Namespace), dc.machineLister, m.Namespace, m.Name, func(clone *v1alpha1.Machine) error { + if clone.Annotations == nil { + clone.Annotations = make(map[string]string) + } + clone.Annotations[machineutils.PreserveMachineAnnotationKey] = machineutils.PreserveMachineAnnotationValuePreservedByMCM + return nil + }) + if err != nil { + return nil, fmt.Errorf("error in annotating machine %s for auto-preservation, error:%v", m.Name, err) + } + klog.V(2).Infof("Updated Machine %s/%s with auto-preserve annotation.", m.Namespace, m.Name) + return updatedMachine, nil + +} diff --git a/pkg/openapi/openapi_generated.go b/pkg/openapi/openapi_generated.go index 60a1d1fb0..257954fd1 100644 --- a/pkg/openapi/openapi_generated.go +++ b/pkg/openapi/openapi_generated.go @@ -955,6 +955,13 @@ func schema_pkg_apis_machine_v1alpha1_MachineDeploymentSpec(ref common.Reference Format: "int32", }, }, + "autoPreserveFailedMachineMax": { + SchemaProps: spec.SchemaProps{ + Description: "The maximum number of machines in the machine deployment that will be auto-preserved. In the gardener context, this number is derived from the AutoPreserveFailedMachineMax set at the worker level, distributed amongst the worker's machine deployments", + Type: []string{"integer"}, + Format: "int32", + }, + }, }, Required: []string{"template"}, }, @@ -1329,6 +1336,12 @@ func schema_pkg_apis_machine_v1alpha1_MachineSetSpec(ref common.ReferenceCallbac Format: "int32", }, }, + "autoPreserveFailedMachineMax": { + SchemaProps: spec.SchemaProps{ + Type: []string{"integer"}, + Format: "int32", + }, + }, }, }, }, @@ -1414,6 +1427,13 @@ func schema_pkg_apis_machine_v1alpha1_MachineSetStatus(ref common.ReferenceCallb }, }, }, + "autoPreservedFailedMachineCount": { + SchemaProps: spec.SchemaProps{ + Description: "AutoPreservedFailedMachineCount has a count of the number of failed machines in the machineset that have been auto-preserved", + Type: []string{"integer"}, + Format: "int32", + }, + }, }, }, }, diff --git a/pkg/util/provider/machinecontroller/machine_util.go b/pkg/util/provider/machinecontroller/machine_util.go index c2cd0804a..2b3b46b75 100644 --- a/pkg/util/provider/machinecontroller/machine_util.go +++ b/pkg/util/provider/machinecontroller/machine_util.go @@ -2358,7 +2358,7 @@ func (c *controller) fetchMatchingNodeName(machineName string) (string, error) { // preserveMachine contains logic to start the preservation of a machine and node. It syncs node annotations to the machine if the backing node exists, // or has an annotation related to preservation. // it does not sync preserve annotation values from machine to node to prevent bi-directional syncing issues. -func (c *controller) preserveMachine(ctx context.Context, machine *v1alpha1.Machine) (machineutils.RetryPeriod, error) { +func (c *controller) preserveMachine(ctx context.Context, machine *v1alpha1.Machine, preserveValue string) (machineutils.RetryPeriod, error) { klog.V(3).Infof("TEST: Entering preserve machine flow") if !machineutils.IsPreserveExpiryTimeSet(machine) { preservedCurrentStatus := v1alpha1.CurrentStatus{ @@ -2406,6 +2406,11 @@ func (c *controller) preserveMachine(ctx context.Context, machine *v1alpha1.Mach Status: v1.ConditionTrue, LastTransitionTime: metav1.Now(), } + if preserveValue != machineutils.PreserveMachineAnnotationValuePreservedByMCM { + newNodePreservedCondition.Reason = v1alpha1.NodePreservedByUser + } else { + newNodePreservedCondition.Reason = v1alpha1.NodePreservedByMCM + } // drain node only if machine has failed if machine.Status.CurrentStatus.Phase == v1alpha1.MachineFailed { existingNodePreservedCondition, err := nodeops.GetNodeCondition(ctx, c.targetCoreClient, getNodeName(machine), v1alpha1.NodePreserved) @@ -2413,7 +2418,7 @@ func (c *controller) preserveMachine(ctx context.Context, machine *v1alpha1.Mach klog.V(3).Infof("Error trying to get node preserved condition for machine %s: %v", machine.Name, err) return machineutils.ShortRetry, err } - if existingNodePreservedCondition == nil || existingNodePreservedCondition.Reason != v1alpha1.DrainSuccessful { + if existingNodePreservedCondition == nil || existingNodePreservedCondition.Message != v1alpha1.PreservedNodeDrainSuccessful { err = c.drainPreservedNode(ctx, machine) if err != nil { klog.V(3).Infof("TEST: drain failed with error:%s", err) @@ -2428,7 +2433,7 @@ func (c *controller) preserveMachine(ctx context.Context, machine *v1alpha1.Mach return machineutils.ShortRetry, err } klog.V(2).Infof("TEST: drainPreservedNode Successful %s", machine.Name) - newNodePreservedCondition.Reason = v1alpha1.DrainSuccessful + newNodePreservedCondition.Message = v1alpha1.PreservedNodeDrainSuccessful } else { klog.V(3).Infof("TEST: unnecessary entry into preserved machine %s", machine.Name) return machineutils.LongRetry, nil diff --git a/pkg/util/provider/machineutils/utils.go b/pkg/util/provider/machineutils/utils.go index b00c01fce..75e68493f 100644 --- a/pkg/util/provider/machineutils/utils.go +++ b/pkg/util/provider/machineutils/utils.go @@ -95,6 +95,10 @@ const ( // a Machine be preserved if and when in it enters Failed phase PreserveMachineAnnotationValueWhenFailed = "when-failed" + // PreserveMachineAnnotationValuePreservedByMCM is the annotation value used to explicitly request that + // a Machine be preserved if and when in it enters Failed phase + PreserveMachineAnnotationValuePreservedByMCM = "auto-preserved" + //PreserveMachineAnnotationValueFalse is the annotation value used to explicitly request that // a Machine should not be preserved any longer, even if the expiry timeout has not been reached PreserveMachineAnnotationValueFalse = "false" From 83fef680c3546a54d1393e20bc020cc582134e55 Mon Sep 17 00:00:00 2001 From: thiyyakat Date: Fri, 5 Dec 2025 15:47:47 +0530 Subject: [PATCH 19/43] Fix bugs that prevented MCS update, and auto-preservation of machines --- docs/documents/apis.md | 4 +- .../crds/machine.sapcloud.io_machinesets.yaml | 4 +- pkg/apis/machine/types.go | 4 +- pkg/apis/machine/v1alpha1/machine_types.go | 2 +- pkg/apis/machine/v1alpha1/machineset_types.go | 4 +- .../v1alpha1/zz_generated.conversion.go | 4 +- pkg/controller/deployment_machineset_util.go | 16 ++--- pkg/controller/machineset.go | 59 ++++++++++++++----- pkg/openapi/openapi_generated.go | 4 +- .../provider/machinecontroller/machine.go | 15 +++-- .../machinecontroller/machine_util.go | 18 +++--- 11 files changed, 86 insertions(+), 48 deletions(-) diff --git a/docs/documents/apis.md b/docs/documents/apis.md index c6f19d3e3..a4e2f7628 100644 --- a/docs/documents/apis.md +++ b/docs/documents/apis.md @@ -2087,7 +2087,7 @@ LastOperation -autoPreservedFailedMachineCount +autoPreserveFailedMachineCount @@ -2096,7 +2096,7 @@ int32 (Optional) -

AutoPreservedFailedMachineCount has a count of the number of failed machines in the machineset that have been auto-preserved

+

AutoPreserveFailedMachineCount has a count of the number of failed machines in the machineset that have been auto-preserved

diff --git a/kubernetes/crds/machine.sapcloud.io_machinesets.yaml b/kubernetes/crds/machine.sapcloud.io_machinesets.yaml index b76c22cc3..970be4b20 100644 --- a/kubernetes/crds/machine.sapcloud.io_machinesets.yaml +++ b/kubernetes/crds/machine.sapcloud.io_machinesets.yaml @@ -319,8 +319,8 @@ spec: description: MachineSetStatus holds the most recently observed status of MachineSet. properties: - autoPreservedFailedMachineCount: - description: AutoPreservedFailedMachineCount has a count of the number + autoPreserveFailedMachineCount: + description: AutoPreserveFailedMachineCount has a count of the number of failed machines in the machineset that have been auto-preserved format: int32 type: integer diff --git a/pkg/apis/machine/types.go b/pkg/apis/machine/types.go index 6c6487d78..10b3b507e 100644 --- a/pkg/apis/machine/types.go +++ b/pkg/apis/machine/types.go @@ -418,8 +418,8 @@ type MachineSetStatus struct { // FailedMachines has summary of machines on which lastOperation Failed FailedMachines *[]MachineSummary - // AutoPreservedFailedMachineCount has a count of the number of failed machines in the machineset that have been auto-preserved - AutoPreservedFailedMachineCount int32 + // AutoPreserveFailedMachineCount has a count of the number of failed machines in the machineset that have been auto-preserved + AutoPreserveFailedMachineCount int32 } // MachineSummary store the summary of machine. diff --git a/pkg/apis/machine/v1alpha1/machine_types.go b/pkg/apis/machine/v1alpha1/machine_types.go index 57a532949..0ce3eb483 100644 --- a/pkg/apis/machine/v1alpha1/machine_types.go +++ b/pkg/apis/machine/v1alpha1/machine_types.go @@ -255,7 +255,7 @@ const ( NodePreservedByUser string = "PreservedByUser" //PreservedNodeDrainSuccessful is a constant for the message in condition that indicates that the preserved node's drain is successful - PreservedNodeDrainSuccessful string = "PreservedNodeDrainSuccessful" + PreservedNodeDrainSuccessful string = "Preserved Node Drained Successfully" ) // CurrentStatus contains information about the current status of Machine. diff --git a/pkg/apis/machine/v1alpha1/machineset_types.go b/pkg/apis/machine/v1alpha1/machineset_types.go index 6e8cf1f03..8cd73d58e 100644 --- a/pkg/apis/machine/v1alpha1/machineset_types.go +++ b/pkg/apis/machine/v1alpha1/machineset_types.go @@ -139,7 +139,7 @@ type MachineSetStatus struct { // +optional FailedMachines *[]MachineSummary `json:"failedMachines,omitempty"` - // AutoPreservedFailedMachineCount has a count of the number of failed machines in the machineset that have been auto-preserved + // AutoPreserveFailedMachineCount has a count of the number of failed machines in the machineset that have been auto-preserved // +optional - AutoPreservedFailedMachineCount int32 `json:"autoPreservedFailedMachineCount,omitempty"` + AutoPreserveFailedMachineCount int32 `json:"autoPreserveFailedMachineCount,omitempty"` } diff --git a/pkg/apis/machine/v1alpha1/zz_generated.conversion.go b/pkg/apis/machine/v1alpha1/zz_generated.conversion.go index 8286caba6..1990c2f03 100644 --- a/pkg/apis/machine/v1alpha1/zz_generated.conversion.go +++ b/pkg/apis/machine/v1alpha1/zz_generated.conversion.go @@ -905,7 +905,7 @@ func autoConvert_v1alpha1_MachineSetStatus_To_machine_MachineSetStatus(in *Machi return err } out.FailedMachines = (*[]machine.MachineSummary)(unsafe.Pointer(in.FailedMachines)) - out.AutoPreservedFailedMachineCount = in.AutoPreservedFailedMachineCount + out.AutoPreserveFailedMachineCount = in.AutoPreserveFailedMachineCount return nil } @@ -925,7 +925,7 @@ func autoConvert_machine_MachineSetStatus_To_v1alpha1_MachineSetStatus(in *machi return err } out.FailedMachines = (*[]MachineSummary)(unsafe.Pointer(in.FailedMachines)) - out.AutoPreservedFailedMachineCount = in.AutoPreservedFailedMachineCount + out.AutoPreserveFailedMachineCount = in.AutoPreserveFailedMachineCount return nil } diff --git a/pkg/controller/deployment_machineset_util.go b/pkg/controller/deployment_machineset_util.go index b41220916..fc9fcb7b9 100644 --- a/pkg/controller/deployment_machineset_util.go +++ b/pkg/controller/deployment_machineset_util.go @@ -48,7 +48,8 @@ func updateMachineSetStatus(ctx context.Context, machineClient machineapi.Machin is.Status.AvailableReplicas == newStatus.AvailableReplicas && is.Generation == is.Status.ObservedGeneration && reflect.DeepEqual(is.Status.Conditions, newStatus.Conditions) && - reflect.DeepEqual(is.Status.FailedMachines, newStatus.FailedMachines) { + reflect.DeepEqual(is.Status.FailedMachines, newStatus.FailedMachines) && + is.Status.AutoPreserveFailedMachineCount == newStatus.AutoPreserveFailedMachineCount { return is, nil } @@ -66,7 +67,8 @@ func updateMachineSetStatus(ctx context.Context, machineClient machineapi.Machin fmt.Sprintf("fullyLabeledReplicas %d->%d, ", is.Status.FullyLabeledReplicas, newStatus.FullyLabeledReplicas)+ fmt.Sprintf("readyReplicas %d->%d, ", is.Status.ReadyReplicas, newStatus.ReadyReplicas)+ fmt.Sprintf("availableReplicas %d->%d, ", is.Status.AvailableReplicas, newStatus.AvailableReplicas)+ - fmt.Sprintf("sequence No: %v->%v", is.Status.ObservedGeneration, newStatus.ObservedGeneration)) + fmt.Sprintf("sequence No: %v->%v", is.Status.ObservedGeneration, newStatus.ObservedGeneration)+ + fmt.Sprintf("autoPreserveFailedMachineCount %v->%v", is.Status.AutoPreserveFailedMachineCount, newStatus.AutoPreserveFailedMachineCount)) is.Status = newStatus updatedIS, updateErr = c.UpdateStatus(ctx, is, metav1.UpdateOptions{}) @@ -78,7 +80,7 @@ func updateMachineSetStatus(ctx context.Context, machineClient machineapi.Machin if i >= statusUpdateRetries { break } - // Update the MachineSet with the latest resource veision for the next poll + // Update the MachineSet with the latest resource version for the next poll if is, getErr = c.Get(ctx, is.Name, metav1.GetOptions{}); getErr != nil { // If the GET fails we can't trust status.Replicas anymore. This error // is bound to be more interesting than the update failure. @@ -99,7 +101,7 @@ func calculateMachineSetStatus(is *v1alpha1.MachineSet, filteredMachines []*v1al fullyLabeledReplicasCount := 0 readyReplicasCount := 0 availableReplicasCount := 0 - autoPreservedFailedMachineCount := 0 + autoPreserveFailedMachineCount := 0 failedMachines := []v1alpha1.MachineSummary{} var machineSummary v1alpha1.MachineSummary @@ -127,7 +129,8 @@ func calculateMachineSetStatus(is *v1alpha1.MachineSet, filteredMachines []*v1al } if cond := getMachineCondition(machine, v1alpha1.NodePreserved); cond != nil { if cond.Reason == v1alpha1.NodePreservedByMCM { - autoPreservedFailedMachineCount++ + autoPreserveFailedMachineCount++ + klog.V(3).Infof("TEST: incrementing autoPreserveFailedMachineCount to %v", autoPreserveFailedMachineCount) } } } @@ -152,7 +155,6 @@ func calculateMachineSetStatus(is *v1alpha1.MachineSet, filteredMachines []*v1al SetCondition(&newStatus, cond) } else if manageReplicasErr == nil && failureCond != nil { RemoveCondition(&newStatus, v1alpha1.MachineSetReplicaFailure) - } else if manageReplicasErr != nil { } newStatus.Replicas = int32(len(filteredMachines)) // #nosec G115 (CWE-190) -- number of machines will not exceed MaxInt32 @@ -160,7 +162,7 @@ func calculateMachineSetStatus(is *v1alpha1.MachineSet, filteredMachines []*v1al newStatus.ReadyReplicas = int32(readyReplicasCount) // #nosec G115 (CWE-190) -- number of machines will not exceed MaxInt32 newStatus.AvailableReplicas = int32(availableReplicasCount) // #nosec G115 (CWE-190) -- number of machines will not exceed MaxInt32 newStatus.LastOperation.LastUpdateTime = metav1.Now() - newStatus.AutoPreservedFailedMachineCount = int32(autoPreservedFailedMachineCount) // #nosec G115 (CWE-190) -- number of machines will not exceed MaxInt32 + newStatus.AutoPreserveFailedMachineCount = int32(autoPreserveFailedMachineCount) // #nosec G115 (CWE-190) -- number of machines will not exceed MaxInt32 return newStatus } diff --git a/pkg/controller/machineset.go b/pkg/controller/machineset.go index c25b4dd70..f253cca17 100644 --- a/pkg/controller/machineset.go +++ b/pkg/controller/machineset.go @@ -347,20 +347,10 @@ func (c *controller) manageReplicas(ctx context.Context, allMachines []*v1alpha1 if machineutils.IsMachineTriggeredForDeletion(m) { staleMachines = append(staleMachines, m) } else if machineutils.IsMachineFailed(m) { - klog.V(2).Infof("TEST: machineutils.IsPreserveExpiryTimeSet(m): %v,machineutils.HasPreservationTimedOut(m):%v", machineutils.IsPreserveExpiryTimeSet(m), machineutils.HasPreservationTimedOut(m)) - if machineutils.IsPreserveExpiryTimeSet(m) && !machineutils.HasPreservationTimedOut(m) { - klog.V(3).Infof("Machine %s is preserved until %v, not adding to stale machines", m.Name, m.Status.CurrentStatus.PreserveExpiryTime) - activeMachines = append(activeMachines, m) - } else if val, exists := m.Annotations[machineutils.PreserveMachineAnnotationKey]; exists && val == machineutils.PreserveMachineAnnotationValueWhenFailed { // this is in case preservation process is not complete yet - klog.V(3).Infof("Machine %s is preserved until %v, not adding to stale machines", m.Name, m.Status.CurrentStatus.PreserveExpiryTime) + if preserve, err := c.isMachineCandidateForPreservation(ctx, machineSet, m); err != nil { + return err + } else if preserve { activeMachines = append(activeMachines, m) - } else if machineSet.Status.AutoPreservedFailedMachineCount < machineSet.Spec.AutoPreserveFailedMachineMax { - klog.V(2).Infof("TEST:marking machine %s for autopreservation", m.Name) - updatedMachine, err := c.annotateMachineForAutoPreservation(ctx, m) - if err != nil { - return err - } - activeMachines = append(activeMachines, updatedMachine) } else { staleMachines = append(staleMachines, m) } @@ -499,6 +489,35 @@ func (c *controller) manageReplicas(ctx context.Context, allMachines []*v1alpha1 return nil } +// isMachineCandidateForPreservation checks if the machine is already preserved, in the process of being preserved +// or if it is a candidate for auto-preservation +// TODO@thiyyakat: find more suitable name for function +func (c *controller) isMachineCandidateForPreservation(ctx context.Context, machineSet *v1alpha1.MachineSet, machine *v1alpha1.Machine) (bool, error) { + klog.V(2).Infof("TEST: machineutils.IsPreserveExpiryTimeSet(m): %v,machineutils.HasPreservationTimedOut(m):%v", machineutils.IsPreserveExpiryTimeSet(machine), machineutils.HasPreservationTimedOut(machine)) + if machineutils.IsPreserveExpiryTimeSet(machine) && !machineutils.HasPreservationTimedOut(machine) { + klog.V(3).Infof("Machine %s is preserved until %v, not adding to stale machines", machine.Name, machine.Status.CurrentStatus.PreserveExpiryTime) + return true, nil + } + val, exists := machine.Annotations[machineutils.PreserveMachineAnnotationKey] + if exists { + switch val { + case machineutils.PreserveMachineAnnotationValueWhenFailed, machineutils.PreserveMachineAnnotationValueNow: // this is in case preservation process is not complete yet + return true, nil + case machineutils.PreserveMachineAnnotationValueFalse: + return false, nil + } + } + if machineSet.Status.AutoPreserveFailedMachineCount < machineSet.Spec.AutoPreserveFailedMachineMax { + klog.V(2).Infof("TEST:marking machine %s for autopreservation", machine.Name) + _, err := c.annotateMachineForAutoPreservation(ctx, machine) + if err != nil { + return true, err + } + return true, nil + } + return false, nil +} + // syncMachineSet will sync the MachineSet with the given key if it has had its expectations fulfilled, // meaning it did not expect to see any more of its machines created or deleted. This function is not meant to be // invoked concurrently with the same key. @@ -943,6 +962,16 @@ func UpdateMachineWithRetries(ctx context.Context, machineClient v1alpha1client. } func (dc *controller) annotateMachineForAutoPreservation(ctx context.Context, m *v1alpha1.Machine) (*v1alpha1.Machine, error) { + if m.Labels[v1alpha1.NodeLabelKey] != "" { + // check if backing node has preserve=false annotation, if yes, do not auto-preserve + node, err := dc.nodeLister.Get(m.Labels[v1alpha1.NodeLabelKey]) + if err != nil { + return nil, err + } + if val, exists := node.Annotations[machineutils.PreserveMachineAnnotationKey]; exists && val == machineutils.PreserveMachineAnnotationValueFalse { + return nil, nil + } + } updatedMachine, err := UpdateMachineWithRetries(ctx, dc.controlMachineClient.Machines(m.Namespace), dc.machineLister, m.Namespace, m.Name, func(clone *v1alpha1.Machine) error { if clone.Annotations == nil { clone.Annotations = make(map[string]string) @@ -951,9 +980,9 @@ func (dc *controller) annotateMachineForAutoPreservation(ctx context.Context, m return nil }) if err != nil { - return nil, fmt.Errorf("error in annotating machine %s for auto-preservation, error:%v", m.Name, err) + return nil, err } - klog.V(2).Infof("Updated Machine %s/%s with auto-preserve annotation.", m.Namespace, m.Name) + klog.V(2).Infof("Updated machine %s with auto-preserve annotation.", m.Name) return updatedMachine, nil } diff --git a/pkg/openapi/openapi_generated.go b/pkg/openapi/openapi_generated.go index 257954fd1..b0cd12043 100644 --- a/pkg/openapi/openapi_generated.go +++ b/pkg/openapi/openapi_generated.go @@ -1427,9 +1427,9 @@ func schema_pkg_apis_machine_v1alpha1_MachineSetStatus(ref common.ReferenceCallb }, }, }, - "autoPreservedFailedMachineCount": { + "autoPreserveFailedMachineCount": { SchemaProps: spec.SchemaProps{ - Description: "AutoPreservedFailedMachineCount has a count of the number of failed machines in the machineset that have been auto-preserved", + Description: "AutoPreserveFailedMachineCount has a count of the number of failed machines in the machineset that have been auto-preserved", Type: []string{"integer"}, Format: "int32", }, diff --git a/pkg/util/provider/machinecontroller/machine.go b/pkg/util/provider/machinecontroller/machine.go index 849fcba11..c59fcd0f0 100644 --- a/pkg/util/provider/machinecontroller/machine.go +++ b/pkg/util/provider/machinecontroller/machine.go @@ -274,6 +274,11 @@ func (c *controller) reconcileClusterMachine(ctx context.Context, machine *v1alp } } + retry, err = c.manageMachinePreservation(ctx, machine) + if err != nil { + return retry, err + } + if machine.Spec.ProviderID == "" || machine.Status.CurrentStatus.Phase == "" || machine.Status.CurrentStatus.Phase == v1alpha1.MachineCrashLoopBackOff { return c.triggerCreationFlow( ctx, @@ -790,7 +795,7 @@ func (c *controller) manageMachinePreservation(ctx context.Context, machine *v1a } klog.V(3).Infof("TEST: preserve:%s", preserveValue) switch preserveValue { - case machineutils.PreserveMachineAnnotationValueNow, machineutils.PreserveMachineAnnotationValueWhenFailed: + case machineutils.PreserveMachineAnnotationValueNow, machineutils.PreserveMachineAnnotationValueWhenFailed, machineutils.PreserveMachineAnnotationValuePreservedByMCM: // if preserve annotation value has switched from now to when-failed, then stop preservation if preserveValue == machineutils.PreserveMachineAnnotationValueWhenFailed && !machineutils.IsMachineFailed(updatedMachine) { if machineutils.IsPreserveExpiryTimeSet(updatedMachine) { @@ -798,12 +803,12 @@ func (c *controller) manageMachinePreservation(ctx context.Context, machine *v1a } return machineutils.LongRetry, nil } - isComplete, err := c.isMachinePreservationComplete(ctx, machine) + isComplete, err := c.isMachinePreservationComplete(machine) if err != nil { return machineutils.ShortRetry, err } if !isComplete { - return c.preserveMachine(ctx, machine) + return c.preserveMachine(ctx, machine, preserveValue) } if hasMachinePreservationTimedOut(machine) { return c.stopMachinePreservation(ctx, updatedMachine) @@ -859,7 +864,7 @@ func (c *controller) syncEffectivePreserveAnnotationValue(ctx context.Context, m return machine, mAnnotationValue, mExists, nil } -func (c *controller) isMachinePreservationComplete(ctx context.Context, machine *v1alpha1.Machine) (bool, error) { +func (c *controller) isMachinePreservationComplete(machine *v1alpha1.Machine) (bool, error) { // if PreserveExpiryTime is set and machine has not failed, then yes, // if PreserveExpiryTime is set and machine has failed, the node condition must be there saying drain successful // if PreserveExpiryTime is not set, then no @@ -872,7 +877,7 @@ func (c *controller) isMachinePreservationComplete(ctx context.Context, machine return false, err } if cond := nodeops.GetCondition(node, v1alpha1.NodePreserved); cond != nil { - if cond.Reason == v1alpha1.DrainSuccessful { + if cond.Message == v1alpha1.PreservedNodeDrainSuccessful { return true, nil } } diff --git a/pkg/util/provider/machinecontroller/machine_util.go b/pkg/util/provider/machinecontroller/machine_util.go index 2b3b46b75..f267778ad 100644 --- a/pkg/util/provider/machinecontroller/machine_util.go +++ b/pkg/util/provider/machinecontroller/machine_util.go @@ -2176,7 +2176,11 @@ func (c *controller) canMarkMachineFailed(machineDeployName, machineName, namesp for _, machine := range machineList { if machine.Status.CurrentStatus.Phase != v1alpha1.MachineUnknown && machine.Status.CurrentStatus.Phase != v1alpha1.MachineRunning { - inProgress++ + // since Preserved Failed machines are not replaced immediately, + // they need not be considered towards inProgress + if !machineutils.IsPreserveExpiryTimeSet(machine) { + inProgress++ + } switch machine.Status.CurrentStatus.Phase { case v1alpha1.MachineTerminating: terminating++ @@ -2391,7 +2395,7 @@ func (c *controller) preserveMachine(ctx context.Context, machine *v1alpha1.Mach CAScaleDownAnnotation := make(map[string]string) CAScaleDownAnnotation[autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationKey] = autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationValue updatedNode, _, _ := annotations.AddOrUpdateAnnotation(nodeCopy, CAScaleDownAnnotation) - updatedNode, err = c.targetCoreClient.CoreV1().Nodes().Update(ctx, updatedNode, metav1.UpdateOptions{}) + _, err = c.targetCoreClient.CoreV1().Nodes().Update(ctx, updatedNode, metav1.UpdateOptions{}) if err != nil { if apierrors.IsConflict(err) { return machineutils.ConflictRetry, err @@ -2418,7 +2422,10 @@ func (c *controller) preserveMachine(ctx context.Context, machine *v1alpha1.Mach klog.V(3).Infof("Error trying to get node preserved condition for machine %s: %v", machine.Name, err) return machineutils.ShortRetry, err } - if existingNodePreservedCondition == nil || existingNodePreservedCondition.Message != v1alpha1.PreservedNodeDrainSuccessful { + if existingNodePreservedCondition != nil && existingNodePreservedCondition.Message != v1alpha1.PreservedNodeDrainSuccessful { + klog.V(2).Infof("TEST: drainPreservedNode Successful %s", machine.Name) + newNodePreservedCondition.Message = v1alpha1.PreservedNodeDrainSuccessful + } else { err = c.drainPreservedNode(ctx, machine) if err != nil { klog.V(3).Infof("TEST: drain failed with error:%s", err) @@ -2432,11 +2439,6 @@ func (c *controller) preserveMachine(ctx context.Context, machine *v1alpha1.Mach } return machineutils.ShortRetry, err } - klog.V(2).Infof("TEST: drainPreservedNode Successful %s", machine.Name) - newNodePreservedCondition.Message = v1alpha1.PreservedNodeDrainSuccessful - } else { - klog.V(3).Infof("TEST: unnecessary entry into preserved machine %s", machine.Name) - return machineutils.LongRetry, nil } } if err = nodeops.AddOrUpdateConditionsOnNode(ctx, c.targetCoreClient, getNodeName(machine), newNodePreservedCondition); err != nil { From 377332a243c85f32802e49f1973966a4dcf5eacc Mon Sep 17 00:00:00 2001 From: thiyyakat Date: Mon, 8 Dec 2025 16:44:47 +0530 Subject: [PATCH 20/43] Add support for uncordoning preserved node that is healthy --- .../provider/machinecontroller/machine.go | 21 ++++++++++++++++--- .../machinecontroller/machine_util.go | 15 +++++++++++++ 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/pkg/util/provider/machinecontroller/machine.go b/pkg/util/provider/machinecontroller/machine.go index c59fcd0f0..8e4afd844 100644 --- a/pkg/util/provider/machinecontroller/machine.go +++ b/pkg/util/provider/machinecontroller/machine.go @@ -231,13 +231,28 @@ func (c *controller) reconcileClusterMachine(ctx context.Context, machine *v1alp return machineutils.ShortRetry, err } if cond := nodeops.GetCondition(node, corev1.NodeNetworkUnavailable); cond.Status != corev1.ConditionTrue { - cond := corev1.NodeCondition{Type: corev1.NodeNetworkUnavailable, Status: corev1.ConditionTrue} - err = nodeops.AddOrUpdateConditionsOnNode(ctx, c.targetCoreClient, getNodeName(machine), cond) + newCond := corev1.NodeCondition{Type: corev1.NodeNetworkUnavailable, Status: corev1.ConditionTrue} + err = nodeops.AddOrUpdateConditionsOnNode(ctx, c.targetCoreClient, getNodeName(machine), newCond) if err != nil { klog.V(2).Infof("TEST:Machine %q: Failed to change node condition %q: %v", machine.Name, machine.Name, err) return machineutils.ShortRetry, err } - klog.V(2).Infof("TEST:Machine %q: updated node %q condition", machine.Name, machine.Name) + klog.V(2).Infof("TEST: marked nodenetwork as unavailable for machine %s", machine.Name) + } + } else if machine.Labels["test-failed"] == "false" { + node, err := c.nodeLister.Get(getNodeName(machine)) + if err != nil { + klog.V(3).Infof("TEST:Machine %q: Failed to get node %q: %v", machine.Name, machine.Name, err) + return machineutils.ShortRetry, err + } + if cond := nodeops.GetCondition(node, corev1.NodeNetworkUnavailable); cond.Status != corev1.ConditionFalse { + newCond := corev1.NodeCondition{Type: corev1.NodeNetworkUnavailable, Status: corev1.ConditionFalse} + err = nodeops.AddOrUpdateConditionsOnNode(ctx, c.targetCoreClient, getNodeName(machine), newCond) + if err != nil { + klog.V(2).Infof("TEST:Machine %q: Failed to change node condition %q: %v", machine.Name, machine.Name, err) + return machineutils.ShortRetry, err + } + klog.V(2).Infof("TEST: marked nodenetwork as available %s", machine.Name) } } } diff --git a/pkg/util/provider/machinecontroller/machine_util.go b/pkg/util/provider/machinecontroller/machine_util.go index f267778ad..dda97a607 100644 --- a/pkg/util/provider/machinecontroller/machine_util.go +++ b/pkg/util/provider/machinecontroller/machine_util.go @@ -983,6 +983,19 @@ func (c *controller) reconcileMachineHealth(ctx context.Context, machine *v1alph klog.Warning(err) } } else { + // if machine was auto-preserved (which means it is in Failed phase), stop preservation + if cond := nodeops.GetCondition(node, v1alpha1.NodePreserved); cond != nil && machine.Status.CurrentStatus.Phase == v1alpha1.MachineFailed { + if cond.Reason == v1alpha1.NodePreservedByMCM { + // need to uncordon node + nodeCopy := node.DeepCopy() + nodeCopy.Spec.Unschedulable = false + _, err = c.targetCoreClient.CoreV1().Nodes().Update(ctx, nodeCopy, metav1.UpdateOptions{}) + if err != nil { + return machineutils.ShortRetry, err + } + klog.V(3).Infof("TEST: preserved node uncordoned successfully %s", machine.Name) + } + } // Machine rejoined the cluster after a health-check description = fmt.Sprintf("Machine %s successfully re-joined the cluster", clone.Name) lastOperationType = v1alpha1.MachineOperationHealthCheck @@ -1027,6 +1040,7 @@ func (c *controller) reconcileMachineHealth(ctx context.Context, machine *v1alph } } } + } if !cloneDirty && (machine.Status.CurrentStatus.Phase == v1alpha1.MachineInPlaceUpdating || @@ -2455,6 +2469,7 @@ func (c *controller) stopMachinePreservation(ctx context.Context, machine *v1alp if !machineutils.IsPreserveExpiryTimeSet(machine) { return machineutils.LongRetry, nil } + klog.V(3).Infof("TEST: stopping preservation machine %q", machine.Name) // if backing node exists, remove annotations that would prevent scale down by autoscaler if machine.Labels[v1alpha1.NodeLabelKey] != "" { nodeName := machine.Labels[v1alpha1.NodeLabelKey] From d1766de6b64e6194f756cb57aa763fb77e84017f Mon Sep 17 00:00:00 2001 From: thiyyakat Date: Wed, 10 Dec 2025 12:19:17 +0530 Subject: [PATCH 21/43] Refactor code: * Split larger functions into smaller ones * Remove debug comments * Add comments where required --- pkg/apis/machine/v1alpha1/machine_types.go | 5 +- pkg/controller/deployment_machineset_util.go | 1 - pkg/controller/machineset.go | 2 - pkg/util/nodeops/conditions.go | 6 +- .../provider/machinecontroller/machine.go | 91 +++---- .../machinecontroller/machine_test.go | 8 +- .../machinecontroller/machine_util.go | 235 +++++++++++------- pkg/util/provider/machineutils/utils.go | 2 - 8 files changed, 199 insertions(+), 151 deletions(-) diff --git a/pkg/apis/machine/v1alpha1/machine_types.go b/pkg/apis/machine/v1alpha1/machine_types.go index 0ce3eb483..8fe3d75fa 100644 --- a/pkg/apis/machine/v1alpha1/machine_types.go +++ b/pkg/apis/machine/v1alpha1/machine_types.go @@ -255,7 +255,10 @@ const ( NodePreservedByUser string = "PreservedByUser" //PreservedNodeDrainSuccessful is a constant for the message in condition that indicates that the preserved node's drain is successful - PreservedNodeDrainSuccessful string = "Preserved Node Drained Successfully" + PreservedNodeDrainSuccessful string = "Preserved Node drained successfully" + + //PreservedNodeDrainUnsuccessful is a constant for the message in condition that indicates that the preserved node's drain was not successful + PreservedNodeDrainUnsuccessful string = "Preserved Node could not be drained" ) // CurrentStatus contains information about the current status of Machine. diff --git a/pkg/controller/deployment_machineset_util.go b/pkg/controller/deployment_machineset_util.go index fc9fcb7b9..82475f405 100644 --- a/pkg/controller/deployment_machineset_util.go +++ b/pkg/controller/deployment_machineset_util.go @@ -130,7 +130,6 @@ func calculateMachineSetStatus(is *v1alpha1.MachineSet, filteredMachines []*v1al if cond := getMachineCondition(machine, v1alpha1.NodePreserved); cond != nil { if cond.Reason == v1alpha1.NodePreservedByMCM { autoPreserveFailedMachineCount++ - klog.V(3).Infof("TEST: incrementing autoPreserveFailedMachineCount to %v", autoPreserveFailedMachineCount) } } } diff --git a/pkg/controller/machineset.go b/pkg/controller/machineset.go index f253cca17..3e255f227 100644 --- a/pkg/controller/machineset.go +++ b/pkg/controller/machineset.go @@ -493,7 +493,6 @@ func (c *controller) manageReplicas(ctx context.Context, allMachines []*v1alpha1 // or if it is a candidate for auto-preservation // TODO@thiyyakat: find more suitable name for function func (c *controller) isMachineCandidateForPreservation(ctx context.Context, machineSet *v1alpha1.MachineSet, machine *v1alpha1.Machine) (bool, error) { - klog.V(2).Infof("TEST: machineutils.IsPreserveExpiryTimeSet(m): %v,machineutils.HasPreservationTimedOut(m):%v", machineutils.IsPreserveExpiryTimeSet(machine), machineutils.HasPreservationTimedOut(machine)) if machineutils.IsPreserveExpiryTimeSet(machine) && !machineutils.HasPreservationTimedOut(machine) { klog.V(3).Infof("Machine %s is preserved until %v, not adding to stale machines", machine.Name, machine.Status.CurrentStatus.PreserveExpiryTime) return true, nil @@ -508,7 +507,6 @@ func (c *controller) isMachineCandidateForPreservation(ctx context.Context, mach } } if machineSet.Status.AutoPreserveFailedMachineCount < machineSet.Spec.AutoPreserveFailedMachineMax { - klog.V(2).Infof("TEST:marking machine %s for autopreservation", machine.Name) _, err := c.annotateMachineForAutoPreservation(ctx, machine) if err != nil { return true, err diff --git a/pkg/util/nodeops/conditions.go b/pkg/util/nodeops/conditions.go index b02257d73..81b4b38c3 100644 --- a/pkg/util/nodeops/conditions.go +++ b/pkg/util/nodeops/conditions.go @@ -92,15 +92,13 @@ func AddOrUpdateConditionsOnNode(ctx context.Context, c clientset.Interface, nod } // UpdateNodeConditions is for updating the node conditions from oldNode to the newNode -// using the nodes Update() method +// using the node's UpdateStatus() method func UpdateNodeConditions(ctx context.Context, c clientset.Interface, nodeName string, oldNode *v1.Node, newNode *v1.Node) error { newNodeClone := oldNode.DeepCopy() newNodeClone.Status.Conditions = newNode.Status.Conditions - _, err := c.CoreV1().Nodes().UpdateStatus(ctx, newNodeClone, metav1.UpdateOptions{}) if err != nil { - return fmt.Errorf("failed to create update conditions for node %q: %v", nodeName, err) + return fmt.Errorf("failed to create/update conditions on node %q: %v", nodeName, err) } - return nil } diff --git a/pkg/util/provider/machinecontroller/machine.go b/pkg/util/provider/machinecontroller/machine.go index 8e4afd844..5b9f56611 100644 --- a/pkg/util/provider/machinecontroller/machine.go +++ b/pkg/util/provider/machinecontroller/machine.go @@ -796,19 +796,16 @@ func (c *controller) isCreationProcessing(machine *v1alpha1.Machine) bool { // - failed machine, autoPreserveMax not breached, must be preserved // - failed machine, already preserved, check for timeout // -// Auto-preserve case will have to be handled where machine moved from Unknown to Failed +// manageMachinePreservation checks if any preservation-related operations need to be performed on the machine and node objects func (c *controller) manageMachinePreservation(ctx context.Context, machine *v1alpha1.Machine) (machineutils.RetryPeriod, error) { - klog.V(3).Infof("TEST: entering manageMachinePreservation ") - // check effective preservation value based on node's and machine's annotations. + // get effective preservation value based on node's and machine's annotations. updatedMachine, preserveValue, exists, err := c.syncEffectivePreserveAnnotationValue(ctx, machine) if err != nil { - klog.Errorf("Error getting preserve annotation value for machine %q: %s", machine.Name, err) return machineutils.ShortRetry, err } if !exists { return machineutils.LongRetry, nil } - klog.V(3).Infof("TEST: preserve:%s", preserveValue) switch preserveValue { case machineutils.PreserveMachineAnnotationValueNow, machineutils.PreserveMachineAnnotationValueWhenFailed, machineutils.PreserveMachineAnnotationValuePreservedByMCM: // if preserve annotation value has switched from now to when-failed, then stop preservation @@ -839,44 +836,45 @@ func (c *controller) manageMachinePreservation(ctx context.Context, machine *v1a return machineutils.LongRetry, nil } +// syncEffectivePreserveAnnotationValue finds the preservation annotation value by considering both node and machine objects +// if the backing node is annotated with preserve annotation, the preserve value will be synced to the machine +// if there is no backing node, or the node has no preserve annotation, then the machine's preserve value is honoured +// if both machine and node objects have conflicting preserve annotation values, the node's value will be honoured func (c *controller) syncEffectivePreserveAnnotationValue(ctx context.Context, machine *v1alpha1.Machine) (*v1alpha1.Machine, string, bool, error) { - var effectivePreserveAnnotationValue string mAnnotationValue, mExists := machine.Annotations[machineutils.PreserveMachineAnnotationKey] - // node annotation value, if exists, will always override and overwrite machine annotation value for preserve - if machine.Labels[v1alpha1.NodeLabelKey] != "" { - nodeName := machine.Labels[v1alpha1.NodeLabelKey] - node, err := c.nodeLister.Get(nodeName) - if err != nil { - klog.Errorf("error trying to get node %q: %v", nodeName, err) - return machine, "", false, err - } - nAnnotationValue, nExists := node.Annotations[machineutils.PreserveMachineAnnotationKey] - switch { - case nExists && mExists: - if nAnnotationValue == mAnnotationValue { - return machine, nAnnotationValue, true, nil - } - effectivePreserveAnnotationValue = nAnnotationValue - case nExists && !mExists: - effectivePreserveAnnotationValue = nAnnotationValue - case mExists && !nExists: - return machine, mAnnotationValue, true, nil - case !nExists && !mExists: - return machine, "", false, nil - } - clone := machine.DeepCopy() - if clone.Annotations == nil { - clone.Annotations = make(map[string]string) - } - clone.Annotations[machineutils.PreserveMachineAnnotationKey] = effectivePreserveAnnotationValue - updatedMachine, err := c.controlMachineClient.Machines(c.namespace).Update(ctx, clone, metav1.UpdateOptions{}) - if err != nil { - klog.Errorf("error updating machine with preserve annotations %q: %v", machine.Name, err) - return machine, "", true, err - } - return updatedMachine, effectivePreserveAnnotationValue, true, nil + nodeName := machine.Labels[v1alpha1.NodeLabelKey] + if nodeName == "" { + return machine, mAnnotationValue, mExists, nil + } + node, err := c.nodeLister.Get(nodeName) + if err != nil { + klog.Errorf("error trying to get node %q: %v", nodeName, err) + return machine, "", false, err + } + nAnnotationValue, nExists := node.Annotations[machineutils.PreserveMachineAnnotationKey] + switch { + case nExists && mExists: + if nAnnotationValue == mAnnotationValue { + return machine, nAnnotationValue, nExists, nil + } // else falls through to update machine with node's value + case nExists && !mExists: + // falls through to update machine with node's value + case mExists && !nExists: + return machine, mAnnotationValue, mExists, nil + case !nExists && !mExists: + return machine, "", false, nil + } + clone := machine.DeepCopy() + if clone.Annotations == nil { + clone.Annotations = make(map[string]string) + } + clone.Annotations[machineutils.PreserveMachineAnnotationKey] = nAnnotationValue + updatedMachine, err := c.controlMachineClient.Machines(c.namespace).Update(ctx, clone, metav1.UpdateOptions{}) + if err != nil { + klog.Errorf("error updating machine %q with preserve annotation %q: %v", machine.Name, nAnnotationValue, err) + return machine, "", true, err } - return machine, mAnnotationValue, mExists, nil + return updatedMachine, nAnnotationValue, nExists, nil } func (c *controller) isMachinePreservationComplete(machine *v1alpha1.Machine) (bool, error) { @@ -886,6 +884,9 @@ func (c *controller) isMachinePreservationComplete(machine *v1alpha1.Machine) (b if !machineutils.IsPreserveExpiryTimeSet(machine) { return false, nil } else if machineutils.IsMachineFailed(machine) { + if machine.Labels[v1alpha1.NodeLabelKey] == "" { + return true, nil + } node, err := c.nodeLister.Get(getNodeName(machine)) if err != nil { klog.Errorf("error trying to get node %q: %v", getNodeName(machine), err) @@ -900,13 +901,3 @@ func (c *controller) isMachinePreservationComplete(machine *v1alpha1.Machine) (b } return true, nil } - -// getMachineDeploymentForMachine returns the machine deployment for a given machine -func (c *controller) getMachineDeploymentForMachine(machine *v1alpha1.Machine) (*v1alpha1.MachineDeployment, error) { - machineDeploymentName := getMachineDeploymentName(machine) - machineDeployment, err := c.controlMachineClient.MachineDeployments(c.namespace).Get(context.TODO(), machineDeploymentName, metav1.GetOptions{ - TypeMeta: metav1.TypeMeta{}, - ResourceVersion: "", - }) - return machineDeployment, err -} diff --git a/pkg/util/provider/machinecontroller/machine_test.go b/pkg/util/provider/machinecontroller/machine_test.go index 76214eac7..d5c5b5925 100644 --- a/pkg/util/provider/machinecontroller/machine_test.go +++ b/pkg/util/provider/machinecontroller/machine_test.go @@ -2782,7 +2782,7 @@ var _ = Describe("machine", func() { }, }, expect: expect{ - err: fmt.Errorf("failed to create update conditions for node \"fakeID-0\": Failed to update node"), + err: fmt.Errorf("failed to create/update conditions on node \"fakeID-0\": Failed to update node"), retry: machineutils.ShortRetry, machine: newMachine( &v1alpha1.MachineTemplateSpec{ @@ -2801,7 +2801,7 @@ var _ = Describe("machine", func() { LastUpdateTime: metav1.Now(), }, LastOperation: v1alpha1.LastOperation{ - Description: fmt.Sprintf("Drain failed due to failure in update of node conditions - %s. Will retry in next sync. %s", "failed to create update conditions for node \"fakeID-0\": Failed to update node", machineutils.InitiateDrain), + Description: fmt.Sprintf("Drain failed due to failure in update of node conditions - %s. Will retry in next sync. %s", "failed to create/update conditions on node \"fakeID-0\": Failed to update node", machineutils.InitiateDrain), State: v1alpha1.MachineStateFailed, Type: v1alpha1.MachineOperationDelete, LastUpdateTime: metav1.Now(), @@ -2996,7 +2996,7 @@ var _ = Describe("machine", func() { }, }, expect: expect{ - err: fmt.Errorf("failed to create update conditions for node \"fakeNode-0\": Failed to update node"), + err: fmt.Errorf("failed to create/update conditions on node \"fakeNode-0\": Failed to update node"), retry: machineutils.ShortRetry, machine: newMachine( &v1alpha1.MachineTemplateSpec{ @@ -3015,7 +3015,7 @@ var _ = Describe("machine", func() { LastUpdateTime: metav1.Now(), }, LastOperation: v1alpha1.LastOperation{ - Description: fmt.Sprintf("Drain failed due to failure in update of node conditions - %s. Will retry in next sync. %s", "failed to create update conditions for node \"fakeNode-0\": Failed to update node", machineutils.InitiateDrain), + Description: fmt.Sprintf("Drain failed due to failure in update of node conditions - %s. Will retry in next sync. %s", "failed to create/update conditions on node \"fakeNode-0\": Failed to update node", machineutils.InitiateDrain), State: v1alpha1.MachineStateFailed, Type: v1alpha1.MachineOperationDelete, LastUpdateTime: metav1.Now(), diff --git a/pkg/util/provider/machinecontroller/machine_util.go b/pkg/util/provider/machinecontroller/machine_util.go index dda97a607..4460a553d 100644 --- a/pkg/util/provider/machinecontroller/machine_util.go +++ b/pkg/util/provider/machinecontroller/machine_util.go @@ -993,7 +993,6 @@ func (c *controller) reconcileMachineHealth(ctx context.Context, machine *v1alph if err != nil { return machineutils.ShortRetry, err } - klog.V(3).Infof("TEST: preserved node uncordoned successfully %s", machine.Name) } } // Machine rejoined the cluster after a health-check @@ -2373,153 +2372,216 @@ func (c *controller) fetchMatchingNodeName(machineName string) (string, error) { return "", fmt.Errorf("machine %q not found in node lister for machine %q", machineName, machineName) } -// preserveMachine contains logic to start the preservation of a machine and node. It syncs node annotations to the machine if the backing node exists, -// or has an annotation related to preservation. -// it does not sync preserve annotation values from machine to node to prevent bi-directional syncing issues. +/* +SECTION +Utility Functions for Machine Preservation +*/ + +// preserveMachine contains logic to start the preservation of a machine and node. func (c *controller) preserveMachine(ctx context.Context, machine *v1alpha1.Machine, preserveValue string) (machineutils.RetryPeriod, error) { - klog.V(3).Infof("TEST: Entering preserve machine flow") + // Step 1: Set PreserveExpiryTime if !machineutils.IsPreserveExpiryTimeSet(machine) { - preservedCurrentStatus := v1alpha1.CurrentStatus{ - Phase: machine.Status.CurrentStatus.Phase, - LastUpdateTime: metav1.Now(), - PreserveExpiryTime: metav1.NewTime(metav1.Now().Add(c.getEffectiveMachinePreserveTimeout(machine).Duration)), - } - clone := machine.DeepCopy() - clone.Status.CurrentStatus = preservedCurrentStatus - _, err := c.controlMachineClient.Machines(clone.Namespace).UpdateStatus(ctx, clone, metav1.UpdateOptions{}) + _, retry, err := c.setPreserveExpiryTime(ctx, machine) if err != nil { - klog.Warningf("Machine/status UPDATE failed for machine %q. Retrying, error: %s", machine.Name, err) - return machineutils.ConflictRetry, err + return retry, err } - klog.V(3).Infof("Machine %q preserved till %v.", machine.Name, preservedCurrentStatus.PreserveExpiryTime) } - klog.V(3).Infof("TEST: preserveexpiry set for machine %q", machine.Name) - if machine.Labels[v1alpha1.NodeLabelKey] != "" { - nodeName := machine.Labels[v1alpha1.NodeLabelKey] - node, err := c.nodeLister.Get(nodeName) + if machine.Labels[v1alpha1.NodeLabelKey] == "" { + return machineutils.LongRetry, nil + } + nodeName := machine.Labels[v1alpha1.NodeLabelKey] + node, err := c.nodeLister.Get(nodeName) + if err != nil { + klog.Errorf("error trying to get node %q of machine %q: %v. Retrying.", nodeName, machine.Name, err) + return machineutils.ShortRetry, err + } + // Step 2: Add annotations to prevent scale down of node by CA + _, retry, err := c.addCAScaleDownDisabledAnnotationOnNode(ctx, node) + if err != nil { + return retry, err + } + existingNodePreservedCondition, err := nodeops.GetNodeCondition(ctx, c.targetCoreClient, getNodeName(machine), v1alpha1.NodePreserved) + if err != nil { + klog.Errorf("error trying to get existing node preserved condition for node %q of machine %q: %v", nodeName, machine.Name, err) + return machineutils.ShortRetry, err + } + drainSuccessful := false + // Step 3: If machine is in Failed Phase, drain the backing node + if c.shouldNodeBeDrained(machine, existingNodePreservedCondition) { + err = c.drainPreservedNode(ctx, machine) if err != nil { - klog.Errorf("error trying to get node %q: %v", nodeName, err) + retry, err = c.updateNodePreservedCondition(ctx, machine, preserveValue, drainSuccessful, existingNodePreservedCondition) + if err != nil { + return retry, err + } return machineutils.ShortRetry, err } - nodeCopy := node.DeepCopy() - // not updating node's preserve annotations here in case operator is manipulating machine annotations only - // if node annotation is updated, machine annotation will be overwritten with this value even if operator wants it to change - // function never returns error, can be ignored - if nodeCopy.Annotations[autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationKey] != autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationValue { - CAScaleDownAnnotation := make(map[string]string) - CAScaleDownAnnotation[autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationKey] = autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationValue - updatedNode, _, _ := annotations.AddOrUpdateAnnotation(nodeCopy, CAScaleDownAnnotation) - _, err = c.targetCoreClient.CoreV1().Nodes().Update(ctx, updatedNode, metav1.UpdateOptions{}) - if err != nil { - if apierrors.IsConflict(err) { - return machineutils.ConflictRetry, err - } - klog.Errorf("node UPDATE failed for machine %s with node %s. Retrying, error: %s", machine.Name, nodeName, err) - return machineutils.ShortRetry, err + drainSuccessful = true + } + // Step 4: Update NodePreserved Condition on Node + retry, err = c.updateNodePreservedCondition(ctx, machine, preserveValue, drainSuccessful, existingNodePreservedCondition) + if err != nil { + return retry, err + } + klog.V(3).Infof("Machine %s preserved successfully.", machine.Name) + return machineutils.LongRetry, nil +} + +// setPreserveExpiryTime sets the PreserveExpiryTime on the machine object's Status.CurrentStatus to now + preserve timeout +func (c *controller) setPreserveExpiryTime(ctx context.Context, machine *v1alpha1.Machine) (*v1alpha1.Machine, machineutils.RetryPeriod, error) { + preservedCurrentStatus := v1alpha1.CurrentStatus{ + Phase: machine.Status.CurrentStatus.Phase, + TimeoutActive: machine.Status.CurrentStatus.TimeoutActive, + LastUpdateTime: metav1.Now(), + PreserveExpiryTime: metav1.NewTime(metav1.Now().Add(c.getEffectiveMachinePreserveTimeout(machine).Duration)), + } + clone := machine.DeepCopy() + clone.Status.CurrentStatus = preservedCurrentStatus + _, err := c.controlMachineClient.Machines(clone.Namespace).UpdateStatus(ctx, clone, metav1.UpdateOptions{}) + if err != nil { + klog.Errorf("machine/status UPDATE failed for machine %q. Retrying, error: %s", machine.Name, err) + if apierrors.IsConflict(err) { + return nil, machineutils.ConflictRetry, err + } + return nil, machineutils.ShortRetry, err + } + klog.V(4).Infof("Machine %q preserved till %v.", machine.Name, preservedCurrentStatus.PreserveExpiryTime) + return clone, machineutils.LongRetry, nil +} + +// addCAScaleDownDisabledAnnotationOnNode adds the cluster-autoscaler annotation to disable scale down of preserved node +func (c *controller) addCAScaleDownDisabledAnnotationOnNode(ctx context.Context, node *v1.Node) (*v1.Node, machineutils.RetryPeriod, error) { + nodeCopy := node.DeepCopy() + if nodeCopy.Annotations == nil || nodeCopy.Annotations[autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationKey] != autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationValue { + CAScaleDownAnnotation := map[string]string{ + autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationKey: autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationValue, + } + updatedNode, _, _ := annotations.AddOrUpdateAnnotation(nodeCopy, CAScaleDownAnnotation) + _, err := c.targetCoreClient.CoreV1().Nodes().Update(ctx, updatedNode, metav1.UpdateOptions{}) + if err != nil { + klog.Errorf("error trying to update CA annotation on node %q: %v", updatedNode.Name, err) + if apierrors.IsConflict(err) { + return nil, machineutils.ConflictRetry, err } - klog.V(2).Infof("Updated CA annotations for node %s, for machine %q, successfully", nodeCopy.Name, machine.Name) + return nil, machineutils.ShortRetry, err } - newNodePreservedCondition := v1.NodeCondition{ + return updatedNode, machineutils.LongRetry, nil + } + return node, machineutils.LongRetry, nil +} + +// getNewNodePreservedCondition returns the NodeCondition with the values set according to the preserveValue and the stage of Preservation +func (c *controller) updateNodePreservedCondition(ctx context.Context, machine *v1alpha1.Machine, preserveValue string, drainSuccessful bool, existingNodeCondition *v1.NodeCondition) (machineutils.RetryPeriod, error) { + var newNodePreservedCondition *v1.NodeCondition + var changed bool + if existingNodeCondition == nil { + newNodePreservedCondition = &v1.NodeCondition{ Type: v1alpha1.NodePreserved, - Status: v1.ConditionTrue, + Status: v1.ConditionFalse, LastTransitionTime: metav1.Now(), } + changed = true + } else { + newNodePreservedCondition = existingNodeCondition.DeepCopy() + } + if machine.Status.CurrentStatus.Phase == v1alpha1.MachineFailed { + if drainSuccessful { + if newNodePreservedCondition.Message != v1alpha1.PreservedNodeDrainSuccessful { + newNodePreservedCondition.Message = v1alpha1.PreservedNodeDrainSuccessful + newNodePreservedCondition.Status = v1.ConditionTrue + changed = true + } + } else if newNodePreservedCondition.Status != v1.ConditionFalse { + newNodePreservedCondition.Message = v1alpha1.PreservedNodeDrainUnsuccessful + newNodePreservedCondition.Status = v1.ConditionFalse + changed = true + } + } else if newNodePreservedCondition.Status != v1.ConditionTrue { + newNodePreservedCondition.Status = v1.ConditionTrue + changed = true + } + if changed { if preserveValue != machineutils.PreserveMachineAnnotationValuePreservedByMCM { newNodePreservedCondition.Reason = v1alpha1.NodePreservedByUser } else { newNodePreservedCondition.Reason = v1alpha1.NodePreservedByMCM } - // drain node only if machine has failed - if machine.Status.CurrentStatus.Phase == v1alpha1.MachineFailed { - existingNodePreservedCondition, err := nodeops.GetNodeCondition(ctx, c.targetCoreClient, getNodeName(machine), v1alpha1.NodePreserved) - if err != nil { - klog.V(3).Infof("Error trying to get node preserved condition for machine %s: %v", machine.Name, err) - return machineutils.ShortRetry, err - } - if existingNodePreservedCondition != nil && existingNodePreservedCondition.Message != v1alpha1.PreservedNodeDrainSuccessful { - klog.V(2).Infof("TEST: drainPreservedNode Successful %s", machine.Name) - newNodePreservedCondition.Message = v1alpha1.PreservedNodeDrainSuccessful - } else { - err = c.drainPreservedNode(ctx, machine) - if err != nil { - klog.V(3).Infof("TEST: drain failed with error:%s", err) - // drain not successful, retry - // if node condition of NodePreserved is not set, set it: - if existingNodePreservedCondition == nil { - if err = nodeops.AddOrUpdateConditionsOnNode(ctx, c.targetCoreClient, getNodeName(machine), newNodePreservedCondition); err != nil { - klog.V(3).Infof("TEST: updating node with preserved condition failed: %s", err) - return machineutils.ShortRetry, err - } - } - return machineutils.ShortRetry, err - } + if err := nodeops.AddOrUpdateConditionsOnNode(ctx, c.targetCoreClient, getNodeName(machine), *newNodePreservedCondition); err != nil { + klog.Errorf("error trying to update node preserved condition for node %q of machine %q : %v", getNodeName(machine), machine.Name, err) + if apierrors.IsConflict(err) { + return machineutils.ConflictRetry, err } - } - if err = nodeops.AddOrUpdateConditionsOnNode(ctx, c.targetCoreClient, getNodeName(machine), newNodePreservedCondition); err != nil { - klog.V(3).Infof("TEST: updating node with preserved condition failed: %s", err) return machineutils.ShortRetry, err } - klog.V(3).Infof("TEST: updating machine %q with new node condition was successful", machine.Name) } return machineutils.LongRetry, nil } +// shouldNodeBeDrained returns true if the machine's backing node must be drained, else false +func (c *controller) shouldNodeBeDrained(machine *v1alpha1.Machine, existingCondition *v1.NodeCondition) bool { + if machine.Status.CurrentStatus.Phase == v1alpha1.MachineFailed { + if existingCondition == nil { + return true + } + if existingCondition.Message == v1alpha1.PreservedNodeDrainSuccessful { + return false + } else { + return true + } + } + return false +} + +// stopMachinePreservation stops the preservation of the machine and node func (c *controller) stopMachinePreservation(ctx context.Context, machine *v1alpha1.Machine) (machineutils.RetryPeriod, error) { // check if preserveExpiryTime is set, if not, no need to do anything if !machineutils.IsPreserveExpiryTimeSet(machine) { return machineutils.LongRetry, nil } - klog.V(3).Infof("TEST: stopping preservation machine %q", machine.Name) - // if backing node exists, remove annotations that would prevent scale down by autoscaler if machine.Labels[v1alpha1.NodeLabelKey] != "" { nodeName := machine.Labels[v1alpha1.NodeLabelKey] - node, err := c.nodeLister.Get(nodeName) - if err != nil { - klog.Errorf("error trying to get backing node %q for machine %s. error: %v", nodeName, machine.Name, err) - return machineutils.ShortRetry, err - } preservedCondition := v1.NodeCondition{ Type: v1alpha1.NodePreserved, Status: v1.ConditionFalse, LastTransitionTime: metav1.Now(), } - err = nodeops.AddOrUpdateConditionsOnNode(ctx, c.targetCoreClient, getNodeName(machine), preservedCondition) + // Step 1: if backing node exists, change node condition to reflect that preservation has stopped + err := nodeops.AddOrUpdateConditionsOnNode(ctx, c.targetCoreClient, getNodeName(machine), preservedCondition) if err != nil { - klog.Warningf("Node/status UPDATE failed for machine %q. Retrying, error: %s", machine.Name, err) return machineutils.ShortRetry, err } - klog.V(3).Infof("Updated Node Condition NodePreserved for node %s, for machine %q, successfully", node.Name, machine.Name) - // remove CA annotation from node, values do not matter here + // Step 2: remove CA's scale-down disabled annotations to allow CA to scale down node if needed CAAnnotations := make(map[string]string) CAAnnotations[autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationKey] = "" latestNode, err := c.targetCoreClient.CoreV1().Nodes().Get(ctx, nodeName, metav1.GetOptions{}) if err != nil { - klog.Errorf("error trying to get backing node %q for machine %s. error: %v", nodeName, machine.Name, err) + klog.Errorf("error trying to get backing node %q for machine %s. Retrying, error: %v", nodeName, machine.Name, err) return machineutils.ShortRetry, err } latestNodeCopy := latestNode.DeepCopy() latestNodeCopy, _, _ = annotations.RemoveAnnotation(latestNodeCopy, CAAnnotations) // error can be ignored, always returns nil _, err = c.targetCoreClient.CoreV1().Nodes().Update(ctx, latestNodeCopy, metav1.UpdateOptions{}) if err != nil { - klog.Warningf("Node UPDATE failed for machine %q. Retrying, error: %s", machine.Name, err) + klog.Errorf("Node UPDATE failed for node %q of machine %q. Retrying, error: %s", nodeName, machine.Name, err) if apierrors.IsConflict(err) { return machineutils.ConflictRetry, err } return machineutils.ShortRetry, err } } + // Step 3: update machine status to set preserve expiry time to metav1.Time{} clone := machine.DeepCopy() clone.Status.CurrentStatus = v1alpha1.CurrentStatus{ - Phase: machine.Status.CurrentStatus.Phase, + Phase: clone.Status.CurrentStatus.Phase, LastUpdateTime: metav1.Now(), PreserveExpiryTime: metav1.Time{}, } _, err := c.controlMachineClient.Machines(clone.Namespace).UpdateStatus(ctx, clone, metav1.UpdateOptions{}) if err != nil { - klog.Warningf("Machine/status UPDATE failed for machine %q. Retrying, error: %s", machine.Name, err) + klog.Errorf("machine/status UPDATE failed for machine %q. Retrying, error: %s", machine.Name, err) return machineutils.ConflictRetry, err } - klog.V(3).Infof("Machine status updated to stop preservation for machine %q", clone.Name) + klog.V(3).Infof("Machine status updated to stop preservation for machine %q", machine.Name) return machineutils.LongRetry, nil } @@ -2568,11 +2630,9 @@ func (c *controller) drainPreservedNode(ctx context.Context, machine *v1alpha1.M printLogInitError(message, &err, &description, machine, true) } - // TODO@thiyyakat: how to calculate timeout? In the case of preserve=now, preserveexpirytime will not coincide with time of failure in which case pods will et force + // TODO@thiyyakat: how to calculate timeout? In the case of preserve=now, PreserveExpiryTime will not coincide with time of failure in which case pods will get force // drained. - // current solution: since we want to know when machine transitioned to Failed, using lastupdatetime. - // in the case of preserve=now, preserveExpiryTime is set from the time the annotation is added, and can't tell us when - // machine moved to Failed + // current solution: since we want to know when machine transitioned to Failed, the code uses LastUpdateTime. timeOutOccurred = utiltime.HasTimeOutOccurred(machine.Status.CurrentStatus.LastUpdateTime, timeOutDuration) if forceDrainLabelPresent || timeOutOccurred { forceDeletePods = true @@ -2637,6 +2697,7 @@ func (c *controller) drainPreservedNode(ctx context.Context, machine *v1alpha1.M return nil } +// hasMachinePreservationTimedOut returns true if preserve expiry time has lapsed func hasMachinePreservationTimedOut(machine *v1alpha1.Machine) bool { return machineutils.IsPreserveExpiryTimeSet(machine) && metav1.Now().After(machine.Status.CurrentStatus.PreserveExpiryTime.Time) } diff --git a/pkg/util/provider/machineutils/utils.go b/pkg/util/provider/machineutils/utils.go index 75e68493f..429f50acb 100644 --- a/pkg/util/provider/machineutils/utils.go +++ b/pkg/util/provider/machineutils/utils.go @@ -6,7 +6,6 @@ package machineutils import ( - "k8s.io/klog/v2" "time" v1 "k8s.io/api/core/v1" @@ -148,7 +147,6 @@ func IsMachineTriggeredForDeletion(m *v1alpha1.Machine) bool { // IsPreserveExpiryTimeSet checks if machine is preserved by MCM func IsPreserveExpiryTimeSet(m *v1alpha1.Machine) bool { - klog.V(3).Infof("Preserve Expiry Time: %v, machine: %s", m.Status.CurrentStatus.PreserveExpiryTime, m.Name) return !m.Status.CurrentStatus.PreserveExpiryTime.IsZero() } From 15a3ea2ef706a188798e488c5f2153b968c714fe Mon Sep 17 00:00:00 2001 From: thiyyakat Date: Wed, 10 Dec 2025 13:27:04 +0530 Subject: [PATCH 22/43] Fix bug so that recovered preserved nodes are uncordoned --- .../provider/machinecontroller/machine_util.go | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/pkg/util/provider/machinecontroller/machine_util.go b/pkg/util/provider/machinecontroller/machine_util.go index 4460a553d..652248f99 100644 --- a/pkg/util/provider/machinecontroller/machine_util.go +++ b/pkg/util/provider/machinecontroller/machine_util.go @@ -983,17 +983,15 @@ func (c *controller) reconcileMachineHealth(ctx context.Context, machine *v1alph klog.Warning(err) } } else { - // if machine was auto-preserved (which means it is in Failed phase), stop preservation + // if machine was preserved (which means it is in Failed phase), uncordon node so that pods can be scheduled on it again if cond := nodeops.GetCondition(node, v1alpha1.NodePreserved); cond != nil && machine.Status.CurrentStatus.Phase == v1alpha1.MachineFailed { - if cond.Reason == v1alpha1.NodePreservedByMCM { - // need to uncordon node - nodeCopy := node.DeepCopy() - nodeCopy.Spec.Unschedulable = false - _, err = c.targetCoreClient.CoreV1().Nodes().Update(ctx, nodeCopy, metav1.UpdateOptions{}) - if err != nil { - return machineutils.ShortRetry, err - } + nodeCopy := node.DeepCopy() + nodeCopy.Spec.Unschedulable = false + _, err = c.targetCoreClient.CoreV1().Nodes().Update(ctx, nodeCopy, metav1.UpdateOptions{}) + if err != nil { + return machineutils.ShortRetry, err } + } // Machine rejoined the cluster after a health-check description = fmt.Sprintf("Machine %s successfully re-joined the cluster", clone.Name) From 9e4ee5c1e52f3ed95ecf29b4f3f6c9b716a9b1fb Mon Sep 17 00:00:00 2001 From: thiyyakat Date: Wed, 10 Dec 2025 15:01:40 +0530 Subject: [PATCH 23/43] Minor changes --- Makefile | 6 +++--- pkg/controller/machineset.go | 3 --- pkg/util/provider/machinecontroller/machine_util.go | 7 ++----- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/Makefile b/Makefile index 6b0f4f913..aba0236ac 100644 --- a/Makefile +++ b/Makefile @@ -172,9 +172,9 @@ test-clean: .PHONY: generate generate: $(VGOPATH) $(DEEPCOPY_GEN) $(DEFAULTER_GEN) $(CONVERSION_GEN) $(OPENAPI_GEN) $(CONTROLLER_GEN) $(GEN_CRD_API_REFERENCE_DOCS) - GOFLAGS="-buildvcs=false" $(CONTROLLER_GEN) crd paths=./pkg/apis/machine/v1alpha1/... output:crd:dir=kubernetes/crds output:stdout - @GOFLAGS="-buildvcs=false" ./hack/generate-code - @GOFLAGS="-buildvcs=false" ./hack/api-reference/generate-spec-doc.sh + $(CONTROLLER_GEN) crd paths=./pkg/apis/machine/v1alpha1/... output:crd:dir=kubernetes/crds output:stdout + @./hack/generate-code + @./hack/api-reference/generate-spec-doc.sh .PHONY: add-license-headers add-license-headers: $(GO_ADD_LICENSE) diff --git a/pkg/controller/machineset.go b/pkg/controller/machineset.go index 3e255f227..f13aba13f 100644 --- a/pkg/controller/machineset.go +++ b/pkg/controller/machineset.go @@ -719,9 +719,6 @@ func getMachinesToDelete(filteredMachines []*v1alpha1.Machine, diff int) []*v1al // at all times, replica count will be upheld, even if it means deletion of a pending machine // TODO@thiyyakat: write unit test for this scenario filteredMachines = prioritisePreservedMachines(filteredMachines) - - fmt.Printf("len(filteredMachines)=%d, diff=%d\n", len(filteredMachines), diff) - } return filteredMachines[:diff] } diff --git a/pkg/util/provider/machinecontroller/machine_util.go b/pkg/util/provider/machinecontroller/machine_util.go index 652248f99..e5d88125d 100644 --- a/pkg/util/provider/machinecontroller/machine_util.go +++ b/pkg/util/provider/machinecontroller/machine_util.go @@ -212,7 +212,6 @@ func nodeConditionsHaveChanged(oldConditions []v1.NodeCondition, newConditions [ if !exists || (oldC.Status != c.Status) || (c.Type == v1alpha1.NodeInPlaceUpdate && oldC.Reason != c.Reason) { addedOrUpdatedConditions = append(addedOrUpdatedConditions, c) } - } // checking for any deleted condition @@ -991,7 +990,6 @@ func (c *controller) reconcileMachineHealth(ctx context.Context, machine *v1alph if err != nil { return machineutils.ShortRetry, err } - } // Machine rejoined the cluster after a health-check description = fmt.Sprintf("Machine %s successfully re-joined the cluster", clone.Name) @@ -1037,7 +1035,6 @@ func (c *controller) reconcileMachineHealth(ctx context.Context, machine *v1alph } } } - } if !cloneDirty && (machine.Status.CurrentStatus.Phase == v1alpha1.MachineInPlaceUpdating || @@ -1172,7 +1169,7 @@ func (c *controller) reconcileMachineHealth(ctx context.Context, machine *v1alph } if cloneDirty { - updatedMachine, err := c.controlMachineClient.Machines(clone.Namespace).UpdateStatus(ctx, clone, metav1.UpdateOptions{}) + _, err := c.controlMachineClient.Machines(clone.Namespace).UpdateStatus(ctx, clone, metav1.UpdateOptions{}) if err != nil { // Keep retrying across reconciles until update goes through klog.Errorf("Update of Phase/Conditions failed for machine %q. Retrying, error: %q", machine.Name, err) @@ -1181,7 +1178,7 @@ func (c *controller) reconcileMachineHealth(ctx context.Context, machine *v1alph } return machineutils.ShortRetry, err } else { - klog.V(2).Infof("Machine Phase/Conditions have been updated for %q with providerID %q and are in sync with backing node %q", updatedMachine.Name, getProviderID(updatedMachine), getNodeName(updatedMachine)) + klog.V(2).Infof("Machine Phase/Conditions have been updated for %q with providerID %q and are in sync with backing node %q", machine.Name, getProviderID(machine), getNodeName(machine)) err = errSuccessfulPhaseUpdate } return machineutils.ShortRetry, err From 1a524636436fd31321fd76eeae87fc9aa20753c9 Mon Sep 17 00:00:00 2001 From: thiyyakat Date: Wed, 10 Dec 2025 15:48:56 +0530 Subject: [PATCH 24/43] Change verb used in log statements for machine/node name --- pkg/controller/machineset.go | 4 ++-- pkg/util/provider/machinecontroller/machine.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/controller/machineset.go b/pkg/controller/machineset.go index f13aba13f..81ab171dc 100644 --- a/pkg/controller/machineset.go +++ b/pkg/controller/machineset.go @@ -494,7 +494,7 @@ func (c *controller) manageReplicas(ctx context.Context, allMachines []*v1alpha1 // TODO@thiyyakat: find more suitable name for function func (c *controller) isMachineCandidateForPreservation(ctx context.Context, machineSet *v1alpha1.MachineSet, machine *v1alpha1.Machine) (bool, error) { if machineutils.IsPreserveExpiryTimeSet(machine) && !machineutils.HasPreservationTimedOut(machine) { - klog.V(3).Infof("Machine %s is preserved until %v, not adding to stale machines", machine.Name, machine.Status.CurrentStatus.PreserveExpiryTime) + klog.V(3).Infof("Machine %q is preserved until %v, not adding to stale machines", machine.Name, machine.Status.CurrentStatus.PreserveExpiryTime) return true, nil } val, exists := machine.Annotations[machineutils.PreserveMachineAnnotationKey] @@ -977,7 +977,7 @@ func (dc *controller) annotateMachineForAutoPreservation(ctx context.Context, m if err != nil { return nil, err } - klog.V(2).Infof("Updated machine %s with auto-preserve annotation.", m.Name) + klog.V(2).Infof("Updated machine %q with auto-preserved annotation.", m.Name) return updatedMachine, nil } diff --git a/pkg/util/provider/machinecontroller/machine.go b/pkg/util/provider/machinecontroller/machine.go index 5b9f56611..a260b3341 100644 --- a/pkg/util/provider/machinecontroller/machine.go +++ b/pkg/util/provider/machinecontroller/machine.go @@ -77,7 +77,7 @@ func (c *controller) updateMachine(oldObj, newObj any) { } if oldMachine.Generation == newMachine.Generation { - klog.V(3).Infof("Skipping other non-spec updates for machine %s", oldMachine.Name) + klog.V(3).Infof("Skipping other non-spec updates for machine %q", oldMachine.Name) return } From e66e2b7befd725454c5a7b332ceaeb858bb106ca Mon Sep 17 00:00:00 2001 From: thiyyakat Date: Wed, 10 Dec 2025 16:57:17 +0530 Subject: [PATCH 25/43] Fix mistake made during rebasing --- .../provider/machinecontroller/machine_util.go | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/pkg/util/provider/machinecontroller/machine_util.go b/pkg/util/provider/machinecontroller/machine_util.go index e5d88125d..f99635a67 100644 --- a/pkg/util/provider/machinecontroller/machine_util.go +++ b/pkg/util/provider/machinecontroller/machine_util.go @@ -28,9 +28,9 @@ import ( "encoding/json" "errors" "fmt" - "maps" "github.com/gardener/machine-controller-manager/pkg/controller/autoscaler" "github.com/gardener/machine-controller-manager/pkg/util/annotations" + "maps" "math" "runtime" "strconv" @@ -982,7 +982,7 @@ func (c *controller) reconcileMachineHealth(ctx context.Context, machine *v1alph klog.Warning(err) } } else { - // if machine was preserved (which means it is in Failed phase), uncordon node so that pods can be scheduled on it again + // if machine was preserved and in Failed phase, uncordon node so that pods can be scheduled on it again if cond := nodeops.GetCondition(node, v1alpha1.NodePreserved); cond != nil && machine.Status.CurrentStatus.Phase == v1alpha1.MachineFailed { nodeCopy := node.DeepCopy() nodeCopy.Spec.Unschedulable = false @@ -1110,11 +1110,7 @@ func (c *controller) reconcileMachineHealth(ctx context.Context, machine *v1alph machineDeployName := getMachineDeploymentName(machine) // creating lock for machineDeployment, if not allocated c.permitGiver.RegisterPermits(machineDeployName, 1) - retry, err := c.tryMarkingMachineFailed(ctx, machine, clone, machineDeployName, description, lockAcquireTimeout) - if err != nil { - return retry, err - } - return retry, err + return c.tryMarkingMachineFailed(ctx, machine, clone, machineDeployName, description, lockAcquireTimeout) } if isMachineInPlaceUpdating { @@ -1169,20 +1165,19 @@ func (c *controller) reconcileMachineHealth(ctx context.Context, machine *v1alph } if cloneDirty { - _, err := c.controlMachineClient.Machines(clone.Namespace).UpdateStatus(ctx, clone, metav1.UpdateOptions{}) + _, err = c.controlMachineClient.Machines(clone.Namespace).UpdateStatus(ctx, clone, metav1.UpdateOptions{}) if err != nil { // Keep retrying across reconciles until update goes through klog.Errorf("Update of Phase/Conditions failed for machine %q. Retrying, error: %q", machine.Name, err) if apierrors.IsConflict(err) { return machineutils.ConflictRetry, err } - return machineutils.ShortRetry, err } else { klog.V(2).Infof("Machine Phase/Conditions have been updated for %q with providerID %q and are in sync with backing node %q", machine.Name, getProviderID(machine), getNodeName(machine)) + // Return error to end the reconcile err = errSuccessfulPhaseUpdate } return machineutils.ShortRetry, err - // Return error to end the reconcile } return machineutils.LongRetry, nil } From ead3648844d6773e39266c5dea74facceab3ee2e Mon Sep 17 00:00:00 2001 From: thiyyakat Date: Thu, 11 Dec 2025 13:03:54 +0530 Subject: [PATCH 26/43] Change return types of preservation util functions such that only caller returns retry period --- pkg/controller/machineset.go | 2 +- .../provider/machinecontroller/machine.go | 32 +++++++- .../machinecontroller/machine_util.go | 75 ++++++++----------- 3 files changed, 59 insertions(+), 50 deletions(-) diff --git a/pkg/controller/machineset.go b/pkg/controller/machineset.go index 81ab171dc..1884f3633 100644 --- a/pkg/controller/machineset.go +++ b/pkg/controller/machineset.go @@ -640,7 +640,7 @@ func (c *controller) reconcileClusterMachineSet(key string) error { // Multiple things could lead to this update failing. Requeuing the machine set ensures // Returning an error causes a requeue without forcing a hotloop if !apierrors.IsNotFound(err) { - klog.Errorf("Update machineSet %s failed with: %s", machineSet.Name, err) + klog.Errorf("update machineSet %s failed with: %s", machineSet.Name, err) } return err } diff --git a/pkg/util/provider/machinecontroller/machine.go b/pkg/util/provider/machinecontroller/machine.go index a260b3341..f723bccba 100644 --- a/pkg/util/provider/machinecontroller/machine.go +++ b/pkg/util/provider/machinecontroller/machine.go @@ -811,7 +811,13 @@ func (c *controller) manageMachinePreservation(ctx context.Context, machine *v1a // if preserve annotation value has switched from now to when-failed, then stop preservation if preserveValue == machineutils.PreserveMachineAnnotationValueWhenFailed && !machineutils.IsMachineFailed(updatedMachine) { if machineutils.IsPreserveExpiryTimeSet(updatedMachine) { - return c.stopMachinePreservation(ctx, updatedMachine) + err = c.stopMachinePreservation(ctx, updatedMachine) + if err != nil { + if apierrors.IsConflict(err) { + return machineutils.ConflictRetry, nil + } + return machineutils.ShortRetry, err + } } return machineutils.LongRetry, nil } @@ -820,13 +826,31 @@ func (c *controller) manageMachinePreservation(ctx context.Context, machine *v1a return machineutils.ShortRetry, err } if !isComplete { - return c.preserveMachine(ctx, machine, preserveValue) + err = c.preserveMachine(ctx, machine, preserveValue) + if err != nil { + if apierrors.IsConflict(err) { + return machineutils.ConflictRetry, nil + } + return machineutils.ShortRetry, err + } } if hasMachinePreservationTimedOut(machine) { - return c.stopMachinePreservation(ctx, updatedMachine) + err = c.stopMachinePreservation(ctx, updatedMachine) + if err != nil { + if apierrors.IsConflict(err) { + return machineutils.ConflictRetry, nil + } + return machineutils.ShortRetry, err + } } case machineutils.PreserveMachineAnnotationValueFalse: - return c.stopMachinePreservation(ctx, updatedMachine) + err = c.stopMachinePreservation(ctx, updatedMachine) + if err != nil { + if apierrors.IsConflict(err) { + return machineutils.ConflictRetry, nil + } + return machineutils.ShortRetry, err + } case "": return machineutils.LongRetry, nil default: diff --git a/pkg/util/provider/machinecontroller/machine_util.go b/pkg/util/provider/machinecontroller/machine_util.go index f99635a67..0271c1b2a 100644 --- a/pkg/util/provider/machinecontroller/machine_util.go +++ b/pkg/util/provider/machinecontroller/machine_util.go @@ -2368,57 +2368,54 @@ Utility Functions for Machine Preservation */ // preserveMachine contains logic to start the preservation of a machine and node. -func (c *controller) preserveMachine(ctx context.Context, machine *v1alpha1.Machine, preserveValue string) (machineutils.RetryPeriod, error) { +func (c *controller) preserveMachine(ctx context.Context, machine *v1alpha1.Machine, preserveValue string) error { // Step 1: Set PreserveExpiryTime if !machineutils.IsPreserveExpiryTimeSet(machine) { - _, retry, err := c.setPreserveExpiryTime(ctx, machine) + _, err := c.setPreserveExpiryTime(ctx, machine) if err != nil { - return retry, err + return err } } if machine.Labels[v1alpha1.NodeLabelKey] == "" { - return machineutils.LongRetry, nil + return nil } nodeName := machine.Labels[v1alpha1.NodeLabelKey] node, err := c.nodeLister.Get(nodeName) if err != nil { klog.Errorf("error trying to get node %q of machine %q: %v. Retrying.", nodeName, machine.Name, err) - return machineutils.ShortRetry, err + return err } // Step 2: Add annotations to prevent scale down of node by CA - _, retry, err := c.addCAScaleDownDisabledAnnotationOnNode(ctx, node) + _, err = c.addCAScaleDownDisabledAnnotationOnNode(ctx, node) if err != nil { - return retry, err + return err } existingNodePreservedCondition, err := nodeops.GetNodeCondition(ctx, c.targetCoreClient, getNodeName(machine), v1alpha1.NodePreserved) if err != nil { klog.Errorf("error trying to get existing node preserved condition for node %q of machine %q: %v", nodeName, machine.Name, err) - return machineutils.ShortRetry, err + return err } drainSuccessful := false // Step 3: If machine is in Failed Phase, drain the backing node if c.shouldNodeBeDrained(machine, existingNodePreservedCondition) { err = c.drainPreservedNode(ctx, machine) if err != nil { - retry, err = c.updateNodePreservedCondition(ctx, machine, preserveValue, drainSuccessful, existingNodePreservedCondition) - if err != nil { - return retry, err - } - return machineutils.ShortRetry, err + _ = c.updateNodePreservedCondition(ctx, machine, preserveValue, drainSuccessful, existingNodePreservedCondition) + return err } drainSuccessful = true } // Step 4: Update NodePreserved Condition on Node - retry, err = c.updateNodePreservedCondition(ctx, machine, preserveValue, drainSuccessful, existingNodePreservedCondition) + err = c.updateNodePreservedCondition(ctx, machine, preserveValue, drainSuccessful, existingNodePreservedCondition) if err != nil { - return retry, err + return err } klog.V(3).Infof("Machine %s preserved successfully.", machine.Name) - return machineutils.LongRetry, nil + return nil } // setPreserveExpiryTime sets the PreserveExpiryTime on the machine object's Status.CurrentStatus to now + preserve timeout -func (c *controller) setPreserveExpiryTime(ctx context.Context, machine *v1alpha1.Machine) (*v1alpha1.Machine, machineutils.RetryPeriod, error) { +func (c *controller) setPreserveExpiryTime(ctx context.Context, machine *v1alpha1.Machine) (*v1alpha1.Machine, error) { preservedCurrentStatus := v1alpha1.CurrentStatus{ Phase: machine.Status.CurrentStatus.Phase, TimeoutActive: machine.Status.CurrentStatus.TimeoutActive, @@ -2430,17 +2427,14 @@ func (c *controller) setPreserveExpiryTime(ctx context.Context, machine *v1alpha _, err := c.controlMachineClient.Machines(clone.Namespace).UpdateStatus(ctx, clone, metav1.UpdateOptions{}) if err != nil { klog.Errorf("machine/status UPDATE failed for machine %q. Retrying, error: %s", machine.Name, err) - if apierrors.IsConflict(err) { - return nil, machineutils.ConflictRetry, err - } - return nil, machineutils.ShortRetry, err + return nil, err } klog.V(4).Infof("Machine %q preserved till %v.", machine.Name, preservedCurrentStatus.PreserveExpiryTime) - return clone, machineutils.LongRetry, nil + return clone, nil } // addCAScaleDownDisabledAnnotationOnNode adds the cluster-autoscaler annotation to disable scale down of preserved node -func (c *controller) addCAScaleDownDisabledAnnotationOnNode(ctx context.Context, node *v1.Node) (*v1.Node, machineutils.RetryPeriod, error) { +func (c *controller) addCAScaleDownDisabledAnnotationOnNode(ctx context.Context, node *v1.Node) (*v1.Node, error) { nodeCopy := node.DeepCopy() if nodeCopy.Annotations == nil || nodeCopy.Annotations[autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationKey] != autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationValue { CAScaleDownAnnotation := map[string]string{ @@ -2450,18 +2444,15 @@ func (c *controller) addCAScaleDownDisabledAnnotationOnNode(ctx context.Context, _, err := c.targetCoreClient.CoreV1().Nodes().Update(ctx, updatedNode, metav1.UpdateOptions{}) if err != nil { klog.Errorf("error trying to update CA annotation on node %q: %v", updatedNode.Name, err) - if apierrors.IsConflict(err) { - return nil, machineutils.ConflictRetry, err - } - return nil, machineutils.ShortRetry, err + return nil, err } - return updatedNode, machineutils.LongRetry, nil + return updatedNode, nil } - return node, machineutils.LongRetry, nil + return node, nil } // getNewNodePreservedCondition returns the NodeCondition with the values set according to the preserveValue and the stage of Preservation -func (c *controller) updateNodePreservedCondition(ctx context.Context, machine *v1alpha1.Machine, preserveValue string, drainSuccessful bool, existingNodeCondition *v1.NodeCondition) (machineutils.RetryPeriod, error) { +func (c *controller) updateNodePreservedCondition(ctx context.Context, machine *v1alpha1.Machine, preserveValue string, drainSuccessful bool, existingNodeCondition *v1.NodeCondition) error { var newNodePreservedCondition *v1.NodeCondition var changed bool if existingNodeCondition == nil { @@ -2498,13 +2489,10 @@ func (c *controller) updateNodePreservedCondition(ctx context.Context, machine * } if err := nodeops.AddOrUpdateConditionsOnNode(ctx, c.targetCoreClient, getNodeName(machine), *newNodePreservedCondition); err != nil { klog.Errorf("error trying to update node preserved condition for node %q of machine %q : %v", getNodeName(machine), machine.Name, err) - if apierrors.IsConflict(err) { - return machineutils.ConflictRetry, err - } - return machineutils.ShortRetry, err + return err } } - return machineutils.LongRetry, nil + return nil } // shouldNodeBeDrained returns true if the machine's backing node must be drained, else false @@ -2523,10 +2511,10 @@ func (c *controller) shouldNodeBeDrained(machine *v1alpha1.Machine, existingCond } // stopMachinePreservation stops the preservation of the machine and node -func (c *controller) stopMachinePreservation(ctx context.Context, machine *v1alpha1.Machine) (machineutils.RetryPeriod, error) { +func (c *controller) stopMachinePreservation(ctx context.Context, machine *v1alpha1.Machine) error { // check if preserveExpiryTime is set, if not, no need to do anything if !machineutils.IsPreserveExpiryTimeSet(machine) { - return machineutils.LongRetry, nil + return nil } if machine.Labels[v1alpha1.NodeLabelKey] != "" { nodeName := machine.Labels[v1alpha1.NodeLabelKey] @@ -2538,7 +2526,7 @@ func (c *controller) stopMachinePreservation(ctx context.Context, machine *v1alp // Step 1: if backing node exists, change node condition to reflect that preservation has stopped err := nodeops.AddOrUpdateConditionsOnNode(ctx, c.targetCoreClient, getNodeName(machine), preservedCondition) if err != nil { - return machineutils.ShortRetry, err + return err } // Step 2: remove CA's scale-down disabled annotations to allow CA to scale down node if needed CAAnnotations := make(map[string]string) @@ -2546,17 +2534,14 @@ func (c *controller) stopMachinePreservation(ctx context.Context, machine *v1alp latestNode, err := c.targetCoreClient.CoreV1().Nodes().Get(ctx, nodeName, metav1.GetOptions{}) if err != nil { klog.Errorf("error trying to get backing node %q for machine %s. Retrying, error: %v", nodeName, machine.Name, err) - return machineutils.ShortRetry, err + return err } latestNodeCopy := latestNode.DeepCopy() latestNodeCopy, _, _ = annotations.RemoveAnnotation(latestNodeCopy, CAAnnotations) // error can be ignored, always returns nil _, err = c.targetCoreClient.CoreV1().Nodes().Update(ctx, latestNodeCopy, metav1.UpdateOptions{}) if err != nil { klog.Errorf("Node UPDATE failed for node %q of machine %q. Retrying, error: %s", nodeName, machine.Name, err) - if apierrors.IsConflict(err) { - return machineutils.ConflictRetry, err - } - return machineutils.ShortRetry, err + return err } } // Step 3: update machine status to set preserve expiry time to metav1.Time{} @@ -2569,10 +2554,10 @@ func (c *controller) stopMachinePreservation(ctx context.Context, machine *v1alp _, err := c.controlMachineClient.Machines(clone.Namespace).UpdateStatus(ctx, clone, metav1.UpdateOptions{}) if err != nil { klog.Errorf("machine/status UPDATE failed for machine %q. Retrying, error: %s", machine.Name, err) - return machineutils.ConflictRetry, err + return err } klog.V(3).Infof("Machine status updated to stop preservation for machine %q", machine.Name) - return machineutils.LongRetry, nil + return nil } // drainPreservedNode attempts to drain the node backing a preserved machine From 9e44aeeacd246ad1c85db364ab9c48d646b64692 Mon Sep 17 00:00:00 2001 From: thiyyakat Date: Fri, 12 Dec 2025 10:12:30 +0530 Subject: [PATCH 27/43] Address review comments --- pkg/controller/deployment_machineset_util.go | 3 +- pkg/controller/machineset.go | 6 +- .../provider/machinecontroller/machine.go | 217 +++++++++--------- .../machinecontroller/machine_util.go | 68 +++--- 4 files changed, 160 insertions(+), 134 deletions(-) diff --git a/pkg/controller/deployment_machineset_util.go b/pkg/controller/deployment_machineset_util.go index 82475f405..f09c640a0 100644 --- a/pkg/controller/deployment_machineset_util.go +++ b/pkg/controller/deployment_machineset_util.go @@ -127,7 +127,8 @@ func calculateMachineSetStatus(is *v1alpha1.MachineSet, filteredMachines []*v1al } failedMachines = append(failedMachines, machineSummary) } - if cond := getMachineCondition(machine, v1alpha1.NodePreserved); cond != nil { + cond := getMachineCondition(machine, v1alpha1.NodePreserved) + if cond != nil { if cond.Reason == v1alpha1.NodePreservedByMCM { autoPreserveFailedMachineCount++ } diff --git a/pkg/controller/machineset.go b/pkg/controller/machineset.go index 1884f3633..06deb8786 100644 --- a/pkg/controller/machineset.go +++ b/pkg/controller/machineset.go @@ -332,7 +332,7 @@ func (c *controller) enqueueMachineSetAfter(obj any, after time.Duration) { func (c *controller) manageReplicas(ctx context.Context, allMachines []*v1alpha1.Machine, machineSet *v1alpha1.MachineSet) error { machineSetKey, err := KeyFunc(machineSet) if err != nil { - utilruntime.HandleError(fmt.Errorf("Couldn't get key for %v %#v: %v", machineSet.Kind, machineSet, err)) + utilruntime.HandleError(fmt.Errorf("couldn't get key for %v %#v: %v", machineSet.Kind, machineSet, err)) return nil } @@ -347,7 +347,9 @@ func (c *controller) manageReplicas(ctx context.Context, allMachines []*v1alpha1 if machineutils.IsMachineTriggeredForDeletion(m) { staleMachines = append(staleMachines, m) } else if machineutils.IsMachineFailed(m) { - if preserve, err := c.isMachineCandidateForPreservation(ctx, machineSet, m); err != nil { + // if machine is preserved or in the process of being preserved, the machine should be considered an active machine and not be added to stale machines + preserve, err := c.isMachineCandidateForPreservation(ctx, machineSet, m) + if err != nil { return err } else if preserve { activeMachines = append(activeMachines, m) diff --git a/pkg/util/provider/machinecontroller/machine.go b/pkg/util/provider/machinecontroller/machine.go index f723bccba..e23abae46 100644 --- a/pkg/util/provider/machinecontroller/machine.go +++ b/pkg/util/provider/machinecontroller/machine.go @@ -797,131 +797,142 @@ func (c *controller) isCreationProcessing(machine *v1alpha1.Machine) bool { // - failed machine, already preserved, check for timeout // // manageMachinePreservation checks if any preservation-related operations need to be performed on the machine and node objects -func (c *controller) manageMachinePreservation(ctx context.Context, machine *v1alpha1.Machine) (machineutils.RetryPeriod, error) { - // get effective preservation value based on node's and machine's annotations. - updatedMachine, preserveValue, exists, err := c.syncEffectivePreserveAnnotationValue(ctx, machine) - if err != nil { - return machineutils.ShortRetry, err - } - if !exists { - return machineutils.LongRetry, nil - } - switch preserveValue { - case machineutils.PreserveMachineAnnotationValueNow, machineutils.PreserveMachineAnnotationValueWhenFailed, machineutils.PreserveMachineAnnotationValuePreservedByMCM: - // if preserve annotation value has switched from now to when-failed, then stop preservation - if preserveValue == machineutils.PreserveMachineAnnotationValueWhenFailed && !machineutils.IsMachineFailed(updatedMachine) { - if machineutils.IsPreserveExpiryTimeSet(updatedMachine) { - err = c.stopMachinePreservation(ctx, updatedMachine) - if err != nil { - if apierrors.IsConflict(err) { - return machineutils.ConflictRetry, nil - } - return machineutils.ShortRetry, err - } - } - return machineutils.LongRetry, nil - } - isComplete, err := c.isMachinePreservationComplete(machine) +func (c *controller) manageMachinePreservation(ctx context.Context, machine *v1alpha1.Machine) (retry machineutils.RetryPeriod, err error) { + defer func() { if err != nil { - return machineutils.ShortRetry, err - } - if !isComplete { - err = c.preserveMachine(ctx, machine, preserveValue) - if err != nil { - if apierrors.IsConflict(err) { - return machineutils.ConflictRetry, nil - } - return machineutils.ShortRetry, err - } - } - if hasMachinePreservationTimedOut(machine) { - err = c.stopMachinePreservation(ctx, updatedMachine) - if err != nil { - if apierrors.IsConflict(err) { - return machineutils.ConflictRetry, nil - } - return machineutils.ShortRetry, err + if apierrors.IsConflict(err) { + retry = machineutils.ConflictRetry } + retry = machineutils.ShortRetry } - case machineutils.PreserveMachineAnnotationValueFalse: - err = c.stopMachinePreservation(ctx, updatedMachine) + retry = machineutils.LongRetry + }() + + preserveValue, exists, err := c.computeEffectivePreserveAnnotationValue(machine) + + if err != nil { + return + } + if !exists { + return + } + // if preserve value differs from machine's preserve value, overwrite the value in the machine + clone := machine.DeepCopy() + if machine.Annotations == nil || machine.Annotations[machineutils.PreserveMachineAnnotationKey] != preserveValue { + clone, err = c.writePreserveAnnotationValueOnMachine(ctx, clone, preserveValue) if err != nil { - if apierrors.IsConflict(err) { - return machineutils.ConflictRetry, nil - } - return machineutils.ShortRetry, err + return } - case "": - return machineutils.LongRetry, nil - default: + } + if !c.isPreserveAnnotationValueValid(preserveValue) { klog.Warningf("Preserve annotation value %s on machine %s is invalid", preserveValue, machine.Name) - return machineutils.LongRetry, nil + return + } else if preserveValue == machineutils.PreserveMachineAnnotationValueFalse || hasMachinePreservationTimedOut(clone) { + err = c.stopMachinePreservation(ctx, clone) + return + } else if preserveValue == machineutils.PreserveMachineAnnotationValueWhenFailed { + // if machine is preserved, stop preservation. Else, do nothing. + // this check is done in case the annotation value has changed from preserve=now to preserve=when-failed, in which case preservation needs to be stopped + preserveExpirySet := machineutils.IsPreserveExpiryTimeSet(clone) + machineFailed := machineutils.IsMachineFailed(clone) + if !preserveExpirySet && !machineFailed { + return + } else if !preserveExpirySet { + err = c.preserveMachine(ctx, clone, preserveValue) + return + } + // Here, we do not stop preservation even when preserve expiry time is set but the machine is in Running. + // This is to accommodate the case where the annotation is when-failed and the machine has recovered from Failed to Running. + // In this case, we want the preservation to continue so that CA does not scale down the node before pods are assigned to it + return + } else if preserveValue == machineutils.PreserveMachineAnnotationValueNow || preserveValue == machineutils.PreserveMachineAnnotationValuePreservedByMCM { + err = c.preserveMachine(ctx, clone, preserveValue) + return } - return machineutils.LongRetry, nil + return } -// syncEffectivePreserveAnnotationValue finds the preservation annotation value by considering both node and machine objects -// if the backing node is annotated with preserve annotation, the preserve value will be synced to the machine -// if there is no backing node, or the node has no preserve annotation, then the machine's preserve value is honoured -// if both machine and node objects have conflicting preserve annotation values, the node's value will be honoured -func (c *controller) syncEffectivePreserveAnnotationValue(ctx context.Context, machine *v1alpha1.Machine) (*v1alpha1.Machine, string, bool, error) { - mAnnotationValue, mExists := machine.Annotations[machineutils.PreserveMachineAnnotationKey] +func (c *controller) getNodePreserveAnnotationValue(machine *v1alpha1.Machine) (nAnnotationValue string, nExists bool, err error) { nodeName := machine.Labels[v1alpha1.NodeLabelKey] if nodeName == "" { - return machine, mAnnotationValue, mExists, nil + return } node, err := c.nodeLister.Get(nodeName) if err != nil { klog.Errorf("error trying to get node %q: %v", nodeName, err) - return machine, "", false, err + return } - nAnnotationValue, nExists := node.Annotations[machineutils.PreserveMachineAnnotationKey] - switch { - case nExists && mExists: - if nAnnotationValue == mAnnotationValue { - return machine, nAnnotationValue, nExists, nil - } // else falls through to update machine with node's value - case nExists && !mExists: - // falls through to update machine with node's value - case mExists && !nExists: - return machine, mAnnotationValue, mExists, nil - case !nExists && !mExists: - return machine, "", false, nil + if node.Annotations != nil { + nAnnotationValue, nExists = node.Annotations[machineutils.PreserveMachineAnnotationKey] } - clone := machine.DeepCopy() - if clone.Annotations == nil { - clone.Annotations = make(map[string]string) + return +} + +// computeEffectivePreserveAnnotationValue returns the effective preservation value based on node's and machine's annotations. +// if the backing node is annotated with preserve annotation, the node's preserve value will be honoured +// if there is no backing node, or the node has no preserve annotation, then the machine's preserve value is honoured +// if both machine and node objects have conflicting preserve annotation values, the node's value will be honoured +func (c *controller) computeEffectivePreserveAnnotationValue(machine *v1alpha1.Machine) (preserveValue string, exists bool, err error) { + mAnnotationValue, mExists := machine.Annotations[machineutils.PreserveMachineAnnotationKey] + nAnnotationValue, nExists, err := c.getNodePreserveAnnotationValue(machine) + if err != nil { + return + } + exists = mExists || nExists + if !exists { + return } - clone.Annotations[machineutils.PreserveMachineAnnotationKey] = nAnnotationValue - updatedMachine, err := c.controlMachineClient.Machines(c.namespace).Update(ctx, clone, metav1.UpdateOptions{}) + if nExists { + preserveValue = nAnnotationValue + } else { + preserveValue = mAnnotationValue + } + return +} + +// writePreserveAnnotationValueOnMachine syncs the effective preserve value on the machine objects +func (c *controller) writePreserveAnnotationValueOnMachine(ctx context.Context, machine *v1alpha1.Machine, preserveValue string) (*v1alpha1.Machine, error) { + if machine.Annotations == nil { + machine.Annotations = make(map[string]string) + } + machine.Annotations[machineutils.PreserveMachineAnnotationKey] = preserveValue + updatedMachine, err := c.controlMachineClient.Machines(c.namespace).Update(ctx, machine, metav1.UpdateOptions{}) if err != nil { - klog.Errorf("error updating machine %q with preserve annotation %q: %v", machine.Name, nAnnotationValue, err) - return machine, "", true, err + klog.Errorf("error updating machine %q with preserve annotation %q: %v", machine.Name, preserveValue, err) + return machine, err } - return updatedMachine, nAnnotationValue, nExists, nil + return updatedMachine, nil } -func (c *controller) isMachinePreservationComplete(machine *v1alpha1.Machine) (bool, error) { - // if PreserveExpiryTime is set and machine has not failed, then yes, - // if PreserveExpiryTime is set and machine has failed, the node condition must be there saying drain successful - // if PreserveExpiryTime is not set, then no - if !machineutils.IsPreserveExpiryTimeSet(machine) { - return false, nil - } else if machineutils.IsMachineFailed(machine) { - if machine.Labels[v1alpha1.NodeLabelKey] == "" { - return true, nil - } - node, err := c.nodeLister.Get(getNodeName(machine)) - if err != nil { - klog.Errorf("error trying to get node %q: %v", getNodeName(machine), err) - return false, err - } - if cond := nodeops.GetCondition(node, v1alpha1.NodePreserved); cond != nil { - if cond.Message == v1alpha1.PreservedNodeDrainSuccessful { - return true, nil - } - } +// isPreserveAnnotationValueValid checks if the preserve annotation value is valid +func (c *controller) isPreserveAnnotationValueValid(preserveValue string) bool { + allowedValues := map[string]bool{ + machineutils.PreserveMachineAnnotationValueNow: true, + machineutils.PreserveMachineAnnotationValueWhenFailed: true, + machineutils.PreserveMachineAnnotationValuePreservedByMCM: true, + machineutils.PreserveMachineAnnotationValueFalse: true, + } + _, exists := allowedValues[preserveValue] + return exists +} + +// isMachinePreservationComplete check if all the steps in the preservation logic have been completed for the machine +func (c *controller) isMachinePreservationComplete(machine *v1alpha1.Machine, isExpirySet bool) (bool, error) { + nodeName := getNodeName(machine) + if nodeName == "" && isExpirySet { + return true, nil + } + node, err := c.nodeLister.Get(nodeName) + if err != nil { + klog.Errorf("error trying to get node %q: %v", nodeName, err) + return false, err + } + cond := nodeops.GetCondition(node, v1alpha1.NodePreserved) + if cond == nil { return false, nil } - return true, nil + if cond.Status == corev1.ConditionTrue { + return true, nil + } + return false, nil } diff --git a/pkg/util/provider/machinecontroller/machine_util.go b/pkg/util/provider/machinecontroller/machine_util.go index 0271c1b2a..c7b0587ce 100644 --- a/pkg/util/provider/machinecontroller/machine_util.go +++ b/pkg/util/provider/machinecontroller/machine_util.go @@ -2369,8 +2369,17 @@ Utility Functions for Machine Preservation // preserveMachine contains logic to start the preservation of a machine and node. func (c *controller) preserveMachine(ctx context.Context, machine *v1alpha1.Machine, preserveValue string) error { + isExpirySet := machineutils.IsPreserveExpiryTimeSet(machine) + // check if preservation is complete + isComplete, err := c.isMachinePreservationComplete(machine, isExpirySet) + if err != nil { + return err + } + if isComplete { + return nil + } // Step 1: Set PreserveExpiryTime - if !machineutils.IsPreserveExpiryTimeSet(machine) { + if !isExpirySet { _, err := c.setPreserveExpiryTime(ctx, machine) if err != nil { return err @@ -2400,15 +2409,23 @@ func (c *controller) preserveMachine(ctx context.Context, machine *v1alpha1.Mach if c.shouldNodeBeDrained(machine, existingNodePreservedCondition) { err = c.drainPreservedNode(ctx, machine) if err != nil { - _ = c.updateNodePreservedCondition(ctx, machine, preserveValue, drainSuccessful, existingNodePreservedCondition) + newCond, needsUpdate := c.computeNewNodePreservedCondition(machine.Status.CurrentStatus.Phase, preserveValue, drainSuccessful, existingNodePreservedCondition) + if needsUpdate { + _ = nodeops.AddOrUpdateConditionsOnNode(ctx, c.targetCoreClient, nodeName, *newCond) + return err + } return err } drainSuccessful = true } // Step 4: Update NodePreserved Condition on Node - err = c.updateNodePreservedCondition(ctx, machine, preserveValue, drainSuccessful, existingNodePreservedCondition) - if err != nil { - return err + newCond, needsUpdate := c.computeNewNodePreservedCondition(machine.Status.CurrentStatus.Phase, preserveValue, drainSuccessful, existingNodePreservedCondition) + if needsUpdate { + err = nodeops.AddOrUpdateConditionsOnNode(ctx, c.targetCoreClient, nodeName, *newCond) + if err != nil { + klog.Errorf("error trying to update node preserved condition for node %q of machine %q : %v", getNodeName(machine), machine.Name, err) + return err + } } klog.V(3).Infof("Machine %s preserved successfully.", machine.Name) return nil @@ -2452,47 +2469,41 @@ func (c *controller) addCAScaleDownDisabledAnnotationOnNode(ctx context.Context, } // getNewNodePreservedCondition returns the NodeCondition with the values set according to the preserveValue and the stage of Preservation -func (c *controller) updateNodePreservedCondition(ctx context.Context, machine *v1alpha1.Machine, preserveValue string, drainSuccessful bool, existingNodeCondition *v1.NodeCondition) error { +func (c *controller) computeNewNodePreservedCondition(machinePhase v1alpha1.MachinePhase, preserveValue string, drainSuccessful bool, existingNodeCondition *v1.NodeCondition) (*v1.NodeCondition, bool) { var newNodePreservedCondition *v1.NodeCondition - var changed bool + var needsUpdate bool if existingNodeCondition == nil { newNodePreservedCondition = &v1.NodeCondition{ Type: v1alpha1.NodePreserved, Status: v1.ConditionFalse, LastTransitionTime: metav1.Now(), } - changed = true + if preserveValue == machineutils.PreserveMachineAnnotationValuePreservedByMCM { + newNodePreservedCondition.Reason = v1alpha1.NodePreservedByMCM + } else { + newNodePreservedCondition.Reason = v1alpha1.NodePreservedByUser + } + needsUpdate = true } else { newNodePreservedCondition = existingNodeCondition.DeepCopy() } - if machine.Status.CurrentStatus.Phase == v1alpha1.MachineFailed { + if machinePhase == v1alpha1.MachineFailed { if drainSuccessful { if newNodePreservedCondition.Message != v1alpha1.PreservedNodeDrainSuccessful { newNodePreservedCondition.Message = v1alpha1.PreservedNodeDrainSuccessful newNodePreservedCondition.Status = v1.ConditionTrue - changed = true + needsUpdate = true } } else if newNodePreservedCondition.Status != v1.ConditionFalse { newNodePreservedCondition.Message = v1alpha1.PreservedNodeDrainUnsuccessful newNodePreservedCondition.Status = v1.ConditionFalse - changed = true + needsUpdate = true } } else if newNodePreservedCondition.Status != v1.ConditionTrue { newNodePreservedCondition.Status = v1.ConditionTrue - changed = true + needsUpdate = true } - if changed { - if preserveValue != machineutils.PreserveMachineAnnotationValuePreservedByMCM { - newNodePreservedCondition.Reason = v1alpha1.NodePreservedByUser - } else { - newNodePreservedCondition.Reason = v1alpha1.NodePreservedByMCM - } - if err := nodeops.AddOrUpdateConditionsOnNode(ctx, c.targetCoreClient, getNodeName(machine), *newNodePreservedCondition); err != nil { - klog.Errorf("error trying to update node preserved condition for node %q of machine %q : %v", getNodeName(machine), machine.Name, err) - return err - } - } - return nil + return newNodePreservedCondition, needsUpdate } // shouldNodeBeDrained returns true if the machine's backing node must be drained, else false @@ -2516,15 +2527,15 @@ func (c *controller) stopMachinePreservation(ctx context.Context, machine *v1alp if !machineutils.IsPreserveExpiryTimeSet(machine) { return nil } - if machine.Labels[v1alpha1.NodeLabelKey] != "" { - nodeName := machine.Labels[v1alpha1.NodeLabelKey] + nodeName := machine.Labels[v1alpha1.NodeLabelKey] + if nodeName != "" { preservedCondition := v1.NodeCondition{ Type: v1alpha1.NodePreserved, Status: v1.ConditionFalse, LastTransitionTime: metav1.Now(), } // Step 1: if backing node exists, change node condition to reflect that preservation has stopped - err := nodeops.AddOrUpdateConditionsOnNode(ctx, c.targetCoreClient, getNodeName(machine), preservedCondition) + err := nodeops.AddOrUpdateConditionsOnNode(ctx, c.targetCoreClient, nodeName, preservedCondition) if err != nil { return err } @@ -2589,7 +2600,8 @@ func (c *controller) drainPreservedNode(ctx context.Context, machine *v1alpha1.M } // verify and log node object's existence - if _, err := c.nodeLister.Get(nodeName); err == nil { + _, err = c.nodeLister.Get(nodeName) + if err == nil { klog.V(3).Infof("(drainNode) For node %q, machine %q", nodeName, machine.Name) } else if apierrors.IsNotFound(err) { klog.Warningf("(drainNode) Node %q for machine %q doesn't exist, so drain will finish instantly", nodeName, machine.Name) From 8225d2028ad40043f20aefc785815c6b9bd0b994 Mon Sep 17 00:00:00 2001 From: thiyyakat Date: Thu, 18 Dec 2025 10:07:22 +0530 Subject: [PATCH 28/43] Remove incorrect json tag and regenerate CRDs. --- .../crds/machine.sapcloud.io_machinedeployments.yaml | 8 ++++---- kubernetes/crds/machine.sapcloud.io_machines.yaml | 8 ++++---- kubernetes/crds/machine.sapcloud.io_machinesets.yaml | 8 ++++---- pkg/apis/machine/types.go | 3 +-- pkg/apis/machine/v1alpha1/shared_types.go | 2 +- 5 files changed, 14 insertions(+), 15 deletions(-) diff --git a/kubernetes/crds/machine.sapcloud.io_machinedeployments.yaml b/kubernetes/crds/machine.sapcloud.io_machinedeployments.yaml index 555d898c4..abb36d1c4 100644 --- a/kubernetes/crds/machine.sapcloud.io_machinedeployments.yaml +++ b/kubernetes/crds/machine.sapcloud.io_machinedeployments.yaml @@ -302,6 +302,10 @@ spec: description: MachineInPlaceUpdateTimeout is the timeout after which in-place update is declared failed. type: string + machinePreserveTimeout: + description: MachinePreserveTimeout is the timeout after which + the machine preservation is stopped + type: string maxEvictRetries: description: MaxEvictRetries is the number of retries that will be attempted while draining the node. @@ -425,10 +429,6 @@ spec: type: boolean type: object type: object - preserveTimeout: - description: MachinePreserveTimeout is the timeout after which - the machine preservation is stopped - type: string providerID: description: ProviderID represents the provider's unique ID given to a machine diff --git a/kubernetes/crds/machine.sapcloud.io_machines.yaml b/kubernetes/crds/machine.sapcloud.io_machines.yaml index 6e75f1441..fcea16750 100644 --- a/kubernetes/crds/machine.sapcloud.io_machines.yaml +++ b/kubernetes/crds/machine.sapcloud.io_machines.yaml @@ -95,6 +95,10 @@ spec: description: MachineInPlaceUpdateTimeout is the timeout after which in-place update is declared failed. type: string + machinePreserveTimeout: + description: MachinePreserveTimeout is the timeout after which the + machine preservation is stopped + type: string maxEvictRetries: description: MaxEvictRetries is the number of retries that will be attempted while draining the node. @@ -216,10 +220,6 @@ spec: type: boolean type: object type: object - preserveTimeout: - description: MachinePreserveTimeout is the timeout after which the - machine preservation is stopped - type: string providerID: description: ProviderID represents the provider's unique ID given to a machine diff --git a/kubernetes/crds/machine.sapcloud.io_machinesets.yaml b/kubernetes/crds/machine.sapcloud.io_machinesets.yaml index 970be4b20..46445131f 100644 --- a/kubernetes/crds/machine.sapcloud.io_machinesets.yaml +++ b/kubernetes/crds/machine.sapcloud.io_machinesets.yaml @@ -181,6 +181,10 @@ spec: description: MachineInPlaceUpdateTimeout is the timeout after which in-place update is declared failed. type: string + machinePreserveTimeout: + description: MachinePreserveTimeout is the timeout after which + the machine preservation is stopped + type: string maxEvictRetries: description: MaxEvictRetries is the number of retries that will be attempted while draining the node. @@ -304,10 +308,6 @@ spec: type: boolean type: object type: object - preserveTimeout: - description: MachinePreserveTimeout is the timeout after which - the machine preservation is stopped - type: string providerID: description: ProviderID represents the provider's unique ID given to a machine diff --git a/pkg/apis/machine/types.go b/pkg/apis/machine/types.go index 10b3b507e..c2e535bf7 100644 --- a/pkg/apis/machine/types.go +++ b/pkg/apis/machine/types.go @@ -98,8 +98,7 @@ type MachineConfiguration struct { MachineInPlaceUpdateTimeout *metav1.Duration // MachinePreserveTimeout is the timeout after which the machine preservation is stopped - // +optional - MachinePreserveTimeout *metav1.Duration `json:"preserveTimeout,omitempty"` + MachinePreserveTimeout *metav1.Duration // DisableHealthTimeout if set to true, health timeout will be ignored. Leading to machine never being declared failed. // This is intended to be used only for in-place updates. DisableHealthTimeout *bool diff --git a/pkg/apis/machine/v1alpha1/shared_types.go b/pkg/apis/machine/v1alpha1/shared_types.go index 1a673b79f..d9a7d0c7b 100644 --- a/pkg/apis/machine/v1alpha1/shared_types.go +++ b/pkg/apis/machine/v1alpha1/shared_types.go @@ -46,7 +46,7 @@ type MachineConfiguration struct { // MachinePreserveTimeout is the timeout after which the machine preservation is stopped // +optional - MachinePreserveTimeout *metav1.Duration `json:"preserveTimeout,omitempty"` + MachinePreserveTimeout *metav1.Duration `json:"machinePreserveTimeout,omitempty"` // DisableHealthTimeout if set to true, health timeout will be ignored. Leading to machine never being declared failed. // This is intended to be used only for in-place updates. From 9eb910d70a215aad16909c46b1ba64a2d3fa1c2d Mon Sep 17 00:00:00 2001 From: thiyyakat Date: Fri, 19 Dec 2025 11:07:09 +0530 Subject: [PATCH 29/43] Apply suggestions from code review - part 1 Co-authored-by: Prashant Tak --- pkg/apis/machine/v1alpha1/machine_types.go | 6 +++--- pkg/controller/deployment_machineset_util.go | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/pkg/apis/machine/v1alpha1/machine_types.go b/pkg/apis/machine/v1alpha1/machine_types.go index 8fe3d75fa..dc69e2e49 100644 --- a/pkg/apis/machine/v1alpha1/machine_types.go +++ b/pkg/apis/machine/v1alpha1/machine_types.go @@ -251,13 +251,13 @@ const ( // NodePreservedByMCM is a node condition reason for preservation of machines to indicate that the node is auto-preserved by MCM NodePreservedByMCM string = "PreservedByMCM" - //NodePreservedByUser is a node condition reason to indicate that a machine/node has been preserved due to explicit annotation by user + // NodePreservedByUser is a node condition reason to indicate that a machine/node has been preserved due to explicit annotation by user NodePreservedByUser string = "PreservedByUser" - //PreservedNodeDrainSuccessful is a constant for the message in condition that indicates that the preserved node's drain is successful + // PreservedNodeDrainSuccessful is a constant for the message in condition that indicates that the preserved node's drain is successful PreservedNodeDrainSuccessful string = "Preserved Node drained successfully" - //PreservedNodeDrainUnsuccessful is a constant for the message in condition that indicates that the preserved node's drain was not successful + // PreservedNodeDrainUnsuccessful is a constant for the message in condition that indicates that the preserved node's drain was not successful PreservedNodeDrainUnsuccessful string = "Preserved Node could not be drained" ) diff --git a/pkg/controller/deployment_machineset_util.go b/pkg/controller/deployment_machineset_util.go index f09c640a0..016422590 100644 --- a/pkg/controller/deployment_machineset_util.go +++ b/pkg/controller/deployment_machineset_util.go @@ -128,8 +128,7 @@ func calculateMachineSetStatus(is *v1alpha1.MachineSet, filteredMachines []*v1al failedMachines = append(failedMachines, machineSummary) } cond := getMachineCondition(machine, v1alpha1.NodePreserved) - if cond != nil { - if cond.Reason == v1alpha1.NodePreservedByMCM { + if cond != nil && cond.Reason == v1alpha1.NodePreservedByMCM { autoPreserveFailedMachineCount++ } } From 5e7e2d7e587b4729c8c07a72a20136649f48cdd5 Mon Sep 17 00:00:00 2001 From: thiyyakat Date: Fri, 19 Dec 2025 14:00:28 +0530 Subject: [PATCH 30/43] Delete invalid gitlink --- machine-controller-manager | 1 - 1 file changed, 1 deletion(-) delete mode 160000 machine-controller-manager diff --git a/machine-controller-manager b/machine-controller-manager deleted file mode 160000 index f2cbb0378..000000000 --- a/machine-controller-manager +++ /dev/null @@ -1 +0,0 @@ -Subproject commit f2cbb037802eb399e7b655388ef6e182c90cb70f From d560664f127ee37be3a2a583228e76b25eb31a11 Mon Sep 17 00:00:00 2001 From: thiyyakat Date: Mon, 22 Dec 2025 16:23:19 +0530 Subject: [PATCH 31/43] Address review comments- part 2: * fix edge case of handling switch from preserve=now to when-failed * Create map in package with valid preserve annotation values * Fix big where node condition's reason wouldn't get updated after toggling of preservation --- pkg/apis/machine/v1alpha1/machine_types.go | 3 + pkg/controller/deployment_machineset_util.go | 3 +- .../provider/machinecontroller/machine.go | 97 +++++------ .../machinecontroller/machine_util.go | 150 ++++++++++-------- pkg/util/provider/machineutils/utils.go | 10 ++ 5 files changed, 142 insertions(+), 121 deletions(-) diff --git a/pkg/apis/machine/v1alpha1/machine_types.go b/pkg/apis/machine/v1alpha1/machine_types.go index dc69e2e49..654256d32 100644 --- a/pkg/apis/machine/v1alpha1/machine_types.go +++ b/pkg/apis/machine/v1alpha1/machine_types.go @@ -254,6 +254,9 @@ const ( // NodePreservedByUser is a node condition reason to indicate that a machine/node has been preserved due to explicit annotation by user NodePreservedByUser string = "PreservedByUser" + // NodePreservationStopped is a node condition reason to indicate that a machine/node preservation has been stopped due to annotation update or timeout + NodePreservationStopped string = "PreservationStopped" + // PreservedNodeDrainSuccessful is a constant for the message in condition that indicates that the preserved node's drain is successful PreservedNodeDrainSuccessful string = "Preserved Node drained successfully" diff --git a/pkg/controller/deployment_machineset_util.go b/pkg/controller/deployment_machineset_util.go index 016422590..e44505393 100644 --- a/pkg/controller/deployment_machineset_util.go +++ b/pkg/controller/deployment_machineset_util.go @@ -129,8 +129,7 @@ func calculateMachineSetStatus(is *v1alpha1.MachineSet, filteredMachines []*v1al } cond := getMachineCondition(machine, v1alpha1.NodePreserved) if cond != nil && cond.Reason == v1alpha1.NodePreservedByMCM { - autoPreserveFailedMachineCount++ - } + autoPreserveFailedMachineCount++ } } diff --git a/pkg/util/provider/machinecontroller/machine.go b/pkg/util/provider/machinecontroller/machine.go index e23abae46..9e913329a 100644 --- a/pkg/util/provider/machinecontroller/machine.go +++ b/pkg/util/provider/machinecontroller/machine.go @@ -10,6 +10,7 @@ import ( "errors" "fmt" "github.com/gardener/machine-controller-manager/pkg/util/nodeops" + clientretry "k8s.io/client-go/util/retry" "maps" "slices" "strings" @@ -67,7 +68,7 @@ func (c *controller) updateMachine(oldObj, newObj any) { c.enqueueMachine(newObj, "TEST: handling machine failure simulation UPDATE event") } } - if preserveAnnotationsChanged(oldMachine.Annotations, newMachine.Annotations) { + if c.handlePreserveAnnotationsChange(oldMachine.Annotations, newMachine.Annotations, newMachine) { c.enqueueMachine(newObj, "handling machine object preservation related UPDATE event") return } @@ -222,8 +223,8 @@ func (c *controller) reconcileClusterMachine(ctx context.Context, machine *v1alp klog.Errorf("cannot reconcile machine %s: %s", machine.Name, err) return retry, err } - { //TODO@thiyyakat: remove after drain - //insert condition changing code here + + { //TODO@thiyyakat: remove after testing if machine.Labels["test-failed"] == "true" { node, err := c.nodeLister.Get(getNodeName(machine)) if err != nil { @@ -358,10 +359,30 @@ func (c *controller) reconcileClusterMachineTermination(key string) error { } return nil } -func preserveAnnotationsChanged(oldAnnotations, newAnnotations map[string]string) bool { + +// handlePreserveAnnotationsChange returns true if there is a change in preserve annotations +// it also handles the special case where the annotation is changed from 'now' to 'when-failed' +// in which case it stops the preservation if expiry time is already set +func (c *controller) handlePreserveAnnotationsChange(oldAnnotations, newAnnotations map[string]string, machine *v1alpha1.Machine) bool { valueNew, existsInNew := newAnnotations[machineutils.PreserveMachineAnnotationKey] valueOld, existsInOld := oldAnnotations[machineutils.PreserveMachineAnnotationKey] - return existsInOld != existsInNew || valueOld != valueNew + if valueNew != machineutils.PreserveMachineAnnotationValueWhenFailed || valueOld != machineutils.PreserveMachineAnnotationValueNow { + return existsInOld != existsInNew || valueOld != valueNew + } + // Special case: annotation changed from 'now' to 'when-failed' + isPreserved := machineutils.IsPreserveExpiryTimeSet(machine) + if !isPreserved { + return true + } + ctx := context.Background() + err := clientretry.RetryOnConflict(nodeops.Backoff, func() error { + klog.V(3).Infof("Stopping preservation for machine %q as preserve annotation changed from 'now' to 'when-failed'.", machine.Name) + return c.stopMachinePreservation(ctx, machine) + }) + if err != nil { + klog.Errorf("error while stopping preservation for machine %q: %v. Use preserve=false to stop preservation.", machine.Name, err) + } + return true } /* @@ -784,18 +805,6 @@ func (c *controller) isCreationProcessing(machine *v1alpha1.Machine) bool { return isMachineInCreationFlow } -// TODO@thiyyakat: check case where, preserved and annotated but times out. Not handled currently -// possible cases: -// 1. Annotated -// - already preserved, check for timeout -// - already preserved, check for explicit stop preservation -// - needs to be preserved on failure -// - needs to be preserved now -// -// 2. Unannotated -// - failed machine, autoPreserveMax not breached, must be preserved -// - failed machine, already preserved, check for timeout -// // manageMachinePreservation checks if any preservation-related operations need to be performed on the machine and node objects func (c *controller) manageMachinePreservation(ctx context.Context, machine *v1alpha1.Machine) (retry machineutils.RetryPeriod, err error) { defer func() { @@ -809,7 +818,6 @@ func (c *controller) manageMachinePreservation(ctx context.Context, machine *v1a }() preserveValue, exists, err := c.computeEffectivePreserveAnnotationValue(machine) - if err != nil { return } @@ -824,26 +832,23 @@ func (c *controller) manageMachinePreservation(ctx context.Context, machine *v1a return } } - if !c.isPreserveAnnotationValueValid(preserveValue) { - klog.Warningf("Preserve annotation value %s on machine %s is invalid", preserveValue, machine.Name) + if !isPreserveAnnotationValueValid(preserveValue) { + klog.Warningf("Preserve annotation value %q on machine %s is invalid", preserveValue, machine.Name) return } else if preserveValue == machineutils.PreserveMachineAnnotationValueFalse || hasMachinePreservationTimedOut(clone) { err = c.stopMachinePreservation(ctx, clone) return } else if preserveValue == machineutils.PreserveMachineAnnotationValueWhenFailed { - // if machine is preserved, stop preservation. Else, do nothing. - // this check is done in case the annotation value has changed from preserve=now to preserve=when-failed, in which case preservation needs to be stopped - preserveExpirySet := machineutils.IsPreserveExpiryTimeSet(clone) machineFailed := machineutils.IsMachineFailed(clone) - if !preserveExpirySet && !machineFailed { - return - } else if !preserveExpirySet { + if machineFailed { err = c.preserveMachine(ctx, clone, preserveValue) - return } - // Here, we do not stop preservation even when preserve expiry time is set but the machine is in Running. - // This is to accommodate the case where the annotation is when-failed and the machine has recovered from Failed to Running. - // In this case, we want the preservation to continue so that CA does not scale down the node before pods are assigned to it + // Here, if the preserve value is when-failed, but the machine is in running, there could be 2 possibilities: + // 1. The machine was initially annotated with preserve=now and has been preserved, but later the annotation was changed to when-failed. In this case, + // we want to stop preservation. This case is already being handled in updateMachine and updateNodeToMachine functions. + // 2. The machine was initially annotated with preserve=when-failed and has recovered from Failed to Running. In this case, + // we want to continue preservation until the annotation is changed to false or the preservation times out, so that CA does not + // scale down the node before pods are assigned to it. return } else if preserveValue == machineutils.PreserveMachineAnnotationValueNow || preserveValue == machineutils.PreserveMachineAnnotationValuePreservedByMCM { err = c.preserveMachine(ctx, clone, preserveValue) @@ -905,34 +910,20 @@ func (c *controller) writePreserveAnnotationValueOnMachine(ctx context.Context, } // isPreserveAnnotationValueValid checks if the preserve annotation value is valid -func (c *controller) isPreserveAnnotationValueValid(preserveValue string) bool { - allowedValues := map[string]bool{ - machineutils.PreserveMachineAnnotationValueNow: true, - machineutils.PreserveMachineAnnotationValueWhenFailed: true, - machineutils.PreserveMachineAnnotationValuePreservedByMCM: true, - machineutils.PreserveMachineAnnotationValueFalse: true, - } - _, exists := allowedValues[preserveValue] +func isPreserveAnnotationValueValid(preserveValue string) bool { + _, exists := machineutils.AllowedPreserveAnnotationValues[preserveValue] return exists } -// isMachinePreservationComplete check if all the steps in the preservation logic have been completed for the machine -func (c *controller) isMachinePreservationComplete(machine *v1alpha1.Machine, isExpirySet bool) (bool, error) { - nodeName := getNodeName(machine) - if nodeName == "" && isExpirySet { - return true, nil - } - node, err := c.nodeLister.Get(nodeName) - if err != nil { - klog.Errorf("error trying to get node %q: %v", nodeName, err) - return false, err - } - cond := nodeops.GetCondition(node, v1alpha1.NodePreserved) +// isPreservedNodeConditionStatusTrue check if all the steps in the preservation logic have been completed for the machine +// if the machine has no backing node, only PreserveExpiryTime needs to be set +// if the machine has a backing node, the NodePreserved condition on the node needs to be true +func (c *controller) isPreservedNodeConditionStatusTrue(cond *corev1.NodeCondition) bool { if cond == nil { - return false, nil + return false } if cond.Status == corev1.ConditionTrue { - return true, nil + return true } - return false, nil + return false } diff --git a/pkg/util/provider/machinecontroller/machine_util.go b/pkg/util/provider/machinecontroller/machine_util.go index c7b0587ce..9e4008fcd 100644 --- a/pkg/util/provider/machinecontroller/machine_util.go +++ b/pkg/util/provider/machinecontroller/machine_util.go @@ -2369,48 +2369,57 @@ Utility Functions for Machine Preservation // preserveMachine contains logic to start the preservation of a machine and node. func (c *controller) preserveMachine(ctx context.Context, machine *v1alpha1.Machine, preserveValue string) error { + nodeName := machine.Labels[v1alpha1.NodeLabelKey] isExpirySet := machineutils.IsPreserveExpiryTimeSet(machine) - // check if preservation is complete - isComplete, err := c.isMachinePreservationComplete(machine, isExpirySet) - if err != nil { - return err - } - if isComplete { - return nil - } - // Step 1: Set PreserveExpiryTime - if !isExpirySet { - _, err := c.setPreserveExpiryTime(ctx, machine) + + // If machine has no backing node + if nodeName == "" { + if isExpirySet { + return nil + } + // Step 1: Add preserveExpiryTime to machine status + updatedMachine, err := c.setPreserveExpiryTimeOnMachine(ctx, machine) if err != nil { return err } - } - if machine.Labels[v1alpha1.NodeLabelKey] == "" { + klog.V(2).Infof("Machine %s preserved successfully till %v.", machine.Name, updatedMachine.Status.CurrentStatus.PreserveExpiryTime) return nil + } - nodeName := machine.Labels[v1alpha1.NodeLabelKey] + // Machine has a backing node node, err := c.nodeLister.Get(nodeName) if err != nil { klog.Errorf("error trying to get node %q of machine %q: %v. Retrying.", nodeName, machine.Name, err) return err } + existingNodePreservedCondition := nodeops.GetCondition(node, v1alpha1.NodePreserved) + // check if preservation is already complete + if isExpirySet && c.isPreservedNodeConditionStatusTrue(existingNodePreservedCondition) { + return nil + } + // Preservation incomplete - either the flow is just starting or in progress + updatedMachine := machine + if !isExpirySet { + // Step 1: Add preserveExpiryTime to machine status + updatedMachine, err = c.setPreserveExpiryTimeOnMachine(ctx, machine) + if err != nil { + return err + } + } // Step 2: Add annotations to prevent scale down of node by CA _, err = c.addCAScaleDownDisabledAnnotationOnNode(ctx, node) if err != nil { return err } - existingNodePreservedCondition, err := nodeops.GetNodeCondition(ctx, c.targetCoreClient, getNodeName(machine), v1alpha1.NodePreserved) - if err != nil { - klog.Errorf("error trying to get existing node preserved condition for node %q of machine %q: %v", nodeName, machine.Name, err) - return err - } + drainSuccessful := false - // Step 3: If machine is in Failed Phase, drain the backing node if c.shouldNodeBeDrained(machine, existingNodePreservedCondition) { + // Step 3: If machine is in Failed Phase, drain the backing node err = c.drainPreservedNode(ctx, machine) if err != nil { newCond, needsUpdate := c.computeNewNodePreservedCondition(machine.Status.CurrentStatus.Phase, preserveValue, drainSuccessful, existingNodePreservedCondition) if needsUpdate { + // Step 4a: Update NodePreserved Condition on Node, with drain unsuccessful status _ = nodeops.AddOrUpdateConditionsOnNode(ctx, c.targetCoreClient, nodeName, *newCond) return err } @@ -2418,54 +2427,59 @@ func (c *controller) preserveMachine(ctx context.Context, machine *v1alpha1.Mach } drainSuccessful = true } - // Step 4: Update NodePreserved Condition on Node + // Step 4b: Update NodePreserved Condition on Node with drain successful status newCond, needsUpdate := c.computeNewNodePreservedCondition(machine.Status.CurrentStatus.Phase, preserveValue, drainSuccessful, existingNodePreservedCondition) if needsUpdate { err = nodeops.AddOrUpdateConditionsOnNode(ctx, c.targetCoreClient, nodeName, *newCond) if err != nil { - klog.Errorf("error trying to update node preserved condition for node %q of machine %q : %v", getNodeName(machine), machine.Name, err) + klog.Errorf("error trying to update node preserved condition for node %q of machine %q : %v", nodeName, machine.Name, err) return err } } - klog.V(3).Infof("Machine %s preserved successfully.", machine.Name) + klog.V(2).Infof("Machine %s preserved successfully till %v.", machine.Name, updatedMachine.Status.CurrentStatus.PreserveExpiryTime) return nil } -// setPreserveExpiryTime sets the PreserveExpiryTime on the machine object's Status.CurrentStatus to now + preserve timeout -func (c *controller) setPreserveExpiryTime(ctx context.Context, machine *v1alpha1.Machine) (*v1alpha1.Machine, error) { +// setPreserveExpiryTimeOnMachine sets the PreserveExpiryTime on the machine object's Status.CurrentStatus to now + preserve timeout +func (c *controller) setPreserveExpiryTimeOnMachine(ctx context.Context, machine *v1alpha1.Machine) (*v1alpha1.Machine, error) { + clone := machine.DeepCopy() preservedCurrentStatus := v1alpha1.CurrentStatus{ Phase: machine.Status.CurrentStatus.Phase, TimeoutActive: machine.Status.CurrentStatus.TimeoutActive, LastUpdateTime: metav1.Now(), PreserveExpiryTime: metav1.NewTime(metav1.Now().Add(c.getEffectiveMachinePreserveTimeout(machine).Duration)), } - clone := machine.DeepCopy() + clone.Status.CurrentStatus = preservedCurrentStatus - _, err := c.controlMachineClient.Machines(clone.Namespace).UpdateStatus(ctx, clone, metav1.UpdateOptions{}) + updatedMachine, err := c.controlMachineClient.Machines(machine.Namespace).UpdateStatus(ctx, clone, metav1.UpdateOptions{}) if err != nil { klog.Errorf("machine/status UPDATE failed for machine %q. Retrying, error: %s", machine.Name, err) return nil, err } klog.V(4).Infof("Machine %q preserved till %v.", machine.Name, preservedCurrentStatus.PreserveExpiryTime) - return clone, nil + return updatedMachine, nil } // addCAScaleDownDisabledAnnotationOnNode adds the cluster-autoscaler annotation to disable scale down of preserved node func (c *controller) addCAScaleDownDisabledAnnotationOnNode(ctx context.Context, node *v1.Node) (*v1.Node, error) { + + // Check if annotation already exists with correct value + if node.Annotations != nil && + node.Annotations[autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationKey] == autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationValue { + return node, nil + } + + CAScaleDownAnnotation := map[string]string{ + autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationKey: autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationValue, + } nodeCopy := node.DeepCopy() - if nodeCopy.Annotations == nil || nodeCopy.Annotations[autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationKey] != autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationValue { - CAScaleDownAnnotation := map[string]string{ - autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationKey: autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationValue, - } - updatedNode, _, _ := annotations.AddOrUpdateAnnotation(nodeCopy, CAScaleDownAnnotation) - _, err := c.targetCoreClient.CoreV1().Nodes().Update(ctx, updatedNode, metav1.UpdateOptions{}) - if err != nil { - klog.Errorf("error trying to update CA annotation on node %q: %v", updatedNode.Name, err) - return nil, err - } - return updatedNode, nil + updatedNode, _, _ := annotations.AddOrUpdateAnnotation(nodeCopy, CAScaleDownAnnotation) + updatedNode, err := c.targetCoreClient.CoreV1().Nodes().Update(ctx, updatedNode, metav1.UpdateOptions{}) + if err != nil { + klog.Errorf("error trying to update CA annotation on node %q: %v", node.Name, err) + return nil, err } - return node, nil + return updatedNode, nil } // getNewNodePreservedCondition returns the NodeCondition with the values set according to the preserveValue and the stage of Preservation @@ -2478,11 +2492,6 @@ func (c *controller) computeNewNodePreservedCondition(machinePhase v1alpha1.Mach Status: v1.ConditionFalse, LastTransitionTime: metav1.Now(), } - if preserveValue == machineutils.PreserveMachineAnnotationValuePreservedByMCM { - newNodePreservedCondition.Reason = v1alpha1.NodePreservedByMCM - } else { - newNodePreservedCondition.Reason = v1alpha1.NodePreservedByUser - } needsUpdate = true } else { newNodePreservedCondition = existingNodeCondition.DeepCopy() @@ -2503,6 +2512,11 @@ func (c *controller) computeNewNodePreservedCondition(machinePhase v1alpha1.Mach newNodePreservedCondition.Status = v1.ConditionTrue needsUpdate = true } + if preserveValue == machineutils.PreserveMachineAnnotationValuePreservedByMCM { + newNodePreservedCondition.Reason = v1alpha1.NodePreservedByMCM + } else { + newNodePreservedCondition.Reason = v1alpha1.NodePreservedByUser + } return newNodePreservedCondition, needsUpdate } @@ -2512,62 +2526,66 @@ func (c *controller) shouldNodeBeDrained(machine *v1alpha1.Machine, existingCond if existingCondition == nil { return true } - if existingCondition.Message == v1alpha1.PreservedNodeDrainSuccessful { - return false - } else { - return true - } + return existingCondition.Message != v1alpha1.PreservedNodeDrainSuccessful } return false } // stopMachinePreservation stops the preservation of the machine and node func (c *controller) stopMachinePreservation(ctx context.Context, machine *v1alpha1.Machine) error { - // check if preserveExpiryTime is set, if not, no need to do anything + // removal of preserveExpiryTime is the last step of stopping preservation + // if preserveExpiryTime is not set, preservation is already stopped if !machineutils.IsPreserveExpiryTimeSet(machine) { return nil } nodeName := machine.Labels[v1alpha1.NodeLabelKey] if nodeName != "" { + // Machine has a backing node preservedCondition := v1.NodeCondition{ Type: v1alpha1.NodePreserved, Status: v1.ConditionFalse, LastTransitionTime: metav1.Now(), + Reason: v1alpha1.NodePreservationStopped, } + // Step 1: if backing node exists, change node condition to reflect that preservation has stopped err := nodeops.AddOrUpdateConditionsOnNode(ctx, c.targetCoreClient, nodeName, preservedCondition) if err != nil { return err } // Step 2: remove CA's scale-down disabled annotations to allow CA to scale down node if needed - CAAnnotations := make(map[string]string) - CAAnnotations[autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationKey] = "" + // fetch latest node object since cache may be not be up-to-date with node updated earlier latestNode, err := c.targetCoreClient.CoreV1().Nodes().Get(ctx, nodeName, metav1.GetOptions{}) if err != nil { - klog.Errorf("error trying to get backing node %q for machine %s. Retrying, error: %v", nodeName, machine.Name, err) + klog.Errorf("error trying to get backing node %q for machine %q. Retrying, error: %s", nodeName, machine.Name, err) return err } - latestNodeCopy := latestNode.DeepCopy() - latestNodeCopy, _, _ = annotations.RemoveAnnotation(latestNodeCopy, CAAnnotations) // error can be ignored, always returns nil - _, err = c.targetCoreClient.CoreV1().Nodes().Update(ctx, latestNodeCopy, metav1.UpdateOptions{}) - if err != nil { - klog.Errorf("Node UPDATE failed for node %q of machine %q. Retrying, error: %s", nodeName, machine.Name, err) - return err + if latestNode.Annotations != nil && latestNode.Annotations[autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationKey] != "" { + annotationsToRemove := make(map[string]string) + annotationsToRemove[autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationKey] = "" + nodeCopy := latestNode.DeepCopy() + nodeCopy, _, err = annotations.RemoveAnnotation(nodeCopy, annotationsToRemove) + if err != nil { + klog.Errorf("error trying to remove CA annotation from node %q of machine %q : %s", nodeName, machine.Name, err) + return err + } + _, err = c.targetCoreClient.CoreV1().Nodes().Update(ctx, nodeCopy, metav1.UpdateOptions{}) + if err != nil { + klog.Errorf("Node UPDATE failed for node %q of machine %q. Retrying, error: %s", nodeName, machine.Name, err) + return err + } } } // Step 3: update machine status to set preserve expiry time to metav1.Time{} clone := machine.DeepCopy() - clone.Status.CurrentStatus = v1alpha1.CurrentStatus{ - Phase: clone.Status.CurrentStatus.Phase, - LastUpdateTime: metav1.Now(), - PreserveExpiryTime: metav1.Time{}, - } + clone.Status.CurrentStatus.PreserveExpiryTime = metav1.Time{} + clone.Status.CurrentStatus.LastUpdateTime = metav1.Now() _, err := c.controlMachineClient.Machines(clone.Namespace).UpdateStatus(ctx, clone, metav1.UpdateOptions{}) if err != nil { klog.Errorf("machine/status UPDATE failed for machine %q. Retrying, error: %s", machine.Name, err) return err } - klog.V(3).Infof("Machine status updated to stop preservation for machine %q", machine.Name) + klog.V(3).Infof("Preservation stopped for machine %q", machine.Name) return nil } diff --git a/pkg/util/provider/machineutils/utils.go b/pkg/util/provider/machineutils/utils.go index 429f50acb..5fa1bd87c 100644 --- a/pkg/util/provider/machineutils/utils.go +++ b/pkg/util/provider/machineutils/utils.go @@ -101,8 +101,18 @@ const ( //PreserveMachineAnnotationValueFalse is the annotation value used to explicitly request that // a Machine should not be preserved any longer, even if the expiry timeout has not been reached PreserveMachineAnnotationValueFalse = "false" + + PreserveMac ) +// AllowedPreserveAnnotationValues contains the allowed values for the preserve annotation +var AllowedPreserveAnnotationValues = map[string]bool{ + PreserveMachineAnnotationValueNow: true, + PreserveMachineAnnotationValueWhenFailed: true, + PreserveMachineAnnotationValuePreservedByMCM: true, + PreserveMachineAnnotationValueFalse: true, +} + // RetryPeriod is an alias for specifying the retry period type RetryPeriod time.Duration From b60af945705741c3616dcec060e8fe7d26a8fa60 Mon Sep 17 00:00:00 2001 From: thiyyakat Date: Tue, 23 Dec 2025 11:05:14 +0530 Subject: [PATCH 32/43] Address review comments- part 3: * remove duplicate function to check preservation timeout * rename variables --- pkg/controller/machineset.go | 20 +++++++++---------- .../provider/machinecontroller/machine.go | 2 +- .../machinecontroller/machine_util.go | 9 ++------- pkg/util/provider/machineutils/utils.go | 9 +-------- 4 files changed, 14 insertions(+), 26 deletions(-) diff --git a/pkg/controller/machineset.go b/pkg/controller/machineset.go index 06deb8786..1d1023cc5 100644 --- a/pkg/controller/machineset.go +++ b/pkg/controller/machineset.go @@ -509,7 +509,7 @@ func (c *controller) isMachineCandidateForPreservation(ctx context.Context, mach } } if machineSet.Status.AutoPreserveFailedMachineCount < machineSet.Spec.AutoPreserveFailedMachineMax { - _, err := c.annotateMachineForAutoPreservation(ctx, machine) + err := c.annotateMachineForAutoPreservation(ctx, machine) if err != nil { return true, err } @@ -726,16 +726,16 @@ func getMachinesToDelete(filteredMachines []*v1alpha1.Machine, diff int) []*v1al } func prioritisePreservedMachines(machines []*v1alpha1.Machine) []*v1alpha1.Machine { - pendingMachines := make([]*v1alpha1.Machine, 0, len(machines)) + preservedMachines := make([]*v1alpha1.Machine, 0, len(machines)) otherMachines := make([]*v1alpha1.Machine, 0, len(machines)) for _, mc := range machines { if machineutils.IsPreserveExpiryTimeSet(mc) { - pendingMachines = append(pendingMachines, mc) + preservedMachines = append(preservedMachines, mc) } else { otherMachines = append(otherMachines, mc) } } - return slices.Concat(otherMachines, pendingMachines) + return slices.Concat(otherMachines, preservedMachines) } func getMachineKeys(machines []*v1alpha1.Machine) []string { @@ -958,18 +958,18 @@ func UpdateMachineWithRetries(ctx context.Context, machineClient v1alpha1client. return machine, retryErr } -func (dc *controller) annotateMachineForAutoPreservation(ctx context.Context, m *v1alpha1.Machine) (*v1alpha1.Machine, error) { +func (dc *controller) annotateMachineForAutoPreservation(ctx context.Context, m *v1alpha1.Machine) error { if m.Labels[v1alpha1.NodeLabelKey] != "" { // check if backing node has preserve=false annotation, if yes, do not auto-preserve node, err := dc.nodeLister.Get(m.Labels[v1alpha1.NodeLabelKey]) if err != nil { - return nil, err + return err } if val, exists := node.Annotations[machineutils.PreserveMachineAnnotationKey]; exists && val == machineutils.PreserveMachineAnnotationValueFalse { - return nil, nil + return nil } } - updatedMachine, err := UpdateMachineWithRetries(ctx, dc.controlMachineClient.Machines(m.Namespace), dc.machineLister, m.Namespace, m.Name, func(clone *v1alpha1.Machine) error { + _, err := UpdateMachineWithRetries(ctx, dc.controlMachineClient.Machines(m.Namespace), dc.machineLister, m.Namespace, m.Name, func(clone *v1alpha1.Machine) error { if clone.Annotations == nil { clone.Annotations = make(map[string]string) } @@ -977,9 +977,9 @@ func (dc *controller) annotateMachineForAutoPreservation(ctx context.Context, m return nil }) if err != nil { - return nil, err + return err } klog.V(2).Infof("Updated machine %q with auto-preserved annotation.", m.Name) - return updatedMachine, nil + return nil } diff --git a/pkg/util/provider/machinecontroller/machine.go b/pkg/util/provider/machinecontroller/machine.go index 9e913329a..39d4ecdf3 100644 --- a/pkg/util/provider/machinecontroller/machine.go +++ b/pkg/util/provider/machinecontroller/machine.go @@ -835,7 +835,7 @@ func (c *controller) manageMachinePreservation(ctx context.Context, machine *v1a if !isPreserveAnnotationValueValid(preserveValue) { klog.Warningf("Preserve annotation value %q on machine %s is invalid", preserveValue, machine.Name) return - } else if preserveValue == machineutils.PreserveMachineAnnotationValueFalse || hasMachinePreservationTimedOut(clone) { + } else if preserveValue == machineutils.PreserveMachineAnnotationValueFalse || machineutils.HasPreservationTimedOut(clone) { err = c.stopMachinePreservation(ctx, clone) return } else if preserveValue == machineutils.PreserveMachineAnnotationValueWhenFailed { diff --git a/pkg/util/provider/machinecontroller/machine_util.go b/pkg/util/provider/machinecontroller/machine_util.go index 9e4008fcd..a9acd1aa4 100644 --- a/pkg/util/provider/machinecontroller/machine_util.go +++ b/pkg/util/provider/machinecontroller/machine_util.go @@ -2541,7 +2541,7 @@ func (c *controller) stopMachinePreservation(ctx context.Context, machine *v1alp nodeName := machine.Labels[v1alpha1.NodeLabelKey] if nodeName != "" { // Machine has a backing node - preservedCondition := v1.NodeCondition{ + preservedConditionFalse := v1.NodeCondition{ Type: v1alpha1.NodePreserved, Status: v1.ConditionFalse, LastTransitionTime: metav1.Now(), @@ -2549,7 +2549,7 @@ func (c *controller) stopMachinePreservation(ctx context.Context, machine *v1alp } // Step 1: if backing node exists, change node condition to reflect that preservation has stopped - err := nodeops.AddOrUpdateConditionsOnNode(ctx, c.targetCoreClient, nodeName, preservedCondition) + err := nodeops.AddOrUpdateConditionsOnNode(ctx, c.targetCoreClient, nodeName, preservedConditionFalse) if err != nil { return err } @@ -2701,8 +2701,3 @@ func (c *controller) drainPreservedNode(ctx context.Context, machine *v1alpha1.M } return nil } - -// hasMachinePreservationTimedOut returns true if preserve expiry time has lapsed -func hasMachinePreservationTimedOut(machine *v1alpha1.Machine) bool { - return machineutils.IsPreserveExpiryTimeSet(machine) && metav1.Now().After(machine.Status.CurrentStatus.PreserveExpiryTime.Time) -} diff --git a/pkg/util/provider/machineutils/utils.go b/pkg/util/provider/machineutils/utils.go index 5fa1bd87c..16f7ebdd8 100644 --- a/pkg/util/provider/machineutils/utils.go +++ b/pkg/util/provider/machineutils/utils.go @@ -101,8 +101,6 @@ const ( //PreserveMachineAnnotationValueFalse is the annotation value used to explicitly request that // a Machine should not be preserved any longer, even if the expiry timeout has not been reached PreserveMachineAnnotationValueFalse = "false" - - PreserveMac ) // AllowedPreserveAnnotationValues contains the allowed values for the preserve annotation @@ -162,10 +160,5 @@ func IsPreserveExpiryTimeSet(m *v1alpha1.Machine) bool { // HasPreservationTimedOut checks if the Status.CurrentStatus.PreserveExpiryTime has not yet passed func HasPreservationTimedOut(m *v1alpha1.Machine) bool { - if m.Status.CurrentStatus.PreserveExpiryTime.IsZero() { - return true - } else if m.Status.CurrentStatus.PreserveExpiryTime.After(time.Now()) { - return false - } - return true + return IsPreserveExpiryTimeSet(m) && m.Status.CurrentStatus.PreserveExpiryTime.After(time.Now()) } From 1a9752247fb2d1c903b7f352096c1d2eef7cc350 Mon Sep 17 00:00:00 2001 From: thiyyakat Date: Tue, 23 Dec 2025 13:43:06 +0530 Subject: [PATCH 33/43] Address review comments- part 4: * reduce get calls * remove usage of RemoveAnnotations() --- .../provider/machinecontroller/machine.go | 2 +- .../machinecontroller/machine_util.go | 32 ++++++++----------- pkg/util/provider/machineutils/utils.go | 2 +- 3 files changed, 16 insertions(+), 20 deletions(-) diff --git a/pkg/util/provider/machinecontroller/machine.go b/pkg/util/provider/machinecontroller/machine.go index 39d4ecdf3..1de75ca9d 100644 --- a/pkg/util/provider/machinecontroller/machine.go +++ b/pkg/util/provider/machinecontroller/machine.go @@ -835,7 +835,7 @@ func (c *controller) manageMachinePreservation(ctx context.Context, machine *v1a if !isPreserveAnnotationValueValid(preserveValue) { klog.Warningf("Preserve annotation value %q on machine %s is invalid", preserveValue, machine.Name) return - } else if preserveValue == machineutils.PreserveMachineAnnotationValueFalse || machineutils.HasPreservationTimedOut(clone) { + } else if preserveValue == machineutils.PreserveMachineAnnotationValueFalse || (machineutils.IsPreserveExpiryTimeSet(clone) && machineutils.HasPreservationTimedOut(clone)) { err = c.stopMachinePreservation(ctx, clone) return } else if preserveValue == machineutils.PreserveMachineAnnotationValueWhenFailed { diff --git a/pkg/util/provider/machinecontroller/machine_util.go b/pkg/util/provider/machinecontroller/machine_util.go index a9acd1aa4..da6c557c6 100644 --- a/pkg/util/provider/machinecontroller/machine_util.go +++ b/pkg/util/provider/machinecontroller/machine_util.go @@ -2541,37 +2541,33 @@ func (c *controller) stopMachinePreservation(ctx context.Context, machine *v1alp nodeName := machine.Labels[v1alpha1.NodeLabelKey] if nodeName != "" { // Machine has a backing node + node, err := c.nodeLister.Get(nodeName) + if err != nil { + klog.Errorf("error trying to get node %q of machine %q: %v. Retrying.", nodeName, machine.Name, err) + return err + } + // prepare NodeCondition to set preservation as stopped preservedConditionFalse := v1.NodeCondition{ Type: v1alpha1.NodePreserved, Status: v1.ConditionFalse, LastTransitionTime: metav1.Now(), Reason: v1alpha1.NodePreservationStopped, } - - // Step 1: if backing node exists, change node condition to reflect that preservation has stopped - err := nodeops.AddOrUpdateConditionsOnNode(ctx, c.targetCoreClient, nodeName, preservedConditionFalse) + // Step 1: change node condition to reflect that preservation has stopped + updatedNode := nodeops.AddOrUpdateCondition(node, preservedConditionFalse) + updatedNode, err = c.targetCoreClient.CoreV1().Nodes().UpdateStatus(ctx, updatedNode, metav1.UpdateOptions{}) if err != nil { + klog.Errorf("error trying to update node preserved condition for node %q of machine %q : %s", nodeName, machine.Name, err) return err } // Step 2: remove CA's scale-down disabled annotations to allow CA to scale down node if needed // fetch latest node object since cache may be not be up-to-date with node updated earlier - latestNode, err := c.targetCoreClient.CoreV1().Nodes().Get(ctx, nodeName, metav1.GetOptions{}) - if err != nil { - klog.Errorf("error trying to get backing node %q for machine %q. Retrying, error: %s", nodeName, machine.Name, err) - return err - } - if latestNode.Annotations != nil && latestNode.Annotations[autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationKey] != "" { - annotationsToRemove := make(map[string]string) - annotationsToRemove[autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationKey] = "" - nodeCopy := latestNode.DeepCopy() - nodeCopy, _, err = annotations.RemoveAnnotation(nodeCopy, annotationsToRemove) - if err != nil { - klog.Errorf("error trying to remove CA annotation from node %q of machine %q : %s", nodeName, machine.Name, err) - return err - } + if updatedNode.Annotations != nil && updatedNode.Annotations[autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationKey] != "" { + nodeCopy := updatedNode.DeepCopy() + delete(nodeCopy.Annotations, autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationKey) _, err = c.targetCoreClient.CoreV1().Nodes().Update(ctx, nodeCopy, metav1.UpdateOptions{}) if err != nil { - klog.Errorf("Node UPDATE failed for node %q of machine %q. Retrying, error: %s", nodeName, machine.Name, err) + klog.Errorf("node UPDATE failed for node %q of machine %q. Retrying, error: %s", nodeName, machine.Name, err) return err } } diff --git a/pkg/util/provider/machineutils/utils.go b/pkg/util/provider/machineutils/utils.go index 16f7ebdd8..eeb722b9e 100644 --- a/pkg/util/provider/machineutils/utils.go +++ b/pkg/util/provider/machineutils/utils.go @@ -160,5 +160,5 @@ func IsPreserveExpiryTimeSet(m *v1alpha1.Machine) bool { // HasPreservationTimedOut checks if the Status.CurrentStatus.PreserveExpiryTime has not yet passed func HasPreservationTimedOut(m *v1alpha1.Machine) bool { - return IsPreserveExpiryTimeSet(m) && m.Status.CurrentStatus.PreserveExpiryTime.After(time.Now()) + return !m.Status.CurrentStatus.PreserveExpiryTime.After(time.Now()) } From 8da62a7bf38b3f251f29a6a8ab07815e8bae3f50 Mon Sep 17 00:00:00 2001 From: thiyyakat Date: Wed, 24 Dec 2025 16:27:25 +0530 Subject: [PATCH 34/43] Add unit tests for preservation logic in machine.go --- .../provider/machinecontroller/machine.go | 58 +- .../machinecontroller/machine_test.go | 1136 +++++++++++------ 2 files changed, 766 insertions(+), 428 deletions(-) diff --git a/pkg/util/provider/machinecontroller/machine.go b/pkg/util/provider/machinecontroller/machine.go index 1de75ca9d..5ad35b52d 100644 --- a/pkg/util/provider/machinecontroller/machine.go +++ b/pkg/util/provider/machinecontroller/machine.go @@ -360,31 +360,6 @@ func (c *controller) reconcileClusterMachineTermination(key string) error { return nil } -// handlePreserveAnnotationsChange returns true if there is a change in preserve annotations -// it also handles the special case where the annotation is changed from 'now' to 'when-failed' -// in which case it stops the preservation if expiry time is already set -func (c *controller) handlePreserveAnnotationsChange(oldAnnotations, newAnnotations map[string]string, machine *v1alpha1.Machine) bool { - valueNew, existsInNew := newAnnotations[machineutils.PreserveMachineAnnotationKey] - valueOld, existsInOld := oldAnnotations[machineutils.PreserveMachineAnnotationKey] - if valueNew != machineutils.PreserveMachineAnnotationValueWhenFailed || valueOld != machineutils.PreserveMachineAnnotationValueNow { - return existsInOld != existsInNew || valueOld != valueNew - } - // Special case: annotation changed from 'now' to 'when-failed' - isPreserved := machineutils.IsPreserveExpiryTimeSet(machine) - if !isPreserved { - return true - } - ctx := context.Background() - err := clientretry.RetryOnConflict(nodeops.Backoff, func() error { - klog.V(3).Infof("Stopping preservation for machine %q as preserve annotation changed from 'now' to 'when-failed'.", machine.Name) - return c.stopMachinePreservation(ctx, machine) - }) - if err != nil { - klog.Errorf("error while stopping preservation for machine %q: %v. Use preserve=false to stop preservation.", machine.Name, err) - } - return true -} - /* SECTION Machine operations - Create, Delete @@ -805,6 +780,36 @@ func (c *controller) isCreationProcessing(machine *v1alpha1.Machine) bool { return isMachineInCreationFlow } +/* + SECTION + Machine Preservation operations +*/ + +// handlePreserveAnnotationsChange returns true if there is a change in preserve annotations +// it also handles the special case where the annotation is changed from 'now' to 'when-failed' +// in which case it stops the preservation if expiry time is already set +func (c *controller) handlePreserveAnnotationsChange(oldAnnotations, newAnnotations map[string]string, machine *v1alpha1.Machine) bool { + valueNew, existsInNew := newAnnotations[machineutils.PreserveMachineAnnotationKey] + valueOld, existsInOld := oldAnnotations[machineutils.PreserveMachineAnnotationKey] + if valueNew != machineutils.PreserveMachineAnnotationValueWhenFailed || valueOld != machineutils.PreserveMachineAnnotationValueNow { + return existsInOld != existsInNew || valueOld != valueNew + } + // Special case: annotation changed from 'now' to 'when-failed' + isPreserved := machineutils.IsPreserveExpiryTimeSet(machine) + if !isPreserved { + return true + } + ctx := context.Background() + err := clientretry.RetryOnConflict(nodeops.Backoff, func() error { + klog.V(3).Infof("Stopping preservation for machine %q as preserve annotation changed from 'now' to 'when-failed'.", machine.Name) + return c.stopMachinePreservation(ctx, machine) + }) + if err != nil { + klog.Errorf("error while stopping preservation for machine %q: %v. Use preserve=false to stop preservation.", machine.Name, err) + } + return true +} + // manageMachinePreservation checks if any preservation-related operations need to be performed on the machine and node objects func (c *controller) manageMachinePreservation(ctx context.Context, machine *v1alpha1.Machine) (retry machineutils.RetryPeriod, err error) { defer func() { @@ -813,8 +818,9 @@ func (c *controller) manageMachinePreservation(ctx context.Context, machine *v1a retry = machineutils.ConflictRetry } retry = machineutils.ShortRetry + } else { + retry = machineutils.LongRetry } - retry = machineutils.LongRetry }() preserveValue, exists, err := c.computeEffectivePreserveAnnotationValue(machine) diff --git a/pkg/util/provider/machinecontroller/machine_test.go b/pkg/util/provider/machinecontroller/machine_test.go index d5c5b5925..a00425c7f 100644 --- a/pkg/util/provider/machinecontroller/machine_test.go +++ b/pkg/util/provider/machinecontroller/machine_test.go @@ -7,6 +7,7 @@ package controller import ( "context" "fmt" + k8stesting "k8s.io/client-go/testing" "math" "time" @@ -16,7 +17,6 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/validation/field" - k8stesting "k8s.io/client-go/testing" machineapi "github.com/gardener/machine-controller-manager/pkg/apis/machine" "github.com/gardener/machine-controller-manager/pkg/apis/machine/v1alpha1" @@ -4074,470 +4074,802 @@ var _ = Describe("machine", func() { }), ) }) - /* - Describe("#checkMachineTimeout", func() { - type setup struct { - machines []*v1alpha1.Machine - } - type action struct { - machine string - } - type expect struct { - machine *v1alpha1.Machine - err bool - } - type data struct { - setup setup - action action - expect expect + + Describe("#handlePreserveAnnotationsChange", func() { + type setup struct { + oldAnnotations map[string]string + newAnnotations map[string]string + machine *v1alpha1.Machine + node *corev1.Node + } + + type expect struct { + change bool + } + type testCase struct { + setup setup + expect expect + } + DescribeTable("##handlePreserveAnnotationsChange scenarios", func(tc testCase) { + stop := make(chan struct{}) + defer close(stop) + + var controlMachineObjects []runtime.Object + + controlMachineObjects = append(controlMachineObjects, tc.setup.machine) + var targetCoreObjects []runtime.Object + if tc.setup.node != nil { + targetCoreObjects = append(targetCoreObjects, tc.setup.node) } - objMeta := &metav1.ObjectMeta{ - GenerateName: "machine", - Namespace: "test", + + c, trackers := createController(stop, testNamespace, controlMachineObjects, nil, targetCoreObjects, nil, false) + defer trackers.Stop() + + waitForCacheSync(stop, c) + result := c.handlePreserveAnnotationsChange(tc.setup.oldAnnotations, tc.setup.newAnnotations, tc.setup.machine) + Expect(result).To(Equal(tc.expect.change)) + if tc.setup.newAnnotations != nil && tc.setup.oldAnnotations != nil && tc.setup.newAnnotations[machineutils.PreserveMachineAnnotationKey] == machineutils.PreserveMachineAnnotationValueWhenFailed && tc.setup.oldAnnotations[machineutils.PreserveMachineAnnotationKey] == machineutils.PreserveMachineAnnotationValueNow { + updatedMachine, err := c.controlMachineClient.Machines(testNamespace).Get(context.TODO(), tc.setup.machine.Name, metav1.GetOptions{}) + Expect(err).ToNot(HaveOccurred()) + Expect(updatedMachine.Status.CurrentStatus.PreserveExpiryTime.IsZero()).To(BeTrue()) // machine preservation should have been stopped } - machineName := "machine-0" - timeOutOccurred := -21 * time.Minute - timeOutNotOccurred := -5 * time.Minute - creationTimeOut := 20 * time.Minute - healthTimeOut := 10 * time.Minute - DescribeTable("##Machine Timeout Scenarios", - func(data *data) { - stop := make(chan struct{}) - defer close(stop) - machineObjects := []runtime.Object{} - for _, o := range data.setup.machines { - machineObjects = append(machineObjects, o) - } - coreObjects := []runtime.Object{} - controller, trackers := createController(stop, objMeta.Namespace, machineObjects, nil, coreObjects) - defer trackers.Stop() - waitForCacheSync(stop, controller) - action := data.action - machine, err := controller.controlMachineClient.Machines(objMeta.Namespace).Get(action.machine, metav1.GetOptions{}) - //Expect(err).ToNot(HaveOccurred()) - controller.checkMachineTimeout(machine) - actual, err := controller.controlMachineClient.Machines(machine.Namespace).Get(machine.Name, metav1.GetOptions{}) - Expect(err).To(BeNil()) - Expect(actual.Status.CurrentStatus.Phase).To(Equal(data.expect.machine.Status.CurrentStatus.Phase)) - Expect(actual.Status.CurrentStatus.//TimeoutActive).To(Equal(data.expect.machine.Status.CurrentStatus.//TimeoutActive)) - Expect(actual.Status.LastOperation.Description).To(Equal(data.expect.machine.Status.LastOperation.Description)) - Expect(actual.Status.LastOperation.State).To(Equal(data.expect.machine.Status.LastOperation.State)) - Expect(actual.Status.LastOperation.Type).To(Equal(data.expect.machine.Status.LastOperation.Type)) - }, - Entry("Machine is still running", &data{ - setup: setup{ - machines: newMachines(1, &v1alpha1.MachineTemplateSpec{ - ObjectMeta: *newObjectMeta(objMeta, 0), - }, &v1alpha1.MachineStatus{ - CurrentStatus: v1alpha1.CurrentStatus{ - Phase: v1alpha1.MachineRunning, - //TimeoutActive: false, - LastUpdateTime: metav1.NewTime(time.Now().Add(timeOutNotOccurred)), - }, - LastOperation: v1alpha1.LastOperation{ - Description: fmt.Sprintf("Machine % successfully joined the cluster", machineName), - State: v1alpha1.MachineStateSuccessful, - Type: v1alpha1.MachineOperationCreate, - LastUpdateTime: metav1.NewTime(time.Now().Add(timeOutNotOccurred)), + }, + Entry("no change in preserve annotations", testCase{ + setup: setup{ + oldAnnotations: map[string]string{machineutils.PreserveMachineAnnotationKey: "someValue"}, + newAnnotations: map[string]string{machineutils.PreserveMachineAnnotationKey: "someValue"}, + machine: &v1alpha1.Machine{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: testNamespace, + Name: "m1", + Annotations: map[string]string{machineutils.PreserveMachineAnnotationKey: "someValue"}, + Labels: map[string]string{ + v1alpha1.NodeLabelKey: "node-1", }, - }, nil, nil, nil), - }, - action: action{ - machine: machineName, - }, - expect: expect{ - machine: newMachine(&v1alpha1.MachineTemplateSpec{ - ObjectMeta: *newObjectMeta(objMeta, 0), - }, &v1alpha1.MachineStatus{ + }, Status: v1alpha1.MachineStatus{ CurrentStatus: v1alpha1.CurrentStatus{ - Phase: v1alpha1.MachineRunning, + Phase: v1alpha1.MachineRunning, + LastUpdateTime: metav1.Now(), + PreserveExpiryTime: metav1.Time{Time: time.Now().Add(1 * time.Hour)}, }, - LastOperation: v1alpha1.LastOperation{ - Description: fmt.Sprintf("Machine % successfully joined the cluster", machineName), - State: v1alpha1.MachineStateSuccessful, - Type: v1alpha1.MachineOperationCreate, - }, - }, nil, nil, nil), + }, }, - }), - Entry("Machine creation has still not timed out", &data{ - setup: setup{ - machines: newMachines(1, &v1alpha1.MachineTemplateSpec{ - ObjectMeta: *newObjectMeta(objMeta, 0), - }, &v1alpha1.MachineStatus{ - CurrentStatus: v1alpha1.CurrentStatus{ - Phase: v1alpha1.MachineUnknown, - LastUpdateTime: metav1.NewTime(time.Now().Add(timeOutNotOccurred)), - }, - LastOperation: v1alpha1.LastOperation{ - Description: fmt.Sprintf("Machine %s is unhealthy - changing MachineState to Unknown", machineName), - State: v1alpha1.MachineStateProcessing, - Type: v1alpha1.MachineOperationCreate, - LastUpdateTime: metav1.NewTime(time.Now().Add(timeOutNotOccurred)), + }, + expect: expect{ + change: false, + }, + }), + Entry("preserve annotation added on machine", testCase{ + setup: setup{ + oldAnnotations: map[string]string{machineutils.PreserveMachineAnnotationKey: ""}, + newAnnotations: map[string]string{machineutils.PreserveMachineAnnotationKey: "newValue"}, + machine: &v1alpha1.Machine{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: testNamespace, + Name: "m1", + Annotations: map[string]string{machineutils.PreserveMachineAnnotationKey: "newValue"}, + Labels: map[string]string{ + v1alpha1.NodeLabelKey: "node-1", }, - }, nil, nil, nil), - }, - action: action{ - machine: machineName, - }, - expect: expect{ - machine: newMachine(&v1alpha1.MachineTemplateSpec{ - ObjectMeta: *newObjectMeta(objMeta, 0), - }, &v1alpha1.MachineStatus{ + }, Status: v1alpha1.MachineStatus{ CurrentStatus: v1alpha1.CurrentStatus{ - Phase: v1alpha1.MachineUnknown, - }, - LastOperation: v1alpha1.LastOperation{ - Description: fmt.Sprintf("Machine %s is unhealthy - changing MachineState to Unknown", machineName), - State: v1alpha1.MachineStateProcessing, - Type: v1alpha1.MachineOperationCreate, + Phase: v1alpha1.MachineRunning, + LastUpdateTime: metav1.Now(), }, - }, nil, nil, nil), + }, }, - }), - Entry("Machine creation has timed out", &data{ - setup: setup{ - machines: newMachines(1, &v1alpha1.MachineTemplateSpec{ - ObjectMeta: *newObjectMeta(objMeta, 0), - }, &v1alpha1.MachineStatus{ - CurrentStatus: v1alpha1.CurrentStatus{ - Phase: v1alpha1.MachinePending, - LastUpdateTime: metav1.NewTime(time.Now().Add(timeOutOccurred)), + }, + expect: expect{ + change: true, + }, + }), + Entry("preserve annotation removed", testCase{ + setup: setup{ + oldAnnotations: map[string]string{machineutils.PreserveMachineAnnotationKey: "someValue"}, + newAnnotations: map[string]string{"someOtherKey": "someValue"}, + machine: &v1alpha1.Machine{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: testNamespace, + Name: "m1", + Annotations: map[string]string{"someOtherKey": "someValue"}, + Labels: map[string]string{ + v1alpha1.NodeLabelKey: "node-1", }, - LastOperation: v1alpha1.LastOperation{ - Description: "Creating machine on cloud provider", - State: v1alpha1.MachineStateProcessing, - Type: v1alpha1.MachineOperationCreate, - LastUpdateTime: metav1.NewTime(time.Now().Add(timeOutOccurred)), + }}}, + expect: expect{ + change: true, + }, + }), + Entry("preserve annotation value changed", testCase{ + setup: setup{ + oldAnnotations: map[string]string{machineutils.PreserveMachineAnnotationKey: "oldValue"}, + newAnnotations: map[string]string{machineutils.PreserveMachineAnnotationKey: "newValue"}, + machine: &v1alpha1.Machine{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: testNamespace, + Name: "m1", + Annotations: map[string]string{machineutils.PreserveMachineAnnotationKey: "newValue"}, + Labels: map[string]string{ + v1alpha1.NodeLabelKey: "node-1", }, - }, nil, nil, nil), - }, - action: action{ - machine: machineName, - }, - expect: expect{ - machine: newMachine(&v1alpha1.MachineTemplateSpec{ - ObjectMeta: *newObjectMeta(objMeta, 0), - }, &v1alpha1.MachineStatus{ - CurrentStatus: v1alpha1.CurrentStatus{ - Phase: v1alpha1.MachineFailed, + }}}, + expect: expect{ + change: true, + }, + }), + Entry("both annotations are nil", testCase{ + setup: setup{ + oldAnnotations: nil, + newAnnotations: nil, + machine: &v1alpha1.Machine{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: testNamespace, + Name: "m1", + Labels: map[string]string{ + v1alpha1.NodeLabelKey: "node-1", }, - LastOperation: v1alpha1.LastOperation{ - Description: fmt.Sprintf( - "Machine %s failed to join the cluster in %s minutes.", - machineName, - creationTimeOut, - ), - State: v1alpha1.MachineStateFailed, - Type: v1alpha1.MachineOperationCreate, + }}}, + expect: expect{ + change: false, + }, + }), + Entry("preserve annotation changed from now to when-failed", testCase{ + setup: setup{ + oldAnnotations: map[string]string{machineutils.PreserveMachineAnnotationKey: machineutils.PreserveMachineAnnotationValueNow}, + newAnnotations: map[string]string{machineutils.PreserveMachineAnnotationKey: machineutils.PreserveMachineAnnotationValueWhenFailed}, + machine: &v1alpha1.Machine{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: testNamespace, + Name: "m1", + Annotations: map[string]string{machineutils.PreserveMachineAnnotationKey: machineutils.PreserveMachineAnnotationValueWhenFailed}, + Labels: map[string]string{ + v1alpha1.NodeLabelKey: "node-1", }, - }, nil, nil, nil), - }, - }), - Entry("Machine health has timed out", &data{ - setup: setup{ - machines: newMachines(1, &v1alpha1.MachineTemplateSpec{ - ObjectMeta: *newObjectMeta(objMeta, 0), - }, &v1alpha1.MachineStatus{ + }, + Status: v1alpha1.MachineStatus{ CurrentStatus: v1alpha1.CurrentStatus{ - Phase: v1alpha1.MachineUnknown, - LastUpdateTime: metav1.NewTime(time.Now().Add(timeOutOccurred)), - }, - LastOperation: v1alpha1.LastOperation{ - Description: fmt.Sprintf("Machine %s is unhealthy - changing MachineState to Unknown", machineName), - State: v1alpha1.MachineStateProcessing, - Type: v1alpha1.MachineOperationHealthCheck, - LastUpdateTime: metav1.NewTime(time.Now().Add(timeOutOccurred)), + Phase: v1alpha1.MachineRunning, + LastUpdateTime: metav1.Now(), + PreserveExpiryTime: metav1.Time{Time: time.Now().Add(1 * time.Hour)}, }, - }, nil, nil, nil), + }, }, - action: action{ - machine: machineName, + node: &corev1.Node{ + ObjectMeta: metav1.ObjectMeta{ + Name: "node-1", + }, }, - expect: expect{ - machine: newMachine(&v1alpha1.MachineTemplateSpec{ - ObjectMeta: *newObjectMeta(objMeta, 0), - }, &v1alpha1.MachineStatus{ - CurrentStatus: v1alpha1.CurrentStatus{ - Phase: v1alpha1.MachineFailed, - }, - LastOperation: v1alpha1.LastOperation{ - Description: fmt.Sprintf( - "Machine %s is not healthy since %s minutes. Changing status to failed. Node Conditions: %+v", - machineName, - healthTimeOut, - []corev1.NodeCondition{}, - ), - State: v1alpha1.MachineStateFailed, - Type: v1alpha1.MachineOperationHealthCheck, + }, + expect: expect{ + change: true, + }, + }), + ) + }) + + Describe("#computeEffectivePreserveAnnotationValue", func() { + type setup struct { + machine *v1alpha1.Machine + node *corev1.Node + } + type expect struct { + preserveValue string + exists bool + err error + } + type testCase struct { + setup setup + expect expect + } + + DescribeTable("computeEffectivePreserveAnnotationValue behavior", + func(tc testCase) { + + stop := make(chan struct{}) + defer close(stop) + + var controlMachineObjects []runtime.Object + var targetCoreObjects []runtime.Object + + // Build machine + controlMachineObjects = append(controlMachineObjects, tc.setup.machine) + if tc.setup.node != nil { + targetCoreObjects = append(targetCoreObjects, tc.setup.node) + } + + c, trackers := createController(stop, testNamespace, controlMachineObjects, nil, targetCoreObjects, nil, false) + defer trackers.Stop() + + waitForCacheSync(stop, c) + value, exists, err := c.computeEffectivePreserveAnnotationValue(tc.setup.machine) + + if tc.expect.err != nil { + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(Equal(tc.expect.err.Error())) + return + } + Expect(err).ToNot(HaveOccurred()) + Expect(exists).To(Equal(tc.expect.exists)) + Expect(value).To(Equal(tc.expect.preserveValue)) + }, + Entry("neither machine nor node has preserve annotation", testCase{ + setup: setup{ + machine: &v1alpha1.Machine{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: testNamespace, + Name: "m1", + Labels: map[string]string{ + v1alpha1.NodeLabelKey: "node-1", }, - }, nil, nil, nil), + }}, + node: &corev1.Node{ + ObjectMeta: metav1.ObjectMeta{ + Name: "node-1", + }, }, - }), - ) - }) - Describe("#updateMachineState", func() { - type setup struct { - machines []*v1alpha1.Machine - nodes []*corev1.Node - } - type action struct { - machine string - } - type expect struct { - machine *v1alpha1.Machine - err bool - } - type data struct { - setup setup - action action - expect expect - } - objMeta := &metav1.ObjectMeta{ - GenerateName: "machine", - // using default namespace for non-namespaced objects - // as our current fake client is with the assumption - // that all objects are namespaced - Namespace: "", - } - machineName := "machine-0" - DescribeTable("##Different machine state update scenrios", - func(data *data) { - stop := make(chan struct{}) - defer close(stop) - machineObjects := []runtime.Object{} - for _, o := range data.setup.machines { - machineObjects = append(machineObjects, o) - } - coreObjects := []runtime.Object{} - for _, o := range data.setup.nodes { - coreObjects = append(coreObjects, o) - } - controller, trackers := createController(stop, objMeta.Namespace, machineObjects, nil, coreObjects) - defer trackers.Stop() - waitForCacheSync(stop, controller) - action := data.action - machine, err := controller.controlMachineClient.Machines(objMeta.Namespace).Get(action.machine, metav1.GetOptions{}) - Expect(err).ToNot(HaveOccurred()) - controller.updateMachineState(machine) - actual, err := controller.controlMachineClient.Machines(objMeta.Namespace).Get(action.machine, metav1.GetOptions{}) - Expect(err).To(BeNil()) - Expect(actual.Name).To(Equal(data.expect.machine.Name)) - Expect(actual.Status.Node).To(Equal(data.expect.machine.Status.Node)) - Expect(actual.Status.CurrentStatus.Phase).To(Equal(data.expect.machine.Status.CurrentStatus.Phase)) - Expect(actual.Status.CurrentStatus.//TimeoutActive).To(Equal(data.expect.machine.Status.CurrentStatus.//TimeoutActive)) - Expect(actual.Status.LastOperation.State).To(Equal(data.expect.machine.Status.LastOperation.State)) - Expect(actual.Status.LastOperation.Type).To(Equal(data.expect.machine.Status.LastOperation.Type)) - Expect(actual.Status.LastOperation.Description).To(Equal(data.expect.machine.Status.LastOperation.Description)) - if data.expect.machine.Labels != nil { - if _, ok := data.expect.machine.Labels["node"]; ok { - Expect(actual.Labels["node"]).To(Equal(data.expect.machine.Labels["node"])) - } - } - for i := range actual.Status.Conditions { - Expect(actual.Status.Conditions[i].Type).To(Equal(data.expect.machine.Status.Conditions[i].Type)) - Expect(actual.Status.Conditions[i].Status).To(Equal(data.expect.machine.Status.Conditions[i].Status)) - Expect(actual.Status.Conditions[i].Reason).To(Equal(data.expect.machine.Status.Conditions[i].Reason)) - Expect(actual.Status.Conditions[i].Message).To(Equal(data.expect.machine.Status.Conditions[i].Message)) - } }, - Entry("Machine does not have a node backing", &data{ - setup: setup{ - machines: newMachines(1, &v1alpha1.MachineTemplateSpec{ - ObjectMeta: *newObjectMeta(objMeta, 0), - }, &v1alpha1.MachineStatus{}, nil, nil, nil), - }, - action: action{ - machine: machineName, - }, - expect: expect{ - machine: newMachine(&v1alpha1.MachineTemplateSpec{ - ObjectMeta: *newObjectMeta(objMeta, 0), - }, &v1alpha1.MachineStatus{}, nil, nil, nil), + expect: expect{ + preserveValue: "", + exists: false, + err: nil, + }, + }), + Entry("only machine has preserve annotation", testCase{ + setup: setup{ + machine: &v1alpha1.Machine{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: testNamespace, + Name: "m1", + Annotations: map[string]string{machineutils.PreserveMachineAnnotationKey: "machineValue"}, + Labels: map[string]string{ + v1alpha1.NodeLabelKey: "node-1", + }, + }}, + node: &corev1.Node{ + ObjectMeta: metav1.ObjectMeta{ + Name: "node-1", + }, }, - }), - Entry("Node object backing machine not found and machine conditions are empty", &data{ - setup: setup{ - machines: newMachines(1, &v1alpha1.MachineTemplateSpec{ - ObjectMeta: *newObjectMeta(objMeta, 0), - }, &v1alpha1.MachineStatus{ - Node: "dummy-node", - }, nil, nil, nil), + }, + expect: expect{ + preserveValue: "machineValue", + exists: true, + err: nil, + }, + }), + Entry("only node has preserve annotation", testCase{ + setup: setup{ + machine: &v1alpha1.Machine{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: testNamespace, + Name: "m1", + Labels: map[string]string{ + v1alpha1.NodeLabelKey: "node-1", + }, + }}, + node: &corev1.Node{ + ObjectMeta: metav1.ObjectMeta{ + Name: "node-1", + Annotations: map[string]string{machineutils.PreserveMachineAnnotationKey: "nodeValue"}, + }, }, - action: action{ - machine: machineName, + }, + expect: expect{ + preserveValue: "nodeValue", + exists: true, + err: nil, + }, + }), + Entry("both machine and node have preserve annotation - node takes precedence", testCase{ + setup: setup{ + machine: &v1alpha1.Machine{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: testNamespace, + Name: "m1", + Annotations: map[string]string{machineutils.PreserveMachineAnnotationKey: "machineValue"}, + Labels: map[string]string{ + v1alpha1.NodeLabelKey: "node-1", + }, + }}, + node: &corev1.Node{ + ObjectMeta: metav1.ObjectMeta{ + Name: "node-1", + Annotations: map[string]string{machineutils.PreserveMachineAnnotationKey: "nodeValue"}, + }, }, - expect: expect{ - machine: newMachine(&v1alpha1.MachineTemplateSpec{ - ObjectMeta: *newObjectMeta(objMeta, 0), - }, &v1alpha1.MachineStatus{ - Node: "dummy-node", - }, nil, nil, nil), - }, - }), - Entry("Machine is running but node object is lost", &data{ - setup: setup{ - machines: newMachines(1, &v1alpha1.MachineTemplateSpec{ - ObjectMeta: *newObjectMeta(objMeta, 0), - }, &v1alpha1.MachineStatus{ - Node: "dummy-node", + }, + expect: expect{ + preserveValue: "nodeValue", + exists: true, + err: nil, + }, + }), + Entry("machine has node label but node object is not found", testCase{ + setup: setup{ + machine: &v1alpha1.Machine{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: testNamespace, + Name: "m1", + Annotations: map[string]string{machineutils.PreserveMachineAnnotationKey: "machineValue"}, + Labels: map[string]string{ + v1alpha1.NodeLabelKey: "node-1", + }, + }}, + node: nil, + }, + expect: expect{ + preserveValue: "", + exists: false, + err: fmt.Errorf("node %q not found", "node-1"), + }, + }), + Entry("machine does not have node label", testCase{ + setup: setup{ + machine: &v1alpha1.Machine{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: testNamespace, + Name: "m1", + Annotations: map[string]string{machineutils.PreserveMachineAnnotationKey: "machineValue"}, + Labels: map[string]string{}, + }}, + }, + expect: expect{ + preserveValue: "machineValue", + exists: true, + err: nil, + }, + }), + ) + }) + + Describe("#manageMachinePreservation", func() { + type setup struct { + machine *v1alpha1.Machine + node *corev1.Node + } + type expect struct { + retry machineutils.RetryPeriod + preserveExpiryTimeIsSet bool + err error + nodeCondition *corev1.NodeCondition + } + type testCase struct { + setup setup + expect expect + } + + DescribeTable("manageMachinePreservation behavior", + func(tc testCase) { + + stop := make(chan struct{}) + defer close(stop) + + var controlMachineObjects []runtime.Object + var targetCoreObjects []runtime.Object + + // Build machine + controlMachineObjects = append(controlMachineObjects, tc.setup.machine) + if tc.setup.node != nil { + targetCoreObjects = append(targetCoreObjects, tc.setup.node) + } + + c, trackers := createController(stop, testNamespace, controlMachineObjects, nil, targetCoreObjects, nil, false) + defer trackers.Stop() + + waitForCacheSync(stop, c) + retry, err := c.manageMachinePreservation(context.TODO(), tc.setup.machine) + Expect(retry).To(Equal(tc.expect.retry)) + if tc.expect.err != nil { + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(Equal(tc.expect.err.Error())) + return + } + Expect(err).ToNot(HaveOccurred()) + updatedMachine, err := c.controlMachineClient.Machines(tc.setup.machine.Namespace).Get(context.TODO(), tc.setup.machine.Name, metav1.GetOptions{}) + Expect(err).ToNot(HaveOccurred()) + + if tc.expect.preserveExpiryTimeIsSet { + Expect(updatedMachine.Status.CurrentStatus.PreserveExpiryTime.IsZero()).To(BeFalse()) + } else { + Expect(updatedMachine.Status.CurrentStatus.PreserveExpiryTime.IsZero()).To(BeTrue()) + } + if tc.setup.machine.Labels[v1alpha1.NodeLabelKey] != "" { + updatedNode, err := c.targetCoreClient.CoreV1().Nodes().Get(context.TODO(), tc.setup.machine.Labels[v1alpha1.NodeLabelKey], metav1.GetOptions{}) + Expect(err).ToNot(HaveOccurred()) + found := false + if tc.expect.nodeCondition != nil { + for _, cond := range updatedNode.Status.Conditions { + if cond.Type == tc.expect.nodeCondition.Type { + found = true + Expect(cond.Status).To(Equal(tc.expect.nodeCondition.Status)) + break + } + } + } + + if tc.expect.nodeCondition != nil { + Expect(found).To(BeTrue()) + } else { + Expect(found).To(BeFalse()) + } + + } + + }, + Entry("no preserve annotation on machine and node", testCase{ + setup: setup{ + machine: &v1alpha1.Machine{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: testNamespace, + Name: "m1", + Labels: map[string]string{ + v1alpha1.NodeLabelKey: "node-1", + }, + }, Status: v1alpha1.MachineStatus{ CurrentStatus: v1alpha1.CurrentStatus{ Phase: v1alpha1.MachineRunning, - //TimeoutActive: false, LastUpdateTime: metav1.Now(), }, - LastOperation: v1alpha1.LastOperation{ - Description: fmt.Sprintf("Machine % successfully joined the cluster", machineName), - State: v1alpha1.MachineStateSuccessful, - Type: v1alpha1.MachineOperationCreate, - LastUpdateTime: metav1.Now(), + }, + }, + node: &corev1.Node{ + ObjectMeta: metav1.ObjectMeta{ + Name: "node-1", + }, + Status: corev1.NodeStatus{ + Conditions: []corev1.NodeCondition{}, + }, + }, + }, + expect: expect{ + preserveExpiryTimeIsSet: false, + nodeCondition: nil, + retry: machineutils.LongRetry, + }, + }), + Entry("preserve annotation 'now' added on Running machine", testCase{ + setup: setup{ + machine: &v1alpha1.Machine{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: testNamespace, + Name: "m1", + Annotations: map[string]string{machineutils.PreserveMachineAnnotationKey: machineutils.PreserveMachineAnnotationValueNow}, + Labels: map[string]string{ + v1alpha1.NodeLabelKey: "node-1", }, - Conditions: []corev1.NodeCondition{ - { - Message: "kubelet is posting ready status", - Reason: "KubeletReady", - Status: "True", - Type: "Ready", - }, + }, Status: v1alpha1.MachineStatus{ + CurrentStatus: v1alpha1.CurrentStatus{ + Phase: v1alpha1.MachineRunning, + LastUpdateTime: metav1.Now(), }, - }, nil, nil, nil), + }, }, - action: action{ - machine: machineName, + node: &corev1.Node{ + ObjectMeta: metav1.ObjectMeta{ + Name: "node-1", + }, + Status: corev1.NodeStatus{ + Conditions: []corev1.NodeCondition{}, + }, }, - expect: expect{ - machine: newMachine(&v1alpha1.MachineTemplateSpec{ - ObjectMeta: *newObjectMeta(objMeta, 0), - }, &v1alpha1.MachineStatus{ - Node: "dummy-node", + }, + expect: expect{ + preserveExpiryTimeIsSet: true, + nodeCondition: &corev1.NodeCondition{ + Type: v1alpha1.NodePreserved, + Status: corev1.ConditionTrue}, + retry: machineutils.LongRetry, + }, + }), + Entry("preserve annotation 'when-failed' added on Running machine", testCase{ + setup: setup{ + machine: &v1alpha1.Machine{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: testNamespace, + Name: "m1", + Annotations: map[string]string{machineutils.PreserveMachineAnnotationKey: machineutils.PreserveMachineAnnotationValueWhenFailed}, + Labels: map[string]string{ + v1alpha1.NodeLabelKey: "node-1", + }, + }, Status: v1alpha1.MachineStatus{ CurrentStatus: v1alpha1.CurrentStatus{ - Phase: v1alpha1.MachineUnknown, + Phase: v1alpha1.MachineRunning, LastUpdateTime: metav1.Now(), }, - LastOperation: v1alpha1.LastOperation{ - Description: fmt.Sprintf( - "Node object went missing. Machine %s is unhealthy - changing MachineState to Unknown", - machineName, - ), - State: v1alpha1.MachineStateProcessing, - Type: v1alpha1.MachineOperationHealthCheck, + }, + }, + node: &corev1.Node{ + ObjectMeta: metav1.ObjectMeta{ + Name: "node-1", + }, + Status: corev1.NodeStatus{ + Conditions: []corev1.NodeCondition{}, + }, + }, + }, + expect: expect{ + preserveExpiryTimeIsSet: false, + nodeCondition: nil, + retry: machineutils.LongRetry, + }, + }), + Entry("preserve annotation 'when-failed' added on Failed machine", testCase{ + setup: setup{ + machine: &v1alpha1.Machine{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: testNamespace, + Name: "m1", + Annotations: map[string]string{machineutils.PreserveMachineAnnotationKey: machineutils.PreserveMachineAnnotationValueWhenFailed}, + Labels: map[string]string{ + v1alpha1.NodeLabelKey: "node-1", + }, + }, Status: v1alpha1.MachineStatus{ + CurrentStatus: v1alpha1.CurrentStatus{ + Phase: v1alpha1.MachineFailed, LastUpdateTime: metav1.Now(), }, + }, + }, + node: &corev1.Node{ + ObjectMeta: metav1.ObjectMeta{ + Name: "node-1", + }, + Status: corev1.NodeStatus{ Conditions: []corev1.NodeCondition{ { - Message: "kubelet is posting ready status", - Reason: "KubeletReady", - Status: "True", - Type: "Ready", + Type: v1alpha1.NodePreserved, + Status: corev1.ConditionTrue, }, }, - }, nil, nil, nil), + }, }, - }), - Entry("Machine and node both are present and kubelet ready status is updated", &data{ - setup: setup{ - machines: newMachines(1, &v1alpha1.MachineTemplateSpec{ - ObjectMeta: *newObjectMeta(objMeta, 0), - }, &v1alpha1.MachineStatus{ - Node: "machine", - CurrentStatus: v1alpha1.CurrentStatus{ - Phase: v1alpha1.MachinePending, - LastUpdateTime: metav1.Now(), + }, + expect: expect{ + preserveExpiryTimeIsSet: true, + nodeCondition: &corev1.NodeCondition{ + Type: v1alpha1.NodePreserved, + Status: corev1.ConditionTrue}, + retry: machineutils.LongRetry, + }, + }), + Entry("preserve annotation 'now' added on Healthy node ", testCase{ + setup: setup{ + machine: &v1alpha1.Machine{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: testNamespace, + Name: "m1", + Labels: map[string]string{ + v1alpha1.NodeLabelKey: "node-1", }, - LastOperation: v1alpha1.LastOperation{ - Description: "Creating machine on cloud provider", - State: v1alpha1.MachineStateProcessing, - Type: v1alpha1.MachineOperationCreate, + }, Status: v1alpha1.MachineStatus{ + CurrentStatus: v1alpha1.CurrentStatus{ + Phase: v1alpha1.MachineRunning, LastUpdateTime: metav1.Now(), }, - Conditions: []corev1.NodeCondition{ - { - Message: "kubelet is not ready", - Reason: "KubeletReady", - Status: "False", - Type: "Ready", - }, - }, - }, nil, nil, nil), - nodes: []*corev1.Node{ - { - ObjectMeta: *newObjectMeta(objMeta, 0), - Status: corev1.NodeStatus{ - Conditions: []corev1.NodeCondition{ - { - Message: "kubelet is posting ready status", - Reason: "KubeletReady", - Status: "True", - Type: "Ready", - }, - }, - }, - }, }, }, - action: action{ - machine: machineName, + node: &corev1.Node{ + ObjectMeta: metav1.ObjectMeta{ + Name: "node-1", + Annotations: map[string]string{machineutils.PreserveMachineAnnotationKey: machineutils.PreserveMachineAnnotationValueNow}, + }, + Status: corev1.NodeStatus{ + Conditions: []corev1.NodeCondition{}, + }, }, - expect: expect{ - machine: newMachine(&v1alpha1.MachineTemplateSpec{ - ObjectMeta: *newObjectMeta(objMeta, 0), - }, &v1alpha1.MachineStatus{ - Node: "machine", + }, + expect: expect{ + preserveExpiryTimeIsSet: true, + nodeCondition: &corev1.NodeCondition{ + Type: v1alpha1.NodePreserved, + Status: corev1.ConditionTrue}, + retry: machineutils.LongRetry, + }, + }), + Entry("preserve annotation 'when-failed' added on Healthy node ", testCase{ + setup: setup{ + machine: &v1alpha1.Machine{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: testNamespace, + Name: "m1", + Labels: map[string]string{ + v1alpha1.NodeLabelKey: "node-1", + }, + }, Status: v1alpha1.MachineStatus{ CurrentStatus: v1alpha1.CurrentStatus{ Phase: v1alpha1.MachineRunning, - //TimeoutActive: false, LastUpdateTime: metav1.Now(), }, - LastOperation: v1alpha1.LastOperation{ - Description: "Machine machine-0 successfully joined the cluster", - State: v1alpha1.MachineStateSuccessful, - Type: v1alpha1.MachineOperationCreate, - LastUpdateTime: metav1.Now(), + }, + }, + node: &corev1.Node{ + ObjectMeta: metav1.ObjectMeta{ + Name: "node-1", + Annotations: map[string]string{machineutils.PreserveMachineAnnotationKey: machineutils.PreserveMachineAnnotationValueWhenFailed}, + }, + Status: corev1.NodeStatus{ + Conditions: []corev1.NodeCondition{}, + }, + }, + }, + expect: expect{ + preserveExpiryTimeIsSet: false, + nodeCondition: nil, + retry: machineutils.LongRetry, + }}), + Entry("preserve annotation 'false' added on backing node of preserved machine", testCase{ + setup: setup{ + machine: &v1alpha1.Machine{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: testNamespace, + Name: "m1", + Labels: map[string]string{ + v1alpha1.NodeLabelKey: "node-1", + }, + Annotations: map[string]string{machineutils.PreserveMachineAnnotationKey: "now"}, + }, Status: v1alpha1.MachineStatus{ + CurrentStatus: v1alpha1.CurrentStatus{ + Phase: v1alpha1.MachineRunning, + LastUpdateTime: metav1.Now(), + PreserveExpiryTime: metav1.Time{Time: time.Now().Add(1 * time.Hour)}, }, + }, + }, + node: &corev1.Node{ + ObjectMeta: metav1.ObjectMeta{ + Name: "node-1", + Annotations: map[string]string{machineutils.PreserveMachineAnnotationKey: "false"}, + }, + Status: corev1.NodeStatus{ Conditions: []corev1.NodeCondition{ { - Message: "kubelet is posting ready status", - Reason: "KubeletReady", - Status: "True", - Type: "Ready", + Type: v1alpha1.NodePreserved, + Status: corev1.ConditionTrue, }, }, - }, nil, nil, nil), + }, }, - }), - Entry("Machine object does not have node-label and node exists", &data{ - setup: setup{ - machines: newMachines(1, &v1alpha1.MachineTemplateSpec{ - ObjectMeta: *newObjectMeta(objMeta, 0), - }, &v1alpha1.MachineStatus{ - Node: "node", - }, nil, nil, nil), - nodes: []*corev1.Node{ - { - ObjectMeta: metav1.ObjectMeta{ - Name: "node-0", - }, + }, + expect: expect{ + preserveExpiryTimeIsSet: false, + nodeCondition: nil, + retry: machineutils.LongRetry, + }, + }), + Entry("machine auto-preserved by MCM", testCase{ + setup: setup{ + machine: &v1alpha1.Machine{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: testNamespace, + Name: "m1", + Labels: map[string]string{ + v1alpha1.NodeLabelKey: "node-1", + }, + Annotations: map[string]string{machineutils.PreserveMachineAnnotationKey: machineutils.PreserveMachineAnnotationValuePreservedByMCM}, + }, Status: v1alpha1.MachineStatus{ + CurrentStatus: v1alpha1.CurrentStatus{ + Phase: v1alpha1.MachineFailed, + LastUpdateTime: metav1.Now(), }, }, }, - action: action{ - machine: machineName, + node: &corev1.Node{ + ObjectMeta: metav1.ObjectMeta{ + Name: "node-1", + }, + Status: corev1.NodeStatus{ + Conditions: []corev1.NodeCondition{}, + }, }, - expect: expect{ - machine: newMachine(&v1alpha1.MachineTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Name: "machine-0", + }, + expect: expect{ + preserveExpiryTimeIsSet: true, + nodeCondition: &corev1.NodeCondition{ + Type: v1alpha1.NodePreserved, + Status: corev1.ConditionTrue}, + retry: machineutils.LongRetry, + }, + }), + Entry("preservation timed out", testCase{ + setup: setup{ + machine: &v1alpha1.Machine{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: testNamespace, + Name: "m1", + Labels: map[string]string{ + v1alpha1.NodeLabelKey: "node-1", }, - }, &v1alpha1.MachineStatus{ - Node: "node", - }, nil, nil, - map[string]string{ - "node": "node-0", + Annotations: map[string]string{machineutils.PreserveMachineAnnotationKey: "now"}, + }, Status: v1alpha1.MachineStatus{ + CurrentStatus: v1alpha1.CurrentStatus{ + Phase: v1alpha1.MachineRunning, + LastUpdateTime: metav1.Now(), + PreserveExpiryTime: metav1.Time{Time: time.Now().Add(-1 * time.Hour)}, }, - ), + }, }, - }), - ) - }) - */ + node: &corev1.Node{ + ObjectMeta: metav1.ObjectMeta{ + Name: "node-1", + }, + }, + }, + expect: expect{ + preserveExpiryTimeIsSet: false, + nodeCondition: &corev1.NodeCondition{Type: v1alpha1.NodePreserved, Status: corev1.ConditionFalse}, + retry: machineutils.LongRetry, + }, + }), + Entry("invalid preserve annotation on node of unpreserved machine", testCase{ + setup: setup{ + machine: &v1alpha1.Machine{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: testNamespace, + Name: "m1", + Labels: map[string]string{ + v1alpha1.NodeLabelKey: "node-1", + }, + }, Status: v1alpha1.MachineStatus{ + CurrentStatus: v1alpha1.CurrentStatus{ + Phase: v1alpha1.MachineRunning, + LastUpdateTime: metav1.Now(), + }, + }, + }, + node: &corev1.Node{ + ObjectMeta: metav1.ObjectMeta{ + Name: "node-1", + Annotations: map[string]string{machineutils.PreserveMachineAnnotationKey: "invalidValue"}, + }, + Status: corev1.NodeStatus{ + Conditions: []corev1.NodeCondition{}, + }, + }, + }, + expect: expect{ + preserveExpiryTimeIsSet: false, + nodeCondition: nil, + retry: machineutils.LongRetry, + err: nil, + }, + }), + Entry("machine annotated with preserve=now, but has no backing node", testCase{ + setup: setup{ + machine: &v1alpha1.Machine{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: testNamespace, + Name: "m1", + Annotations: map[string]string{machineutils.PreserveMachineAnnotationKey: "now"}, + }, + }, + }, + expect: expect{ + preserveExpiryTimeIsSet: true, + nodeCondition: nil, + retry: machineutils.LongRetry, + err: nil, + }, + }), + Entry("machine with backing node, but node retrieval fails", testCase{ + setup: setup{ + machine: &v1alpha1.Machine{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: testNamespace, + Name: "m1", + Annotations: map[string]string{machineutils.PreserveMachineAnnotationKey: "now"}, + Labels: map[string]string{ + v1alpha1.NodeLabelKey: "node-1", + }, + }, + }, + }, + expect: expect{ + preserveExpiryTimeIsSet: false, + nodeCondition: nil, + retry: machineutils.ShortRetry, + err: fmt.Errorf("node %q not found", "node-1"), + }, + }), + ) + }) }) From 718b451495868268038c2de798864c25ca446a5b Mon Sep 17 00:00:00 2001 From: thiyyakat Date: Fri, 26 Dec 2025 15:51:10 +0530 Subject: [PATCH 35/43] Refactor tests to reduce redundancy in code. --- .../provider/machinecontroller/machine.go | 4 + .../machinecontroller/machine_test.go | 656 ++++++------------ 2 files changed, 200 insertions(+), 460 deletions(-) diff --git a/pkg/util/provider/machinecontroller/machine.go b/pkg/util/provider/machinecontroller/machine.go index 5ad35b52d..61db1f3e3 100644 --- a/pkg/util/provider/machinecontroller/machine.go +++ b/pkg/util/provider/machinecontroller/machine.go @@ -799,6 +799,10 @@ func (c *controller) handlePreserveAnnotationsChange(oldAnnotations, newAnnotati if !isPreserved { return true } + if machineutils.IsMachineFailed(machine) { + // If machine is already in failed state, no need to stop preservation + return true + } ctx := context.Background() err := clientretry.RetryOnConflict(nodeops.Backoff, func() error { klog.V(3).Infof("Stopping preservation for machine %q as preserve annotation changed from 'now' to 'when-failed'.", machine.Name) diff --git a/pkg/util/provider/machinecontroller/machine_test.go b/pkg/util/provider/machinecontroller/machine_test.go index a00425c7f..ddc301668 100644 --- a/pkg/util/provider/machinecontroller/machine_test.go +++ b/pkg/util/provider/machinecontroller/machine_test.go @@ -4077,10 +4077,9 @@ var _ = Describe("machine", func() { Describe("#handlePreserveAnnotationsChange", func() { type setup struct { - oldAnnotations map[string]string - newAnnotations map[string]string - machine *v1alpha1.Machine - node *corev1.Node + oldPreserveValue string + newPreserveValue string + phase v1alpha1.MachinePhase } type expect struct { @@ -4094,70 +4093,68 @@ var _ = Describe("machine", func() { stop := make(chan struct{}) defer close(stop) - var controlMachineObjects []runtime.Object + // Build machine object + machine := &v1alpha1.Machine{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: testNamespace, + Name: "m1", + Labels: map[string]string{ + v1alpha1.NodeLabelKey: "node-1", + }, + }, Status: v1alpha1.MachineStatus{ + CurrentStatus: v1alpha1.CurrentStatus{ + Phase: v1alpha1.MachineRunning, + LastUpdateTime: metav1.Now(), + }, + }, + } + if tc.setup.phase != "" { + machine.Status.CurrentStatus.Phase = tc.setup.phase + } + if tc.setup.oldPreserveValue == machineutils.PreserveMachineAnnotationValueNow || tc.setup.oldPreserveValue == machineutils.PreserveMachineAnnotationValuePreservedByMCM { + machine.Status.CurrentStatus.PreserveExpiryTime = metav1.NewTime(metav1.Now().Add(1 * time.Hour)) + } else if tc.setup.oldPreserveValue == machineutils.PreserveMachineAnnotationValueWhenFailed && machineutils.IsMachineFailed(machine) { + machine.Status.CurrentStatus.PreserveExpiryTime = metav1.NewTime(metav1.Now().Add(1 * time.Hour)) + } - controlMachineObjects = append(controlMachineObjects, tc.setup.machine) - var targetCoreObjects []runtime.Object - if tc.setup.node != nil { - targetCoreObjects = append(targetCoreObjects, tc.setup.node) + controlMachineObjects := []runtime.Object{machine} + + // Build node object + node := &corev1.Node{ + ObjectMeta: metav1.ObjectMeta{ + Name: "node-1", + }, } + targetCoreObjects := []runtime.Object{node} c, trackers := createController(stop, testNamespace, controlMachineObjects, nil, targetCoreObjects, nil, false) defer trackers.Stop() waitForCacheSync(stop, c) - result := c.handlePreserveAnnotationsChange(tc.setup.oldAnnotations, tc.setup.newAnnotations, tc.setup.machine) + result := c.handlePreserveAnnotationsChange(map[string]string{machineutils.PreserveMachineAnnotationKey: tc.setup.oldPreserveValue}, map[string]string{machineutils.PreserveMachineAnnotationKey: tc.setup.newPreserveValue}, machine) Expect(result).To(Equal(tc.expect.change)) - if tc.setup.newAnnotations != nil && tc.setup.oldAnnotations != nil && tc.setup.newAnnotations[machineutils.PreserveMachineAnnotationKey] == machineutils.PreserveMachineAnnotationValueWhenFailed && tc.setup.oldAnnotations[machineutils.PreserveMachineAnnotationKey] == machineutils.PreserveMachineAnnotationValueNow { - updatedMachine, err := c.controlMachineClient.Machines(testNamespace).Get(context.TODO(), tc.setup.machine.Name, metav1.GetOptions{}) + if tc.setup.newPreserveValue == machineutils.PreserveMachineAnnotationValueWhenFailed && tc.setup.oldPreserveValue == machineutils.PreserveMachineAnnotationValueNow { + updatedMachine, err := c.controlMachineClient.Machines(testNamespace).Get(context.TODO(), machine.Name, metav1.GetOptions{}) Expect(err).ToNot(HaveOccurred()) - Expect(updatedMachine.Status.CurrentStatus.PreserveExpiryTime.IsZero()).To(BeTrue()) // machine preservation should have been stopped + if tc.setup.phase == v1alpha1.MachineFailed { + Expect(updatedMachine.Status.CurrentStatus.PreserveExpiryTime.IsZero()).To(BeFalse()) // machine preservation should be active + } else { + Expect(updatedMachine.Status.CurrentStatus.PreserveExpiryTime.IsZero()).To(BeTrue()) // machine preservation should have been stopped + } } }, Entry("no change in preserve annotations", testCase{ setup: setup{ - oldAnnotations: map[string]string{machineutils.PreserveMachineAnnotationKey: "someValue"}, - newAnnotations: map[string]string{machineutils.PreserveMachineAnnotationKey: "someValue"}, - machine: &v1alpha1.Machine{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: testNamespace, - Name: "m1", - Annotations: map[string]string{machineutils.PreserveMachineAnnotationKey: "someValue"}, - Labels: map[string]string{ - v1alpha1.NodeLabelKey: "node-1", - }, - }, Status: v1alpha1.MachineStatus{ - CurrentStatus: v1alpha1.CurrentStatus{ - Phase: v1alpha1.MachineRunning, - LastUpdateTime: metav1.Now(), - PreserveExpiryTime: metav1.Time{Time: time.Now().Add(1 * time.Hour)}, - }, - }, - }, + oldPreserveValue: "someValue", + newPreserveValue: "someValue", }, expect: expect{ change: false, }, }), - Entry("preserve annotation added on machine", testCase{ + Entry("preserve annotation newly added on machine", testCase{ setup: setup{ - oldAnnotations: map[string]string{machineutils.PreserveMachineAnnotationKey: ""}, - newAnnotations: map[string]string{machineutils.PreserveMachineAnnotationKey: "newValue"}, - machine: &v1alpha1.Machine{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: testNamespace, - Name: "m1", - Annotations: map[string]string{machineutils.PreserveMachineAnnotationKey: "newValue"}, - Labels: map[string]string{ - v1alpha1.NodeLabelKey: "node-1", - }, - }, Status: v1alpha1.MachineStatus{ - CurrentStatus: v1alpha1.CurrentStatus{ - Phase: v1alpha1.MachineRunning, - LastUpdateTime: metav1.Now(), - }, - }, - }, + newPreserveValue: "newValue", }, expect: expect{ change: true, @@ -4165,80 +4162,41 @@ var _ = Describe("machine", func() { }), Entry("preserve annotation removed", testCase{ setup: setup{ - oldAnnotations: map[string]string{machineutils.PreserveMachineAnnotationKey: "someValue"}, - newAnnotations: map[string]string{"someOtherKey": "someValue"}, - machine: &v1alpha1.Machine{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: testNamespace, - Name: "m1", - Annotations: map[string]string{"someOtherKey": "someValue"}, - Labels: map[string]string{ - v1alpha1.NodeLabelKey: "node-1", - }, - }}}, + oldPreserveValue: "someValue", + newPreserveValue: "", + }, expect: expect{ change: true, }, }), Entry("preserve annotation value changed", testCase{ setup: setup{ - oldAnnotations: map[string]string{machineutils.PreserveMachineAnnotationKey: "oldValue"}, - newAnnotations: map[string]string{machineutils.PreserveMachineAnnotationKey: "newValue"}, - machine: &v1alpha1.Machine{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: testNamespace, - Name: "m1", - Annotations: map[string]string{machineutils.PreserveMachineAnnotationKey: "newValue"}, - Labels: map[string]string{ - v1alpha1.NodeLabelKey: "node-1", - }, - }}}, + oldPreserveValue: "oldValue", + newPreserveValue: "newValue"}, expect: expect{ change: true, }, }), Entry("both annotations are nil", testCase{ - setup: setup{ - oldAnnotations: nil, - newAnnotations: nil, - machine: &v1alpha1.Machine{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: testNamespace, - Name: "m1", - Labels: map[string]string{ - v1alpha1.NodeLabelKey: "node-1", - }, - }}}, + setup: setup{}, expect: expect{ change: false, }, }), - Entry("preserve annotation changed from now to when-failed", testCase{ + Entry("preserve annotation changed from now to when-failed on Running machine", testCase{ setup: setup{ - oldAnnotations: map[string]string{machineutils.PreserveMachineAnnotationKey: machineutils.PreserveMachineAnnotationValueNow}, - newAnnotations: map[string]string{machineutils.PreserveMachineAnnotationKey: machineutils.PreserveMachineAnnotationValueWhenFailed}, - machine: &v1alpha1.Machine{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: testNamespace, - Name: "m1", - Annotations: map[string]string{machineutils.PreserveMachineAnnotationKey: machineutils.PreserveMachineAnnotationValueWhenFailed}, - Labels: map[string]string{ - v1alpha1.NodeLabelKey: "node-1", - }, - }, - Status: v1alpha1.MachineStatus{ - CurrentStatus: v1alpha1.CurrentStatus{ - Phase: v1alpha1.MachineRunning, - LastUpdateTime: metav1.Now(), - PreserveExpiryTime: metav1.Time{Time: time.Now().Add(1 * time.Hour)}, - }, - }, - }, - node: &corev1.Node{ - ObjectMeta: metav1.ObjectMeta{ - Name: "node-1", - }, - }, + oldPreserveValue: machineutils.PreserveMachineAnnotationValueNow, + newPreserveValue: machineutils.PreserveMachineAnnotationValueWhenFailed, + }, + expect: expect{ + change: true, + }, + }), + Entry("preserve annotation changed from now to when-failed on Failed machine", testCase{ + setup: setup{ + oldPreserveValue: machineutils.PreserveMachineAnnotationValueNow, + newPreserveValue: machineutils.PreserveMachineAnnotationValueWhenFailed, + phase: v1alpha1.MachineFailed, }, expect: expect{ change: true, @@ -4249,8 +4207,9 @@ var _ = Describe("machine", func() { Describe("#computeEffectivePreserveAnnotationValue", func() { type setup struct { - machine *v1alpha1.Machine - node *corev1.Node + machinePreserveAnnotation string + nodePreserveAnnotation string + nodeName string } type expect struct { preserveValue string @@ -4272,16 +4231,40 @@ var _ = Describe("machine", func() { var targetCoreObjects []runtime.Object // Build machine - controlMachineObjects = append(controlMachineObjects, tc.setup.machine) - if tc.setup.node != nil { - targetCoreObjects = append(targetCoreObjects, tc.setup.node) + machine := &v1alpha1.Machine{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: testNamespace, + Name: "m1", + Labels: map[string]string{ + v1alpha1.NodeLabelKey: tc.setup.nodeName, + }, + Annotations: map[string]string{}, + }, + } + if tc.setup.machinePreserveAnnotation != "" { + machine.Annotations[machineutils.PreserveMachineAnnotationKey] = tc.setup.machinePreserveAnnotation + } + + controlMachineObjects = append(controlMachineObjects, machine) + // Build node + if tc.setup.nodeName != "" && tc.setup.nodeName != "invalid" { + node := &corev1.Node{ + ObjectMeta: metav1.ObjectMeta{ + Name: tc.setup.nodeName, + Annotations: map[string]string{}, + }, + } + if tc.setup.nodePreserveAnnotation != "" { + node.Annotations[machineutils.PreserveMachineAnnotationKey] = tc.setup.nodePreserveAnnotation + } + targetCoreObjects = append(targetCoreObjects, node) } c, trackers := createController(stop, testNamespace, controlMachineObjects, nil, targetCoreObjects, nil, false) defer trackers.Stop() waitForCacheSync(stop, c) - value, exists, err := c.computeEffectivePreserveAnnotationValue(tc.setup.machine) + value, exists, err := c.computeEffectivePreserveAnnotationValue(machine) if tc.expect.err != nil { Expect(err).To(HaveOccurred()) @@ -4294,19 +4277,7 @@ var _ = Describe("machine", func() { }, Entry("neither machine nor node has preserve annotation", testCase{ setup: setup{ - machine: &v1alpha1.Machine{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: testNamespace, - Name: "m1", - Labels: map[string]string{ - v1alpha1.NodeLabelKey: "node-1", - }, - }}, - node: &corev1.Node{ - ObjectMeta: metav1.ObjectMeta{ - Name: "node-1", - }, - }, + nodeName: "node-1", }, expect: expect{ preserveValue: "", @@ -4316,20 +4287,8 @@ var _ = Describe("machine", func() { }), Entry("only machine has preserve annotation", testCase{ setup: setup{ - machine: &v1alpha1.Machine{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: testNamespace, - Name: "m1", - Annotations: map[string]string{machineutils.PreserveMachineAnnotationKey: "machineValue"}, - Labels: map[string]string{ - v1alpha1.NodeLabelKey: "node-1", - }, - }}, - node: &corev1.Node{ - ObjectMeta: metav1.ObjectMeta{ - Name: "node-1", - }, - }, + machinePreserveAnnotation: "machineValue", + nodeName: "node-1", }, expect: expect{ preserveValue: "machineValue", @@ -4339,20 +4298,8 @@ var _ = Describe("machine", func() { }), Entry("only node has preserve annotation", testCase{ setup: setup{ - machine: &v1alpha1.Machine{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: testNamespace, - Name: "m1", - Labels: map[string]string{ - v1alpha1.NodeLabelKey: "node-1", - }, - }}, - node: &corev1.Node{ - ObjectMeta: metav1.ObjectMeta{ - Name: "node-1", - Annotations: map[string]string{machineutils.PreserveMachineAnnotationKey: "nodeValue"}, - }, - }, + nodePreserveAnnotation: "nodeValue", + nodeName: "node-1", }, expect: expect{ preserveValue: "nodeValue", @@ -4362,21 +4309,9 @@ var _ = Describe("machine", func() { }), Entry("both machine and node have preserve annotation - node takes precedence", testCase{ setup: setup{ - machine: &v1alpha1.Machine{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: testNamespace, - Name: "m1", - Annotations: map[string]string{machineutils.PreserveMachineAnnotationKey: "machineValue"}, - Labels: map[string]string{ - v1alpha1.NodeLabelKey: "node-1", - }, - }}, - node: &corev1.Node{ - ObjectMeta: metav1.ObjectMeta{ - Name: "node-1", - Annotations: map[string]string{machineutils.PreserveMachineAnnotationKey: "nodeValue"}, - }, - }, + machinePreserveAnnotation: "machineValue", + nodePreserveAnnotation: "nodeValue", + nodeName: "node-1", }, expect: expect{ preserveValue: "nodeValue", @@ -4386,32 +4321,18 @@ var _ = Describe("machine", func() { }), Entry("machine has node label but node object is not found", testCase{ setup: setup{ - machine: &v1alpha1.Machine{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: testNamespace, - Name: "m1", - Annotations: map[string]string{machineutils.PreserveMachineAnnotationKey: "machineValue"}, - Labels: map[string]string{ - v1alpha1.NodeLabelKey: "node-1", - }, - }}, - node: nil, + machinePreserveAnnotation: "machineValue", + nodeName: "invalid", }, expect: expect{ preserveValue: "", exists: false, - err: fmt.Errorf("node %q not found", "node-1"), + err: fmt.Errorf("node %q not found", "invalid"), }, }), Entry("machine does not have node label", testCase{ setup: setup{ - machine: &v1alpha1.Machine{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: testNamespace, - Name: "m1", - Annotations: map[string]string{machineutils.PreserveMachineAnnotationKey: "machineValue"}, - Labels: map[string]string{}, - }}, + machinePreserveAnnotation: "machineValue", }, expect: expect{ preserveValue: "machineValue", @@ -4424,8 +4345,11 @@ var _ = Describe("machine", func() { Describe("#manageMachinePreservation", func() { type setup struct { - machine *v1alpha1.Machine - node *corev1.Node + machineAnnotationValue string + nodeAnnotationValue string + nodeName string + machinePhase v1alpha1.MachinePhase + preserveExpiryTime metav1.Time } type expect struct { retry machineutils.RetryPeriod @@ -4448,16 +4372,47 @@ var _ = Describe("machine", func() { var targetCoreObjects []runtime.Object // Build machine - controlMachineObjects = append(controlMachineObjects, tc.setup.machine) - if tc.setup.node != nil { - targetCoreObjects = append(targetCoreObjects, tc.setup.node) + machine := &v1alpha1.Machine{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: testNamespace, + Name: "m1", + Labels: map[string]string{ + v1alpha1.NodeLabelKey: tc.setup.nodeName, + }, + Annotations: map[string]string{}, + }, Status: v1alpha1.MachineStatus{ + CurrentStatus: v1alpha1.CurrentStatus{ + Phase: tc.setup.machinePhase, + LastUpdateTime: metav1.Now(), + PreserveExpiryTime: tc.setup.preserveExpiryTime, + }, + }, + } + if tc.setup.machineAnnotationValue != "" { + machine.Annotations[machineutils.PreserveMachineAnnotationKey] = tc.setup.machineAnnotationValue + } + controlMachineObjects = append(controlMachineObjects, machine) + if tc.setup.nodeName != "" && tc.setup.nodeName != "invalid" { + node := &corev1.Node{ + ObjectMeta: metav1.ObjectMeta{ + Name: tc.setup.nodeName, + Annotations: map[string]string{}, + }, + Status: corev1.NodeStatus{ + Conditions: []corev1.NodeCondition{}, + }, + } + if tc.setup.nodeAnnotationValue != "" { + node.Annotations[machineutils.PreserveMachineAnnotationKey] = tc.setup.nodeAnnotationValue + } + targetCoreObjects = append(targetCoreObjects, node) } - c, trackers := createController(stop, testNamespace, controlMachineObjects, nil, targetCoreObjects, nil, false) defer trackers.Stop() - waitForCacheSync(stop, c) - retry, err := c.manageMachinePreservation(context.TODO(), tc.setup.machine) + + retry, err := c.manageMachinePreservation(context.TODO(), machine) + Expect(retry).To(Equal(tc.expect.retry)) if tc.expect.err != nil { Expect(err).To(HaveOccurred()) @@ -4465,16 +4420,15 @@ var _ = Describe("machine", func() { return } Expect(err).ToNot(HaveOccurred()) - updatedMachine, err := c.controlMachineClient.Machines(tc.setup.machine.Namespace).Get(context.TODO(), tc.setup.machine.Name, metav1.GetOptions{}) + updatedMachine, err := c.controlMachineClient.Machines(testNamespace).Get(context.TODO(), machine.Name, metav1.GetOptions{}) Expect(err).ToNot(HaveOccurred()) - if tc.expect.preserveExpiryTimeIsSet { Expect(updatedMachine.Status.CurrentStatus.PreserveExpiryTime.IsZero()).To(BeFalse()) } else { Expect(updatedMachine.Status.CurrentStatus.PreserveExpiryTime.IsZero()).To(BeTrue()) } - if tc.setup.machine.Labels[v1alpha1.NodeLabelKey] != "" { - updatedNode, err := c.targetCoreClient.CoreV1().Nodes().Get(context.TODO(), tc.setup.machine.Labels[v1alpha1.NodeLabelKey], metav1.GetOptions{}) + if tc.setup.nodeName != "" { + updatedNode, err := c.targetCoreClient.CoreV1().Nodes().Get(context.TODO(), tc.setup.nodeName, metav1.GetOptions{}) Expect(err).ToNot(HaveOccurred()) found := false if tc.expect.nodeCondition != nil { @@ -4486,40 +4440,16 @@ var _ = Describe("machine", func() { } } } - if tc.expect.nodeCondition != nil { Expect(found).To(BeTrue()) } else { Expect(found).To(BeFalse()) } - } - }, Entry("no preserve annotation on machine and node", testCase{ setup: setup{ - machine: &v1alpha1.Machine{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: testNamespace, - Name: "m1", - Labels: map[string]string{ - v1alpha1.NodeLabelKey: "node-1", - }, - }, Status: v1alpha1.MachineStatus{ - CurrentStatus: v1alpha1.CurrentStatus{ - Phase: v1alpha1.MachineRunning, - LastUpdateTime: metav1.Now(), - }, - }, - }, - node: &corev1.Node{ - ObjectMeta: metav1.ObjectMeta{ - Name: "node-1", - }, - Status: corev1.NodeStatus{ - Conditions: []corev1.NodeCondition{}, - }, - }, + nodeName: "node-1", }, expect: expect{ preserveExpiryTimeIsSet: false, @@ -4529,29 +4459,9 @@ var _ = Describe("machine", func() { }), Entry("preserve annotation 'now' added on Running machine", testCase{ setup: setup{ - machine: &v1alpha1.Machine{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: testNamespace, - Name: "m1", - Annotations: map[string]string{machineutils.PreserveMachineAnnotationKey: machineutils.PreserveMachineAnnotationValueNow}, - Labels: map[string]string{ - v1alpha1.NodeLabelKey: "node-1", - }, - }, Status: v1alpha1.MachineStatus{ - CurrentStatus: v1alpha1.CurrentStatus{ - Phase: v1alpha1.MachineRunning, - LastUpdateTime: metav1.Now(), - }, - }, - }, - node: &corev1.Node{ - ObjectMeta: metav1.ObjectMeta{ - Name: "node-1", - }, - Status: corev1.NodeStatus{ - Conditions: []corev1.NodeCondition{}, - }, - }, + machineAnnotationValue: machineutils.PreserveMachineAnnotationValueNow, + nodeName: "node-1", + machinePhase: v1alpha1.MachineRunning, }, expect: expect{ preserveExpiryTimeIsSet: true, @@ -4563,29 +4473,9 @@ var _ = Describe("machine", func() { }), Entry("preserve annotation 'when-failed' added on Running machine", testCase{ setup: setup{ - machine: &v1alpha1.Machine{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: testNamespace, - Name: "m1", - Annotations: map[string]string{machineutils.PreserveMachineAnnotationKey: machineutils.PreserveMachineAnnotationValueWhenFailed}, - Labels: map[string]string{ - v1alpha1.NodeLabelKey: "node-1", - }, - }, Status: v1alpha1.MachineStatus{ - CurrentStatus: v1alpha1.CurrentStatus{ - Phase: v1alpha1.MachineRunning, - LastUpdateTime: metav1.Now(), - }, - }, - }, - node: &corev1.Node{ - ObjectMeta: metav1.ObjectMeta{ - Name: "node-1", - }, - Status: corev1.NodeStatus{ - Conditions: []corev1.NodeCondition{}, - }, - }, + machineAnnotationValue: machineutils.PreserveMachineAnnotationValueWhenFailed, + nodeName: "node-1", + machinePhase: v1alpha1.MachineRunning, }, expect: expect{ preserveExpiryTimeIsSet: false, @@ -4593,36 +4483,11 @@ var _ = Describe("machine", func() { retry: machineutils.LongRetry, }, }), - Entry("preserve annotation 'when-failed' added on Failed machine", testCase{ + Entry("Failed machine annotated with when-failed", testCase{ setup: setup{ - machine: &v1alpha1.Machine{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: testNamespace, - Name: "m1", - Annotations: map[string]string{machineutils.PreserveMachineAnnotationKey: machineutils.PreserveMachineAnnotationValueWhenFailed}, - Labels: map[string]string{ - v1alpha1.NodeLabelKey: "node-1", - }, - }, Status: v1alpha1.MachineStatus{ - CurrentStatus: v1alpha1.CurrentStatus{ - Phase: v1alpha1.MachineFailed, - LastUpdateTime: metav1.Now(), - }, - }, - }, - node: &corev1.Node{ - ObjectMeta: metav1.ObjectMeta{ - Name: "node-1", - }, - Status: corev1.NodeStatus{ - Conditions: []corev1.NodeCondition{ - { - Type: v1alpha1.NodePreserved, - Status: corev1.ConditionTrue, - }, - }, - }, - }, + machineAnnotationValue: machineutils.PreserveMachineAnnotationValueWhenFailed, + nodeName: "node-1", + machinePhase: v1alpha1.MachineFailed, }, expect: expect{ preserveExpiryTimeIsSet: true, @@ -4634,29 +4499,9 @@ var _ = Describe("machine", func() { }), Entry("preserve annotation 'now' added on Healthy node ", testCase{ setup: setup{ - machine: &v1alpha1.Machine{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: testNamespace, - Name: "m1", - Labels: map[string]string{ - v1alpha1.NodeLabelKey: "node-1", - }, - }, Status: v1alpha1.MachineStatus{ - CurrentStatus: v1alpha1.CurrentStatus{ - Phase: v1alpha1.MachineRunning, - LastUpdateTime: metav1.Now(), - }, - }, - }, - node: &corev1.Node{ - ObjectMeta: metav1.ObjectMeta{ - Name: "node-1", - Annotations: map[string]string{machineutils.PreserveMachineAnnotationKey: machineutils.PreserveMachineAnnotationValueNow}, - }, - Status: corev1.NodeStatus{ - Conditions: []corev1.NodeCondition{}, - }, - }, + nodeAnnotationValue: machineutils.PreserveMachineAnnotationValueNow, + nodeName: "node-1", + machinePhase: v1alpha1.MachineRunning, }, expect: expect{ preserveExpiryTimeIsSet: true, @@ -4668,29 +4513,9 @@ var _ = Describe("machine", func() { }), Entry("preserve annotation 'when-failed' added on Healthy node ", testCase{ setup: setup{ - machine: &v1alpha1.Machine{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: testNamespace, - Name: "m1", - Labels: map[string]string{ - v1alpha1.NodeLabelKey: "node-1", - }, - }, Status: v1alpha1.MachineStatus{ - CurrentStatus: v1alpha1.CurrentStatus{ - Phase: v1alpha1.MachineRunning, - LastUpdateTime: metav1.Now(), - }, - }, - }, - node: &corev1.Node{ - ObjectMeta: metav1.ObjectMeta{ - Name: "node-1", - Annotations: map[string]string{machineutils.PreserveMachineAnnotationKey: machineutils.PreserveMachineAnnotationValueWhenFailed}, - }, - Status: corev1.NodeStatus{ - Conditions: []corev1.NodeCondition{}, - }, - }, + nodeAnnotationValue: machineutils.PreserveMachineAnnotationValueWhenFailed, + nodeName: "node-1", + machinePhase: v1alpha1.MachineRunning, }, expect: expect{ preserveExpiryTimeIsSet: false, @@ -4699,36 +4524,10 @@ var _ = Describe("machine", func() { }}), Entry("preserve annotation 'false' added on backing node of preserved machine", testCase{ setup: setup{ - machine: &v1alpha1.Machine{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: testNamespace, - Name: "m1", - Labels: map[string]string{ - v1alpha1.NodeLabelKey: "node-1", - }, - Annotations: map[string]string{machineutils.PreserveMachineAnnotationKey: "now"}, - }, Status: v1alpha1.MachineStatus{ - CurrentStatus: v1alpha1.CurrentStatus{ - Phase: v1alpha1.MachineRunning, - LastUpdateTime: metav1.Now(), - PreserveExpiryTime: metav1.Time{Time: time.Now().Add(1 * time.Hour)}, - }, - }, - }, - node: &corev1.Node{ - ObjectMeta: metav1.ObjectMeta{ - Name: "node-1", - Annotations: map[string]string{machineutils.PreserveMachineAnnotationKey: "false"}, - }, - Status: corev1.NodeStatus{ - Conditions: []corev1.NodeCondition{ - { - Type: v1alpha1.NodePreserved, - Status: corev1.ConditionTrue, - }, - }, - }, - }, + nodeAnnotationValue: "false", + nodeName: "node-1", + machinePhase: v1alpha1.MachineRunning, + preserveExpiryTime: metav1.NewTime(metav1.Now().Add(1 * time.Hour)), }, expect: expect{ preserveExpiryTimeIsSet: false, @@ -4738,29 +4537,10 @@ var _ = Describe("machine", func() { }), Entry("machine auto-preserved by MCM", testCase{ setup: setup{ - machine: &v1alpha1.Machine{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: testNamespace, - Name: "m1", - Labels: map[string]string{ - v1alpha1.NodeLabelKey: "node-1", - }, - Annotations: map[string]string{machineutils.PreserveMachineAnnotationKey: machineutils.PreserveMachineAnnotationValuePreservedByMCM}, - }, Status: v1alpha1.MachineStatus{ - CurrentStatus: v1alpha1.CurrentStatus{ - Phase: v1alpha1.MachineFailed, - LastUpdateTime: metav1.Now(), - }, - }, - }, - node: &corev1.Node{ - ObjectMeta: metav1.ObjectMeta{ - Name: "node-1", - }, - Status: corev1.NodeStatus{ - Conditions: []corev1.NodeCondition{}, - }, - }, + machineAnnotationValue: machineutils.PreserveMachineAnnotationValuePreservedByMCM, + nodeAnnotationValue: "", + nodeName: "node-1", + machinePhase: v1alpha1.MachineRunning, }, expect: expect{ preserveExpiryTimeIsSet: true, @@ -4772,27 +4552,11 @@ var _ = Describe("machine", func() { }), Entry("preservation timed out", testCase{ setup: setup{ - machine: &v1alpha1.Machine{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: testNamespace, - Name: "m1", - Labels: map[string]string{ - v1alpha1.NodeLabelKey: "node-1", - }, - Annotations: map[string]string{machineutils.PreserveMachineAnnotationKey: "now"}, - }, Status: v1alpha1.MachineStatus{ - CurrentStatus: v1alpha1.CurrentStatus{ - Phase: v1alpha1.MachineRunning, - LastUpdateTime: metav1.Now(), - PreserveExpiryTime: metav1.Time{Time: time.Now().Add(-1 * time.Hour)}, - }, - }, - }, - node: &corev1.Node{ - ObjectMeta: metav1.ObjectMeta{ - Name: "node-1", - }, - }, + machineAnnotationValue: machineutils.PreserveMachineAnnotationValueNow, + nodeAnnotationValue: machineutils.PreserveMachineAnnotationValueNow, + nodeName: "node-1", + machinePhase: v1alpha1.MachineRunning, + preserveExpiryTime: metav1.NewTime(metav1.Now().Add(-1 * time.Minute)), }, expect: expect{ preserveExpiryTimeIsSet: false, @@ -4802,29 +4566,10 @@ var _ = Describe("machine", func() { }), Entry("invalid preserve annotation on node of unpreserved machine", testCase{ setup: setup{ - machine: &v1alpha1.Machine{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: testNamespace, - Name: "m1", - Labels: map[string]string{ - v1alpha1.NodeLabelKey: "node-1", - }, - }, Status: v1alpha1.MachineStatus{ - CurrentStatus: v1alpha1.CurrentStatus{ - Phase: v1alpha1.MachineRunning, - LastUpdateTime: metav1.Now(), - }, - }, - }, - node: &corev1.Node{ - ObjectMeta: metav1.ObjectMeta{ - Name: "node-1", - Annotations: map[string]string{machineutils.PreserveMachineAnnotationKey: "invalidValue"}, - }, - Status: corev1.NodeStatus{ - Conditions: []corev1.NodeCondition{}, - }, - }, + machineAnnotationValue: "", + nodeAnnotationValue: "invalidValue", + nodeName: "node-1", + machinePhase: v1alpha1.MachineRunning, }, expect: expect{ preserveExpiryTimeIsSet: false, @@ -4835,13 +4580,10 @@ var _ = Describe("machine", func() { }), Entry("machine annotated with preserve=now, but has no backing node", testCase{ setup: setup{ - machine: &v1alpha1.Machine{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: testNamespace, - Name: "m1", - Annotations: map[string]string{machineutils.PreserveMachineAnnotationKey: "now"}, - }, - }, + machineAnnotationValue: machineutils.PreserveMachineAnnotationValueNow, + nodeAnnotationValue: "", + nodeName: "", + machinePhase: v1alpha1.MachineUnknown, }, expect: expect{ preserveExpiryTimeIsSet: true, @@ -4852,22 +4594,16 @@ var _ = Describe("machine", func() { }), Entry("machine with backing node, but node retrieval fails", testCase{ setup: setup{ - machine: &v1alpha1.Machine{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: testNamespace, - Name: "m1", - Annotations: map[string]string{machineutils.PreserveMachineAnnotationKey: "now"}, - Labels: map[string]string{ - v1alpha1.NodeLabelKey: "node-1", - }, - }, - }, + machineAnnotationValue: machineutils.PreserveMachineAnnotationValueNow, + nodeAnnotationValue: "", + nodeName: "invalid", + machinePhase: v1alpha1.MachineUnknown, }, expect: expect{ preserveExpiryTimeIsSet: false, nodeCondition: nil, retry: machineutils.ShortRetry, - err: fmt.Errorf("node %q not found", "node-1"), + err: fmt.Errorf("node %q not found", "invalid"), }, }), ) From 8145d8ba62e8e99e5e9348295997b3499b8b5072 Mon Sep 17 00:00:00 2001 From: thiyyakat Date: Mon, 29 Dec 2025 16:47:30 +0530 Subject: [PATCH 36/43] Add tests for preservation logic in machine_util.go --- .../machinecontroller/machine_test.go | 77 --- .../machinecontroller/machine_util.go | 39 +- .../machinecontroller/machine_util_test.go | 514 ++++++++++++++++++ 3 files changed, 529 insertions(+), 101 deletions(-) diff --git a/pkg/util/provider/machinecontroller/machine_test.go b/pkg/util/provider/machinecontroller/machine_test.go index ddc301668..10eaad4de 100644 --- a/pkg/util/provider/machinecontroller/machine_test.go +++ b/pkg/util/provider/machinecontroller/machine_test.go @@ -196,82 +196,6 @@ var _ = Describe("machine", func() { ) }) - /* - Describe("##updateMachineConditions", func() { - Describe("Update conditions of a non-existing machine", func() { - It("should return error", func() { - stop := make(chan struct{}) - defer close(stop) - - objects := []runtime.Object{} - c, trackers := createController(stop, testNamespace, objects, nil, nil) - defer trackers.Stop() - - testMachine := &v1alpha1.Machine{ - ObjectMeta: metav1.ObjectMeta{ - Name: "testmachine", - Namespace: testNamespace, - }, - Status: v1alpha1.MachineStatus{ - CurrentStatus: v1alpha1.CurrentStatus{ - Phase: v1alpha1.MachineTerminating, - }, - }, - } - conditions := []corev1.NodeCondition{} - var _, err = c.updateMachineConditions(testMachine, conditions) - Expect(err).Should(Not(BeNil())) - }) - }) - DescribeTable("Update conditions of an existing machine", - func(phase v1alpha1.MachinePhase, conditions []corev1.NodeCondition, expectedPhase v1alpha1.MachinePhase) { - stop := make(chan struct{}) - defer close(stop) - - testMachine := &v1alpha1.Machine{ - ObjectMeta: metav1.ObjectMeta{ - Name: "testmachine", - Namespace: testNamespace, - }, - Status: v1alpha1.MachineStatus{ - CurrentStatus: v1alpha1.CurrentStatus{ - Phase: phase, - }, - }, - } - objects := []runtime.Object{} - objects = append(objects, testMachine) - - c, trackers := createController(stop, testNamespace, objects, nil, nil) - defer trackers.Stop() - - var updatedMachine, err = c.updateMachineConditions(testMachine, conditions) - Expect(updatedMachine.Status.Conditions).Should(BeEquivalentTo(conditions)) - Expect(updatedMachine.Status.CurrentStatus.Phase).Should(BeIdenticalTo(expectedPhase)) - Expect(err).Should(BeNil()) - }, - Entry("healthy status but machine terminating", v1alpha1.MachineTerminating, []corev1.NodeCondition{ - { - Type: corev1.NodeReady, - Status: corev1.ConditionTrue, - }, - }, v1alpha1.MachineTerminating), - Entry("unhealthy status but machine running", v1alpha1.MachineRunning, []corev1.NodeCondition{ - { - Type: corev1.NodeReady, - Status: corev1.ConditionFalse, - }, - }, v1alpha1.MachineUnknown), - Entry("healthy status but machine not running", v1alpha1.MachineAvailable, []corev1.NodeCondition{ - { - Type: corev1.NodeReady, - Status: corev1.ConditionTrue, - }, - }, v1alpha1.MachineRunning), - ) - }) - */ - Describe("#ValidateMachine", func() { type data struct { action machineapi.Machine @@ -4410,7 +4334,6 @@ var _ = Describe("machine", func() { c, trackers := createController(stop, testNamespace, controlMachineObjects, nil, targetCoreObjects, nil, false) defer trackers.Stop() waitForCacheSync(stop, c) - retry, err := c.manageMachinePreservation(context.TODO(), machine) Expect(retry).To(Equal(tc.expect.retry)) diff --git a/pkg/util/provider/machinecontroller/machine_util.go b/pkg/util/provider/machinecontroller/machine_util.go index da6c557c6..ceea0339a 100644 --- a/pkg/util/provider/machinecontroller/machine_util.go +++ b/pkg/util/provider/machinecontroller/machine_util.go @@ -2371,20 +2371,19 @@ Utility Functions for Machine Preservation func (c *controller) preserveMachine(ctx context.Context, machine *v1alpha1.Machine, preserveValue string) error { nodeName := machine.Labels[v1alpha1.NodeLabelKey] isExpirySet := machineutils.IsPreserveExpiryTimeSet(machine) - - // If machine has no backing node - if nodeName == "" { - if isExpirySet { - return nil - } + updatedMachine := machine.DeepCopy() + if !isExpirySet { + klog.V(4).Infof("Starting preservation flow for machine %q.", machine.Name) // Step 1: Add preserveExpiryTime to machine status - updatedMachine, err := c.setPreserveExpiryTimeOnMachine(ctx, machine) + updatedMachine, err := c.setPreserveExpiryTimeOnMachine(ctx, updatedMachine) if err != nil { return err } - klog.V(2).Infof("Machine %s preserved successfully till %v.", machine.Name, updatedMachine.Status.CurrentStatus.PreserveExpiryTime) - return nil - + if nodeName == "" { + // if machine has no backing node, preservation is complete + klog.V(2).Infof("Machine %s preserved successfully till %v.", machine.Name, updatedMachine.Status.CurrentStatus.PreserveExpiryTime) + return nil + } } // Machine has a backing node node, err := c.nodeLister.Get(nodeName) @@ -2394,18 +2393,11 @@ func (c *controller) preserveMachine(ctx context.Context, machine *v1alpha1.Mach } existingNodePreservedCondition := nodeops.GetCondition(node, v1alpha1.NodePreserved) // check if preservation is already complete - if isExpirySet && c.isPreservedNodeConditionStatusTrue(existingNodePreservedCondition) { + if c.isPreservedNodeConditionStatusTrue(existingNodePreservedCondition) { return nil } // Preservation incomplete - either the flow is just starting or in progress - updatedMachine := machine - if !isExpirySet { - // Step 1: Add preserveExpiryTime to machine status - updatedMachine, err = c.setPreserveExpiryTimeOnMachine(ctx, machine) - if err != nil { - return err - } - } + // Step 2: Add annotations to prevent scale down of node by CA _, err = c.addCAScaleDownDisabledAnnotationOnNode(ctx, node) if err != nil { @@ -2413,7 +2405,7 @@ func (c *controller) preserveMachine(ctx context.Context, machine *v1alpha1.Mach } drainSuccessful := false - if c.shouldNodeBeDrained(machine, existingNodePreservedCondition) { + if c.shouldNodeBeDrained(updatedMachine, existingNodePreservedCondition) { // Step 3: If machine is in Failed Phase, drain the backing node err = c.drainPreservedNode(ctx, machine) if err != nil { @@ -2442,7 +2434,7 @@ func (c *controller) preserveMachine(ctx context.Context, machine *v1alpha1.Mach // setPreserveExpiryTimeOnMachine sets the PreserveExpiryTime on the machine object's Status.CurrentStatus to now + preserve timeout func (c *controller) setPreserveExpiryTimeOnMachine(ctx context.Context, machine *v1alpha1.Machine) (*v1alpha1.Machine, error) { - clone := machine.DeepCopy() + preservedCurrentStatus := v1alpha1.CurrentStatus{ Phase: machine.Status.CurrentStatus.Phase, TimeoutActive: machine.Status.CurrentStatus.TimeoutActive, @@ -2450,8 +2442,8 @@ func (c *controller) setPreserveExpiryTimeOnMachine(ctx context.Context, machine PreserveExpiryTime: metav1.NewTime(metav1.Now().Add(c.getEffectiveMachinePreserveTimeout(machine).Duration)), } - clone.Status.CurrentStatus = preservedCurrentStatus - updatedMachine, err := c.controlMachineClient.Machines(machine.Namespace).UpdateStatus(ctx, clone, metav1.UpdateOptions{}) + machine.Status.CurrentStatus = preservedCurrentStatus + updatedMachine, err := c.controlMachineClient.Machines(machine.Namespace).UpdateStatus(ctx, machine, metav1.UpdateOptions{}) if err != nil { klog.Errorf("machine/status UPDATE failed for machine %q. Retrying, error: %s", machine.Name, err) return nil, err @@ -2462,7 +2454,6 @@ func (c *controller) setPreserveExpiryTimeOnMachine(ctx context.Context, machine // addCAScaleDownDisabledAnnotationOnNode adds the cluster-autoscaler annotation to disable scale down of preserved node func (c *controller) addCAScaleDownDisabledAnnotationOnNode(ctx context.Context, node *v1.Node) (*v1.Node, error) { - // Check if annotation already exists with correct value if node.Annotations != nil && node.Annotations[autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationKey] == autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationValue { diff --git a/pkg/util/provider/machinecontroller/machine_util_test.go b/pkg/util/provider/machinecontroller/machine_util_test.go index 53e92a6ba..0095b9bf2 100644 --- a/pkg/util/provider/machinecontroller/machine_util_test.go +++ b/pkg/util/provider/machinecontroller/machine_util_test.go @@ -9,6 +9,7 @@ import ( "encoding/json" "errors" "fmt" + "github.com/gardener/machine-controller-manager/pkg/controller/autoscaler" "k8s.io/klog/v2" "time" @@ -3957,4 +3958,517 @@ var _ = Describe("machine_util", func() { }), ) }) + Describe("#preserveMachine", func() { + type setup struct { + machine *machinev1.Machine + nodeName string + preserveValue string + isCAAnnotationPresent bool + preservedNodeCondition corev1.NodeCondition + } + type expect struct { + preserveNodeCondition corev1.NodeCondition + isPreserveExpiryTimeSet bool + isCAAnnotationPresent bool + err error + } + type testCase struct { + setup setup + expect expect + } + DescribeTable("##preserveMachine behaviour scenarios", + func(tc *testCase) { + stop := make(chan struct{}) + defer close(stop) + + var controlMachineObjects []runtime.Object + var targetCoreObjects []runtime.Object + + controlMachineObjects = append(controlMachineObjects, tc.setup.machine) + if tc.setup.nodeName != "" && tc.setup.nodeName != "invalid" { + node := corev1.Node{ + ObjectMeta: metav1.ObjectMeta{ + Name: tc.setup.nodeName, + Labels: map[string]string{}, + Annotations: map[string]string{}, + }, + Status: corev1.NodeStatus{ + Conditions: []corev1.NodeCondition{}, + }, + } + if tc.setup.isCAAnnotationPresent { + node.Annotations[autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationKey] = "true" + } + targetCoreObjects = append(targetCoreObjects, &node) + } + + c, trackers := createController(stop, testNamespace, controlMachineObjects, nil, targetCoreObjects, nil, false) + defer trackers.Stop() + waitForCacheSync(stop, c) + err := c.preserveMachine(context.TODO(), tc.setup.machine, tc.setup.preserveValue) + if tc.expect.err == nil { + Expect(err).To(BeNil()) + } else { + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(Equal(tc.expect.err.Error())) + } + updatedMachine, getErr := c.controlMachineClient.Machines(testNamespace).Get(context.TODO(), tc.setup.machine.Name, metav1.GetOptions{}) + Expect(getErr).To(BeNil()) + if tc.expect.isPreserveExpiryTimeSet { + Expect(updatedMachine.Status.CurrentStatus.PreserveExpiryTime.IsZero()).To(BeFalse()) + } else { + Expect(updatedMachine.Status.CurrentStatus.PreserveExpiryTime.IsZero()).To(BeTrue()) + } + if tc.setup.nodeName == "" || tc.setup.nodeName == "invalid" { + return + } + updatedNode, getErr := c.targetCoreClient.CoreV1().Nodes().Get(context.TODO(), tc.setup.nodeName, metav1.GetOptions{}) + Expect(getErr).To(BeNil()) + if tc.expect.isCAAnnotationPresent { + Expect(updatedNode.Annotations[autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationKey]).To(Equal(autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationValue)) + } + if tc.expect.preserveNodeCondition.Type != "" { + updatedNodeCondition := nodeops.GetCondition(updatedNode, tc.expect.preserveNodeCondition.Type) + Expect(updatedNodeCondition.Status).To(Equal(tc.expect.preserveNodeCondition.Status)) + Expect(updatedNodeCondition.Reason).To(Equal(tc.expect.preserveNodeCondition.Reason)) + Expect(updatedNodeCondition.Message).To(Equal(tc.expect.preserveNodeCondition.Message)) + } + + }, + Entry("when preserve=now and there is no backing node", &testCase{ + setup: setup{ + machine: &machinev1.Machine{ + ObjectMeta: metav1.ObjectMeta{ + Name: "machine-1", + Namespace: testNamespace, + }, + Spec: machinev1.MachineSpec{}, + Status: machinev1.MachineStatus{ + CurrentStatus: machinev1.CurrentStatus{ + Phase: machinev1.MachineUnknown, + LastUpdateTime: metav1.Now(), + }, + }, + }, + nodeName: "", + preserveValue: machineutils.PreserveMachineAnnotationValueNow, + }, + expect: expect{ + err: nil, + isPreserveExpiryTimeSet: true, + }, + }), + Entry("when preserve=now, the machine is Running, and there is a backing node", &testCase{ + setup: setup{ + machine: &machinev1.Machine{ + ObjectMeta: metav1.ObjectMeta{ + Name: "machine-1", + Namespace: testNamespace, + Labels: map[string]string{ + machinev1.NodeLabelKey: "node-1", + }, + }, + Spec: machinev1.MachineSpec{}, + Status: machinev1.MachineStatus{ + CurrentStatus: machinev1.CurrentStatus{ + Phase: machinev1.MachineRunning, + LastUpdateTime: metav1.Now(), + }, + }, + }, + nodeName: "node-1", + preserveValue: machineutils.PreserveMachineAnnotationValueNow, + }, + expect: expect{ + err: nil, + isPreserveExpiryTimeSet: true, + isCAAnnotationPresent: true, + preserveNodeCondition: corev1.NodeCondition{ + Type: machinev1.NodePreserved, + Status: corev1.ConditionTrue, + Reason: machinev1.NodePreservedByUser, + }, + }, + }), + Entry("when preserve=now, the machine has Failed, and there is a backing node", &testCase{ + setup: setup{ + machine: &machinev1.Machine{ + ObjectMeta: metav1.ObjectMeta{ + Name: "machine-1", + Namespace: testNamespace, + Labels: map[string]string{ + machinev1.NodeLabelKey: "node-1", + }, + }, + Spec: machinev1.MachineSpec{}, + Status: machinev1.MachineStatus{ + CurrentStatus: machinev1.CurrentStatus{ + Phase: machinev1.MachineFailed, + LastUpdateTime: metav1.Now(), + }, + }, + }, + nodeName: "node-1", + preserveValue: machineutils.PreserveMachineAnnotationValueNow, + }, + expect: expect{ + err: nil, + isPreserveExpiryTimeSet: true, + isCAAnnotationPresent: true, + preserveNodeCondition: corev1.NodeCondition{ + Type: machinev1.NodePreserved, + Status: corev1.ConditionTrue, + Reason: machinev1.NodePreservedByUser, + Message: machinev1.PreservedNodeDrainSuccessful, + }, + }, + }), + Entry("when preserve=now, the machine has Failed, and the preservation is incomplete after step 1 - adding preserveExpiryTime", &testCase{ + setup: setup{ + machine: &machinev1.Machine{ + ObjectMeta: metav1.ObjectMeta{ + Name: "machine-1", + Namespace: testNamespace, + Labels: map[string]string{ + machinev1.NodeLabelKey: "node-1", + }, + }, + Spec: machinev1.MachineSpec{}, + Status: machinev1.MachineStatus{ + CurrentStatus: machinev1.CurrentStatus{ + Phase: machinev1.MachineFailed, + LastUpdateTime: metav1.Now(), + PreserveExpiryTime: metav1.NewTime(time.Now().Add(10 * time.Minute)), + }, + }, + }, + nodeName: "node-1", + preserveValue: machineutils.PreserveMachineAnnotationValueNow, + }, + expect: expect{ + err: nil, + isPreserveExpiryTimeSet: true, + isCAAnnotationPresent: true, + preserveNodeCondition: corev1.NodeCondition{ + Type: machinev1.NodePreserved, + Status: corev1.ConditionTrue, + Reason: machinev1.NodePreservedByUser, + Message: machinev1.PreservedNodeDrainSuccessful, + }, + }, + }), + Entry("when preserve=now, the machine has Failed, and the preservation is incomplete at step 2 - adding CA annotations", &testCase{ + setup: setup{ + machine: &machinev1.Machine{ + ObjectMeta: metav1.ObjectMeta{ + Name: "machine-1", + Namespace: testNamespace, + Labels: map[string]string{ + machinev1.NodeLabelKey: "node-1", + }, + }, + Spec: machinev1.MachineSpec{}, + Status: machinev1.MachineStatus{ + CurrentStatus: machinev1.CurrentStatus{ + Phase: machinev1.MachineFailed, + LastUpdateTime: metav1.Now(), + PreserveExpiryTime: metav1.NewTime(time.Now().Add(10 * time.Minute)), + }, + }, + }, + nodeName: "node-1", + preserveValue: machineutils.PreserveMachineAnnotationValueNow, + isCAAnnotationPresent: true, + }, + expect: expect{ + err: nil, + isPreserveExpiryTimeSet: true, + isCAAnnotationPresent: true, + preserveNodeCondition: corev1.NodeCondition{ + Type: machinev1.NodePreserved, + Status: corev1.ConditionTrue, + Reason: machinev1.NodePreservedByUser, + Message: machinev1.PreservedNodeDrainSuccessful, + }, + }, + }), + Entry("when preserve=now, the machine has Failed, and the preservation is incomplete because of drain failure", &testCase{ + setup: setup{ + machine: &machinev1.Machine{ + ObjectMeta: metav1.ObjectMeta{ + Name: "machine-1", + Namespace: testNamespace, + Labels: map[string]string{ + machinev1.NodeLabelKey: "node-1", + }, + }, + Spec: machinev1.MachineSpec{}, + Status: machinev1.MachineStatus{ + CurrentStatus: machinev1.CurrentStatus{ + Phase: machinev1.MachineFailed, + LastUpdateTime: metav1.Now(), + PreserveExpiryTime: metav1.NewTime(time.Now().Add(10 * time.Minute)), + }, + }, + }, + nodeName: "node-1", + preserveValue: machineutils.PreserveMachineAnnotationValueNow, + isCAAnnotationPresent: true, + preservedNodeCondition: corev1.NodeCondition{ + Type: machinev1.NodePreserved, + Status: corev1.ConditionFalse, + Reason: machinev1.NodePreservedByUser, + Message: machinev1.PreservedNodeDrainUnsuccessful, + }, + }, + expect: expect{ + err: nil, + isPreserveExpiryTimeSet: true, + isCAAnnotationPresent: true, + preserveNodeCondition: corev1.NodeCondition{ + Type: machinev1.NodePreserved, + Status: corev1.ConditionTrue, + Reason: machinev1.NodePreservedByUser, + Message: machinev1.PreservedNodeDrainSuccessful, + }, + }, + }), + Entry("when preserve=when-failed, the machine has Failed, and there is a backing node", &testCase{ + setup: setup{ + machine: &machinev1.Machine{ + ObjectMeta: metav1.ObjectMeta{ + Name: "machine-1", + Namespace: testNamespace, + Labels: map[string]string{ + machinev1.NodeLabelKey: "node-1", + }, + }, + Spec: machinev1.MachineSpec{}, + Status: machinev1.MachineStatus{ + CurrentStatus: machinev1.CurrentStatus{ + Phase: machinev1.MachineFailed, + LastUpdateTime: metav1.Now(), + }, + }, + }, + nodeName: "node-1", + preserveValue: machineutils.PreserveMachineAnnotationValueWhenFailed, + }, + expect: expect{ + err: nil, + isPreserveExpiryTimeSet: true, + isCAAnnotationPresent: true, + preserveNodeCondition: corev1.NodeCondition{ + Type: machinev1.NodePreserved, + Status: corev1.ConditionTrue, + Reason: machinev1.NodePreservedByUser, + Message: machinev1.PreservedNodeDrainSuccessful, + }, + }, + }), + Entry("when preserve=auto-preserved, the machine has Failed, and there is a backing node", &testCase{ + setup: setup{ + machine: &machinev1.Machine{ + ObjectMeta: metav1.ObjectMeta{ + Name: "machine-1", + Namespace: testNamespace, + Labels: map[string]string{ + machinev1.NodeLabelKey: "node-1", + }, + }, + Spec: machinev1.MachineSpec{}, + Status: machinev1.MachineStatus{ + CurrentStatus: machinev1.CurrentStatus{ + Phase: machinev1.MachineFailed, + LastUpdateTime: metav1.Now(), + }, + }, + }, + nodeName: "node-1", + preserveValue: machineutils.PreserveMachineAnnotationValuePreservedByMCM, + }, + expect: expect{ + err: nil, + isPreserveExpiryTimeSet: true, + isCAAnnotationPresent: true, + preserveNodeCondition: corev1.NodeCondition{ + Type: machinev1.NodePreserved, + Status: corev1.ConditionTrue, + Reason: machinev1.NodePreservedByMCM, + Message: machinev1.PreservedNodeDrainSuccessful, + }, + }, + }), + Entry("when preserve=now, the machine has Failed, and there is an error fetching backing node", &testCase{ + setup: setup{ + machine: &machinev1.Machine{ + ObjectMeta: metav1.ObjectMeta{ + Name: "machine-1", + Namespace: testNamespace, + Labels: map[string]string{ + machinev1.NodeLabelKey: "invalid", + }, + }, + Spec: machinev1.MachineSpec{}, + Status: machinev1.MachineStatus{ + CurrentStatus: machinev1.CurrentStatus{ + Phase: machinev1.MachineFailed, + LastUpdateTime: metav1.Now(), + }, + }, + }, + nodeName: "invalid", + preserveValue: machineutils.PreserveMachineAnnotationValueNow, + }, + expect: expect{ + err: fmt.Errorf("node \"invalid\" not found"), + isPreserveExpiryTimeSet: true, + isCAAnnotationPresent: false, + }, + }, + ), + ) + }) + Describe("#stopMachinePreservation", func() { + type setup struct { + machine *machinev1.Machine + node *corev1.Node + } + + type expect struct { + err error + } + type testCase struct { + setup setup + expect expect + } + DescribeTable("##preserveMachine behaviour scenarios", + func(tc *testCase) { + stop := make(chan struct{}) + defer close(stop) + + var controlMachineObjects []runtime.Object + var targetCoreObjects []runtime.Object + + controlMachineObjects = append(controlMachineObjects, tc.setup.machine) + if tc.setup.machine.Labels[machinev1.NodeLabelKey] != "" && tc.setup.machine.Labels[machinev1.NodeLabelKey] != "invalid" { + targetCoreObjects = append(targetCoreObjects, tc.setup.node) + } + + c, trackers := createController(stop, testNamespace, controlMachineObjects, nil, targetCoreObjects, nil, false) + defer trackers.Stop() + waitForCacheSync(stop, c) + err := c.stopMachinePreservation(context.TODO(), tc.setup.machine) + if tc.expect.err != nil { + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(Equal(tc.expect.err.Error())) + return + } + Expect(err).To(BeNil()) + updatedMachine, getErr := c.controlMachineClient.Machines(testNamespace).Get(context.TODO(), tc.setup.machine.Name, metav1.GetOptions{}) + Expect(getErr).To(BeNil()) + Expect(updatedMachine.Status.CurrentStatus.PreserveExpiryTime.IsZero()).To(BeTrue()) + + if tc.setup.machine.Labels[machinev1.NodeLabelKey] == "" || tc.setup.machine.Labels[machinev1.NodeLabelKey] == "invalid" { + return + } + updatedNode, getErr := c.targetCoreClient.CoreV1().Nodes().Get(context.TODO(), tc.setup.node.Name, metav1.GetOptions{}) + Expect(getErr).To(BeNil()) + Expect(updatedNode.Annotations[autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationKey]).To(Equal("")) + updatedNodeCondition := nodeops.GetCondition(updatedNode, machinev1.NodePreserved) + Expect(updatedNodeCondition).ToNot(BeNil()) + Expect(updatedNodeCondition.Status).To(Equal(corev1.ConditionFalse)) + Expect(updatedNodeCondition.Reason).To(Equal(machinev1.NodePreservationStopped)) + }, + Entry("when stopping preservation on a preserved machine with backing node", &testCase{ + setup: setup{ + machine: &machinev1.Machine{ + ObjectMeta: metav1.ObjectMeta{ + Name: "machine-1", + Namespace: testNamespace, + Labels: map[string]string{ + machinev1.NodeLabelKey: "node-1", + }, + }, + Spec: machinev1.MachineSpec{}, + Status: machinev1.MachineStatus{ + CurrentStatus: machinev1.CurrentStatus{ + Phase: machinev1.MachineFailed, + LastUpdateTime: metav1.Now(), + PreserveExpiryTime: metav1.NewTime(time.Now().Add(10 * time.Minute)), + }, + }, + }, + node: &corev1.Node{ + ObjectMeta: metav1.ObjectMeta{ + Name: "node-1", + Annotations: map[string]string{ + autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationKey: autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationValue, + }, + }, + Status: corev1.NodeStatus{ + Conditions: []corev1.NodeCondition{ + { + Type: machinev1.NodePreserved, + Status: corev1.ConditionTrue, + Reason: machinev1.NodePreservedByUser, + }, + }, + }, + }, + }, + expect: expect{ + err: nil, + }, + }), + Entry("when stopping preservation on a preserved machine with no backing node", &testCase{ + setup: setup{ + machine: &machinev1.Machine{ + ObjectMeta: metav1.ObjectMeta{ + Name: "machine-1", + Namespace: testNamespace, + Labels: map[string]string{ + machinev1.NodeLabelKey: "", + }, + }, + Spec: machinev1.MachineSpec{}, + Status: machinev1.MachineStatus{ + CurrentStatus: machinev1.CurrentStatus{ + Phase: machinev1.MachineFailed, + LastUpdateTime: metav1.Now(), + PreserveExpiryTime: metav1.NewTime(time.Now().Add(10 * time.Minute)), + }, + }, + }, + }, + expect: expect{ + err: nil, + }, + }), + Entry("when stopping preservation on a preserved machine, and the backing node is not found", &testCase{ + setup: setup{ + machine: &machinev1.Machine{ + ObjectMeta: metav1.ObjectMeta{ + Name: "machine-1", + Namespace: testNamespace, + Labels: map[string]string{ + machinev1.NodeLabelKey: "invalid", + }, + }, + Spec: machinev1.MachineSpec{}, + Status: machinev1.MachineStatus{ + CurrentStatus: machinev1.CurrentStatus{ + Phase: machinev1.MachineFailed, + LastUpdateTime: metav1.Now(), + PreserveExpiryTime: metav1.NewTime(time.Now().Add(10 * time.Minute)), + }, + }, + }, + }, + expect: expect{ + err: fmt.Errorf("node \"invalid\" not found"), + }, + }), + ) + }) }) From 74603a473f3a2968083b1958605bb447528d5f60 Mon Sep 17 00:00:00 2001 From: thiyyakat Date: Wed, 31 Dec 2025 14:48:52 +0530 Subject: [PATCH 37/43] Refactor test code to reduce redundant code --- .../machinecontroller/machine_util_test.go | 315 +++++------------- 1 file changed, 85 insertions(+), 230 deletions(-) diff --git a/pkg/util/provider/machinecontroller/machine_util_test.go b/pkg/util/provider/machinecontroller/machine_util_test.go index 0095b9bf2..87581bda6 100644 --- a/pkg/util/provider/machinecontroller/machine_util_test.go +++ b/pkg/util/provider/machinecontroller/machine_util_test.go @@ -3960,7 +3960,8 @@ var _ = Describe("machine_util", func() { }) Describe("#preserveMachine", func() { type setup struct { - machine *machinev1.Machine + machinePhase machinev1.MachinePhase + preserveExpiryTime metav1.Time nodeName string preserveValue string isCAAnnotationPresent bool @@ -3984,8 +3985,25 @@ var _ = Describe("machine_util", func() { var controlMachineObjects []runtime.Object var targetCoreObjects []runtime.Object - controlMachineObjects = append(controlMachineObjects, tc.setup.machine) - if tc.setup.nodeName != "" && tc.setup.nodeName != "invalid" { + machine := &machinev1.Machine{ + ObjectMeta: metav1.ObjectMeta{ + Name: "machine-1", + Namespace: testNamespace, + Labels: map[string]string{ + machinev1.NodeLabelKey: tc.setup.nodeName, + }, + }, + Spec: machinev1.MachineSpec{}, + Status: machinev1.MachineStatus{ + CurrentStatus: machinev1.CurrentStatus{ + Phase: tc.setup.machinePhase, + LastUpdateTime: metav1.Now(), + PreserveExpiryTime: tc.setup.preserveExpiryTime, + }, + }, + } + if tc.setup.nodeName != "" && tc.setup.nodeName != "err-backing-node" { + node := corev1.Node{ ObjectMeta: metav1.ObjectMeta{ Name: tc.setup.nodeName, @@ -4001,25 +4019,26 @@ var _ = Describe("machine_util", func() { } targetCoreObjects = append(targetCoreObjects, &node) } + controlMachineObjects = append(controlMachineObjects, machine) c, trackers := createController(stop, testNamespace, controlMachineObjects, nil, targetCoreObjects, nil, false) defer trackers.Stop() waitForCacheSync(stop, c) - err := c.preserveMachine(context.TODO(), tc.setup.machine, tc.setup.preserveValue) + err := c.preserveMachine(context.TODO(), machine, tc.setup.preserveValue) if tc.expect.err == nil { Expect(err).To(BeNil()) } else { Expect(err).To(HaveOccurred()) Expect(err.Error()).To(Equal(tc.expect.err.Error())) } - updatedMachine, getErr := c.controlMachineClient.Machines(testNamespace).Get(context.TODO(), tc.setup.machine.Name, metav1.GetOptions{}) + updatedMachine, getErr := c.controlMachineClient.Machines(testNamespace).Get(context.TODO(), machine.Name, metav1.GetOptions{}) Expect(getErr).To(BeNil()) if tc.expect.isPreserveExpiryTimeSet { Expect(updatedMachine.Status.CurrentStatus.PreserveExpiryTime.IsZero()).To(BeFalse()) } else { Expect(updatedMachine.Status.CurrentStatus.PreserveExpiryTime.IsZero()).To(BeTrue()) } - if tc.setup.nodeName == "" || tc.setup.nodeName == "invalid" { + if tc.setup.nodeName == "" || tc.setup.nodeName == "err-backing-node" { return } updatedNode, getErr := c.targetCoreClient.CoreV1().Nodes().Get(context.TODO(), tc.setup.nodeName, metav1.GetOptions{}) @@ -4037,19 +4056,7 @@ var _ = Describe("machine_util", func() { }, Entry("when preserve=now and there is no backing node", &testCase{ setup: setup{ - machine: &machinev1.Machine{ - ObjectMeta: metav1.ObjectMeta{ - Name: "machine-1", - Namespace: testNamespace, - }, - Spec: machinev1.MachineSpec{}, - Status: machinev1.MachineStatus{ - CurrentStatus: machinev1.CurrentStatus{ - Phase: machinev1.MachineUnknown, - LastUpdateTime: metav1.Now(), - }, - }, - }, + machinePhase: machinev1.MachineUnknown, nodeName: "", preserveValue: machineutils.PreserveMachineAnnotationValueNow, }, @@ -4060,22 +4067,7 @@ var _ = Describe("machine_util", func() { }), Entry("when preserve=now, the machine is Running, and there is a backing node", &testCase{ setup: setup{ - machine: &machinev1.Machine{ - ObjectMeta: metav1.ObjectMeta{ - Name: "machine-1", - Namespace: testNamespace, - Labels: map[string]string{ - machinev1.NodeLabelKey: "node-1", - }, - }, - Spec: machinev1.MachineSpec{}, - Status: machinev1.MachineStatus{ - CurrentStatus: machinev1.CurrentStatus{ - Phase: machinev1.MachineRunning, - LastUpdateTime: metav1.Now(), - }, - }, - }, + machinePhase: machinev1.MachineRunning, nodeName: "node-1", preserveValue: machineutils.PreserveMachineAnnotationValueNow, }, @@ -4092,22 +4084,7 @@ var _ = Describe("machine_util", func() { }), Entry("when preserve=now, the machine has Failed, and there is a backing node", &testCase{ setup: setup{ - machine: &machinev1.Machine{ - ObjectMeta: metav1.ObjectMeta{ - Name: "machine-1", - Namespace: testNamespace, - Labels: map[string]string{ - machinev1.NodeLabelKey: "node-1", - }, - }, - Spec: machinev1.MachineSpec{}, - Status: machinev1.MachineStatus{ - CurrentStatus: machinev1.CurrentStatus{ - Phase: machinev1.MachineFailed, - LastUpdateTime: metav1.Now(), - }, - }, - }, + machinePhase: machinev1.MachineFailed, nodeName: "node-1", preserveValue: machineutils.PreserveMachineAnnotationValueNow, }, @@ -4125,23 +4102,7 @@ var _ = Describe("machine_util", func() { }), Entry("when preserve=now, the machine has Failed, and the preservation is incomplete after step 1 - adding preserveExpiryTime", &testCase{ setup: setup{ - machine: &machinev1.Machine{ - ObjectMeta: metav1.ObjectMeta{ - Name: "machine-1", - Namespace: testNamespace, - Labels: map[string]string{ - machinev1.NodeLabelKey: "node-1", - }, - }, - Spec: machinev1.MachineSpec{}, - Status: machinev1.MachineStatus{ - CurrentStatus: machinev1.CurrentStatus{ - Phase: machinev1.MachineFailed, - LastUpdateTime: metav1.Now(), - PreserveExpiryTime: metav1.NewTime(time.Now().Add(10 * time.Minute)), - }, - }, - }, + machinePhase: machinev1.MachineFailed, nodeName: "node-1", preserveValue: machineutils.PreserveMachineAnnotationValueNow, }, @@ -4159,23 +4120,7 @@ var _ = Describe("machine_util", func() { }), Entry("when preserve=now, the machine has Failed, and the preservation is incomplete at step 2 - adding CA annotations", &testCase{ setup: setup{ - machine: &machinev1.Machine{ - ObjectMeta: metav1.ObjectMeta{ - Name: "machine-1", - Namespace: testNamespace, - Labels: map[string]string{ - machinev1.NodeLabelKey: "node-1", - }, - }, - Spec: machinev1.MachineSpec{}, - Status: machinev1.MachineStatus{ - CurrentStatus: machinev1.CurrentStatus{ - Phase: machinev1.MachineFailed, - LastUpdateTime: metav1.Now(), - PreserveExpiryTime: metav1.NewTime(time.Now().Add(10 * time.Minute)), - }, - }, - }, + machinePhase: machinev1.MachineFailed, nodeName: "node-1", preserveValue: machineutils.PreserveMachineAnnotationValueNow, isCAAnnotationPresent: true, @@ -4194,23 +4139,7 @@ var _ = Describe("machine_util", func() { }), Entry("when preserve=now, the machine has Failed, and the preservation is incomplete because of drain failure", &testCase{ setup: setup{ - machine: &machinev1.Machine{ - ObjectMeta: metav1.ObjectMeta{ - Name: "machine-1", - Namespace: testNamespace, - Labels: map[string]string{ - machinev1.NodeLabelKey: "node-1", - }, - }, - Spec: machinev1.MachineSpec{}, - Status: machinev1.MachineStatus{ - CurrentStatus: machinev1.CurrentStatus{ - Phase: machinev1.MachineFailed, - LastUpdateTime: metav1.Now(), - PreserveExpiryTime: metav1.NewTime(time.Now().Add(10 * time.Minute)), - }, - }, - }, + machinePhase: machinev1.MachineFailed, nodeName: "node-1", preserveValue: machineutils.PreserveMachineAnnotationValueNow, isCAAnnotationPresent: true, @@ -4235,22 +4164,7 @@ var _ = Describe("machine_util", func() { }), Entry("when preserve=when-failed, the machine has Failed, and there is a backing node", &testCase{ setup: setup{ - machine: &machinev1.Machine{ - ObjectMeta: metav1.ObjectMeta{ - Name: "machine-1", - Namespace: testNamespace, - Labels: map[string]string{ - machinev1.NodeLabelKey: "node-1", - }, - }, - Spec: machinev1.MachineSpec{}, - Status: machinev1.MachineStatus{ - CurrentStatus: machinev1.CurrentStatus{ - Phase: machinev1.MachineFailed, - LastUpdateTime: metav1.Now(), - }, - }, - }, + machinePhase: machinev1.MachineFailed, nodeName: "node-1", preserveValue: machineutils.PreserveMachineAnnotationValueWhenFailed, }, @@ -4268,22 +4182,7 @@ var _ = Describe("machine_util", func() { }), Entry("when preserve=auto-preserved, the machine has Failed, and there is a backing node", &testCase{ setup: setup{ - machine: &machinev1.Machine{ - ObjectMeta: metav1.ObjectMeta{ - Name: "machine-1", - Namespace: testNamespace, - Labels: map[string]string{ - machinev1.NodeLabelKey: "node-1", - }, - }, - Spec: machinev1.MachineSpec{}, - Status: machinev1.MachineStatus{ - CurrentStatus: machinev1.CurrentStatus{ - Phase: machinev1.MachineFailed, - LastUpdateTime: metav1.Now(), - }, - }, - }, + machinePhase: machinev1.MachineFailed, nodeName: "node-1", preserveValue: machineutils.PreserveMachineAnnotationValuePreservedByMCM, }, @@ -4301,27 +4200,12 @@ var _ = Describe("machine_util", func() { }), Entry("when preserve=now, the machine has Failed, and there is an error fetching backing node", &testCase{ setup: setup{ - machine: &machinev1.Machine{ - ObjectMeta: metav1.ObjectMeta{ - Name: "machine-1", - Namespace: testNamespace, - Labels: map[string]string{ - machinev1.NodeLabelKey: "invalid", - }, - }, - Spec: machinev1.MachineSpec{}, - Status: machinev1.MachineStatus{ - CurrentStatus: machinev1.CurrentStatus{ - Phase: machinev1.MachineFailed, - LastUpdateTime: metav1.Now(), - }, - }, - }, - nodeName: "invalid", + machinePhase: machinev1.MachineFailed, + nodeName: "err-backing-node", preserveValue: machineutils.PreserveMachineAnnotationValueNow, }, expect: expect{ - err: fmt.Errorf("node \"invalid\" not found"), + err: fmt.Errorf("node \"err-backing-node\" not found"), isPreserveExpiryTimeSet: true, isCAAnnotationPresent: false, }, @@ -4331,8 +4215,7 @@ var _ = Describe("machine_util", func() { }) Describe("#stopMachinePreservation", func() { type setup struct { - machine *machinev1.Machine - node *corev1.Node + nodeName string } type expect struct { @@ -4350,29 +4233,66 @@ var _ = Describe("machine_util", func() { var controlMachineObjects []runtime.Object var targetCoreObjects []runtime.Object - controlMachineObjects = append(controlMachineObjects, tc.setup.machine) - if tc.setup.machine.Labels[machinev1.NodeLabelKey] != "" && tc.setup.machine.Labels[machinev1.NodeLabelKey] != "invalid" { - targetCoreObjects = append(targetCoreObjects, tc.setup.node) + machine := &machinev1.Machine{ + ObjectMeta: metav1.ObjectMeta{ + Name: "machine-1", + Namespace: testNamespace, + Labels: map[string]string{}, + }, + Spec: machinev1.MachineSpec{}, + Status: machinev1.MachineStatus{ + CurrentStatus: machinev1.CurrentStatus{ + Phase: machinev1.MachineFailed, + LastUpdateTime: metav1.Now(), + PreserveExpiryTime: metav1.NewTime(time.Now().Add(10 * time.Minute)), + }, + }, + } + if tc.setup.nodeName != "" && tc.setup.nodeName != "err-backing-node" { + machine.Labels[machinev1.NodeLabelKey] = tc.setup.nodeName + node := &corev1.Node{ + ObjectMeta: metav1.ObjectMeta{ + Name: "node-1", + Annotations: map[string]string{ + autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationKey: autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationValue, + }, + }, + Status: corev1.NodeStatus{ + Conditions: []corev1.NodeCondition{ + { + Type: machinev1.NodePreserved, + Status: corev1.ConditionTrue, + Reason: machinev1.NodePreservedByUser, + }, + }, + }, + } + targetCoreObjects = append(targetCoreObjects, node) + + } else { + machine.Labels[machinev1.NodeLabelKey] = "" } + controlMachineObjects = append(controlMachineObjects, machine) + c, trackers := createController(stop, testNamespace, controlMachineObjects, nil, targetCoreObjects, nil, false) defer trackers.Stop() waitForCacheSync(stop, c) - err := c.stopMachinePreservation(context.TODO(), tc.setup.machine) + err := c.stopMachinePreservation(context.TODO(), machine) if tc.expect.err != nil { Expect(err).To(HaveOccurred()) Expect(err.Error()).To(Equal(tc.expect.err.Error())) return } Expect(err).To(BeNil()) - updatedMachine, getErr := c.controlMachineClient.Machines(testNamespace).Get(context.TODO(), tc.setup.machine.Name, metav1.GetOptions{}) + updatedMachine, getErr := c.controlMachineClient.Machines(testNamespace).Get(context.TODO(), machine.Name, metav1.GetOptions{}) Expect(getErr).To(BeNil()) Expect(updatedMachine.Status.CurrentStatus.PreserveExpiryTime.IsZero()).To(BeTrue()) - if tc.setup.machine.Labels[machinev1.NodeLabelKey] == "" || tc.setup.machine.Labels[machinev1.NodeLabelKey] == "invalid" { + if machine.Labels[machinev1.NodeLabelKey] == "" || machine.Labels[machinev1.NodeLabelKey] == "err-backing-node" { return } - updatedNode, getErr := c.targetCoreClient.CoreV1().Nodes().Get(context.TODO(), tc.setup.node.Name, metav1.GetOptions{}) + updatedNode, getErr := c.targetCoreClient.CoreV1().Nodes().Get(context.TODO(), tc.setup.nodeName, metav1.GetOptions{}) Expect(getErr).To(BeNil()) Expect(updatedNode.Annotations[autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationKey]).To(Equal("")) updatedNodeCondition := nodeops.GetCondition(updatedNode, machinev1.NodePreserved) @@ -4382,40 +4302,7 @@ var _ = Describe("machine_util", func() { }, Entry("when stopping preservation on a preserved machine with backing node", &testCase{ setup: setup{ - machine: &machinev1.Machine{ - ObjectMeta: metav1.ObjectMeta{ - Name: "machine-1", - Namespace: testNamespace, - Labels: map[string]string{ - machinev1.NodeLabelKey: "node-1", - }, - }, - Spec: machinev1.MachineSpec{}, - Status: machinev1.MachineStatus{ - CurrentStatus: machinev1.CurrentStatus{ - Phase: machinev1.MachineFailed, - LastUpdateTime: metav1.Now(), - PreserveExpiryTime: metav1.NewTime(time.Now().Add(10 * time.Minute)), - }, - }, - }, - node: &corev1.Node{ - ObjectMeta: metav1.ObjectMeta{ - Name: "node-1", - Annotations: map[string]string{ - autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationKey: autoscaler.ClusterAutoscalerScaleDownDisabledAnnotationValue, - }, - }, - Status: corev1.NodeStatus{ - Conditions: []corev1.NodeCondition{ - { - Type: machinev1.NodePreserved, - Status: corev1.ConditionTrue, - Reason: machinev1.NodePreservedByUser, - }, - }, - }, - }, + nodeName: "node-1", }, expect: expect{ err: nil, @@ -4423,23 +4310,7 @@ var _ = Describe("machine_util", func() { }), Entry("when stopping preservation on a preserved machine with no backing node", &testCase{ setup: setup{ - machine: &machinev1.Machine{ - ObjectMeta: metav1.ObjectMeta{ - Name: "machine-1", - Namespace: testNamespace, - Labels: map[string]string{ - machinev1.NodeLabelKey: "", - }, - }, - Spec: machinev1.MachineSpec{}, - Status: machinev1.MachineStatus{ - CurrentStatus: machinev1.CurrentStatus{ - Phase: machinev1.MachineFailed, - LastUpdateTime: metav1.Now(), - PreserveExpiryTime: metav1.NewTime(time.Now().Add(10 * time.Minute)), - }, - }, - }, + nodeName: "", }, expect: expect{ err: nil, @@ -4447,26 +4318,10 @@ var _ = Describe("machine_util", func() { }), Entry("when stopping preservation on a preserved machine, and the backing node is not found", &testCase{ setup: setup{ - machine: &machinev1.Machine{ - ObjectMeta: metav1.ObjectMeta{ - Name: "machine-1", - Namespace: testNamespace, - Labels: map[string]string{ - machinev1.NodeLabelKey: "invalid", - }, - }, - Spec: machinev1.MachineSpec{}, - Status: machinev1.MachineStatus{ - CurrentStatus: machinev1.CurrentStatus{ - Phase: machinev1.MachineFailed, - LastUpdateTime: metav1.Now(), - PreserveExpiryTime: metav1.NewTime(time.Now().Add(10 * time.Minute)), - }, - }, - }, + nodeName: "no-backing-node", }, expect: expect{ - err: fmt.Errorf("node \"invalid\" not found"), + err: fmt.Errorf("node \"no-backing-node\" not found"), }, }), ) From 43cf3a15b1e6ef23740e422bc071b623f1d3f01e Mon Sep 17 00:00:00 2001 From: thiyyakat Date: Wed, 31 Dec 2025 15:44:34 +0530 Subject: [PATCH 38/43] Fix bugs after merging --- pkg/util/provider/machinecontroller/machine.go | 3 --- pkg/util/provider/machinecontroller/node.go | 8 ++++++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/pkg/util/provider/machinecontroller/machine.go b/pkg/util/provider/machinecontroller/machine.go index 61db1f3e3..51d877e64 100644 --- a/pkg/util/provider/machinecontroller/machine.go +++ b/pkg/util/provider/machinecontroller/machine.go @@ -7,7 +7,6 @@ package controller import ( "context" - "errors" "fmt" "github.com/gardener/machine-controller-manager/pkg/util/nodeops" clientretry "k8s.io/client-go/util/retry" @@ -19,8 +18,6 @@ import ( corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/apimachinery/pkg/selection" utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/client-go/tools/cache" diff --git a/pkg/util/provider/machinecontroller/node.go b/pkg/util/provider/machinecontroller/node.go index d51c1c19b..08e115876 100644 --- a/pkg/util/provider/machinecontroller/node.go +++ b/pkg/util/provider/machinecontroller/node.go @@ -98,6 +98,14 @@ func (c *controller) updateNode(oldObj, newObj any) { if nodeConditionsHaveChanged && !(isMachineCrashLooping || isMachineTerminating) { c.enqueueMachine(machine, fmt.Sprintf("handling node UPDATE event. Conditions of node %q differ from machine status", node.Name)) } + + // to reconcile on change in annotations related to preservation + if c.handlePreserveAnnotationsChange(oldNode.Annotations, node.Annotations, machine) { + klog.V(3).Infof("Node %q for machine %q is annotated for preservation with value %q.", node.Name, machine.Name, node.Annotations[machineutils.PreserveMachineAnnotationKey]) + c.enqueueMachine(machine, fmt.Sprintf("handling node UPDATE event. Preserve annotations added or updated for node %q", getNodeName(machine))) + return + } + } func (c *controller) deleteNode(obj any) { From 1fedc9fa197a54b96ff50404f946932b45e165ab Mon Sep 17 00:00:00 2001 From: thiyyakat Date: Tue, 6 Jan 2026 11:18:01 +0530 Subject: [PATCH 39/43] Remove testing code --- .../provider/machinecontroller/machine.go | 39 ------------------- 1 file changed, 39 deletions(-) diff --git a/pkg/util/provider/machinecontroller/machine.go b/pkg/util/provider/machinecontroller/machine.go index 51d877e64..e911c151b 100644 --- a/pkg/util/provider/machinecontroller/machine.go +++ b/pkg/util/provider/machinecontroller/machine.go @@ -60,11 +60,6 @@ func (c *controller) updateMachine(oldObj, newObj any) { klog.Errorf("couldn't convert to machine resource from object") return } - { // TODO@thiyyakat: remove after testing - if newMachine.Labels["test-failed"] != oldMachine.Labels["test-failed"] { - c.enqueueMachine(newObj, "TEST: handling machine failure simulation UPDATE event") - } - } if c.handlePreserveAnnotationsChange(oldMachine.Annotations, newMachine.Annotations, newMachine) { c.enqueueMachine(newObj, "handling machine object preservation related UPDATE event") return @@ -221,40 +216,6 @@ func (c *controller) reconcileClusterMachine(ctx context.Context, machine *v1alp return retry, err } - { //TODO@thiyyakat: remove after testing - if machine.Labels["test-failed"] == "true" { - node, err := c.nodeLister.Get(getNodeName(machine)) - if err != nil { - klog.V(3).Infof("TEST:Machine %q: Failed to get node %q: %v", machine.Name, machine.Name, err) - return machineutils.ShortRetry, err - } - if cond := nodeops.GetCondition(node, corev1.NodeNetworkUnavailable); cond.Status != corev1.ConditionTrue { - newCond := corev1.NodeCondition{Type: corev1.NodeNetworkUnavailable, Status: corev1.ConditionTrue} - err = nodeops.AddOrUpdateConditionsOnNode(ctx, c.targetCoreClient, getNodeName(machine), newCond) - if err != nil { - klog.V(2).Infof("TEST:Machine %q: Failed to change node condition %q: %v", machine.Name, machine.Name, err) - return machineutils.ShortRetry, err - } - klog.V(2).Infof("TEST: marked nodenetwork as unavailable for machine %s", machine.Name) - } - } else if machine.Labels["test-failed"] == "false" { - node, err := c.nodeLister.Get(getNodeName(machine)) - if err != nil { - klog.V(3).Infof("TEST:Machine %q: Failed to get node %q: %v", machine.Name, machine.Name, err) - return machineutils.ShortRetry, err - } - if cond := nodeops.GetCondition(node, corev1.NodeNetworkUnavailable); cond.Status != corev1.ConditionFalse { - newCond := corev1.NodeCondition{Type: corev1.NodeNetworkUnavailable, Status: corev1.ConditionFalse} - err = nodeops.AddOrUpdateConditionsOnNode(ctx, c.targetCoreClient, getNodeName(machine), newCond) - if err != nil { - klog.V(2).Infof("TEST:Machine %q: Failed to change node condition %q: %v", machine.Name, machine.Name, err) - return machineutils.ShortRetry, err - } - klog.V(2).Infof("TEST: marked nodenetwork as available %s", machine.Name) - } - } - } - retry, err = c.manageMachinePreservation(ctx, machine) if err != nil { return retry, err From fbf3a2a59c310a0dea66c6017393b10f36610311 Mon Sep 17 00:00:00 2001 From: thiyyakat Date: Thu, 8 Jan 2026 11:17:10 +0530 Subject: [PATCH 40/43] Address review comments - part 5: Change api fields to pointers --- Makefile | 6 +- docs/documents/apis.md | 12 +- .../machine.sapcloud.io_machineclasses.yaml | 127 -- ...achine.sapcloud.io_machinedeployments.yaml | 562 -------- .../crds/machine.sapcloud.io_machines.yaml | 333 ----- .../crds/machine.sapcloud.io_machinesets.yaml | 447 ------- pkg/apis/machine/types.go | 8 +- pkg/apis/machine/v1alpha1/machine_types.go | 2 +- .../v1alpha1/machinedeployment_types.go | 2 +- pkg/apis/machine/v1alpha1/machineset_types.go | 4 +- .../v1alpha1/zz_generated.conversion.go | 1179 ----------------- .../machine/v1alpha1/zz_generated.deepcopy.go | 795 ----------- .../machine/v1alpha1/zz_generated.defaults.go | 21 - pkg/apis/machine/zz_generated.deepcopy.go | 888 ------------- pkg/controller/deployment_machineset_util.go | 3 +- pkg/controller/machineset.go | 2 +- pkg/openapi/api_violations.report | 1 - pkg/openapi/openapi_generated.go | 4 +- .../machinecontroller/machine_test.go | 10 +- .../machinecontroller/machine_util.go | 6 +- .../machinecontroller/machine_util_test.go | 5 +- 21 files changed, 32 insertions(+), 4385 deletions(-) delete mode 100644 kubernetes/crds/machine.sapcloud.io_machineclasses.yaml delete mode 100644 kubernetes/crds/machine.sapcloud.io_machinedeployments.yaml delete mode 100644 kubernetes/crds/machine.sapcloud.io_machines.yaml delete mode 100644 kubernetes/crds/machine.sapcloud.io_machinesets.yaml delete mode 100644 pkg/apis/machine/v1alpha1/zz_generated.conversion.go delete mode 100644 pkg/apis/machine/v1alpha1/zz_generated.deepcopy.go delete mode 100644 pkg/apis/machine/v1alpha1/zz_generated.defaults.go delete mode 100644 pkg/apis/machine/zz_generated.deepcopy.go diff --git a/Makefile b/Makefile index aba0236ac..6b0f4f913 100644 --- a/Makefile +++ b/Makefile @@ -172,9 +172,9 @@ test-clean: .PHONY: generate generate: $(VGOPATH) $(DEEPCOPY_GEN) $(DEFAULTER_GEN) $(CONVERSION_GEN) $(OPENAPI_GEN) $(CONTROLLER_GEN) $(GEN_CRD_API_REFERENCE_DOCS) - $(CONTROLLER_GEN) crd paths=./pkg/apis/machine/v1alpha1/... output:crd:dir=kubernetes/crds output:stdout - @./hack/generate-code - @./hack/api-reference/generate-spec-doc.sh + GOFLAGS="-buildvcs=false" $(CONTROLLER_GEN) crd paths=./pkg/apis/machine/v1alpha1/... output:crd:dir=kubernetes/crds output:stdout + @GOFLAGS="-buildvcs=false" ./hack/generate-code + @GOFLAGS="-buildvcs=false" ./hack/api-reference/generate-spec-doc.sh .PHONY: add-license-headers add-license-headers: $(GO_ADD_LICENSE) diff --git a/docs/documents/apis.md b/docs/documents/apis.md index a4e2f7628..0918a46fb 100644 --- a/docs/documents/apis.md +++ b/docs/documents/apis.md @@ -519,7 +519,7 @@ by default, which is treated as infinite deadline.

-int32 +*int32 @@ -699,7 +699,7 @@ int32 -int32 +*int32 @@ -1114,7 +1114,7 @@ Kubernetes meta/v1.Duration -preserveTimeout +machinePreserveTimeout @@ -1463,7 +1463,7 @@ by default, which is treated as infinite deadline.

-int32 +*int32 @@ -1940,7 +1940,7 @@ int32 -int32 +*int32 @@ -2091,7 +2091,7 @@ LastOperation -int32 +*int32 diff --git a/kubernetes/crds/machine.sapcloud.io_machineclasses.yaml b/kubernetes/crds/machine.sapcloud.io_machineclasses.yaml deleted file mode 100644 index f0cd9d515..000000000 --- a/kubernetes/crds/machine.sapcloud.io_machineclasses.yaml +++ /dev/null @@ -1,127 +0,0 @@ ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.16.1 - name: machineclasses.machine.sapcloud.io -spec: - group: machine.sapcloud.io - names: - kind: MachineClass - listKind: MachineClassList - plural: machineclasses - shortNames: - - mcc - singular: machineclass - scope: Namespaced - versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - description: |- - MachineClass can be used to templatize and re-use provider configuration - across multiple Machines / MachineSets / MachineDeployments. - properties: - apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - type: string - credentialsSecretRef: - description: |- - CredentialsSecretRef can optionally store the credentials (in this case the SecretRef does not need to store them). - This might be useful if multiple machine classes with the same credentials but different user-datas are used. - properties: - name: - description: name is unique within a namespace to reference a secret - resource. - type: string - namespace: - description: namespace defines the space within which the secret name - must be unique. - type: string - type: object - x-kubernetes-map-type: atomic - kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - metadata: - type: object - nodeTemplate: - description: NodeTemplate contains subfields to track all node resources - and other node info required to scale nodegroup from zero - properties: - architecture: - description: CPU Architecture of the node belonging to nodeGroup - type: string - capacity: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: Capacity contains subfields to track all node resources - required to scale nodegroup from zero - type: object - instanceType: - description: Instance type of the node belonging to nodeGroup - type: string - region: - description: Region of the expected node belonging to nodeGroup - type: string - virtualCapacity: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: VirtualCapacity represents the expected Node 'virtual' - capacity ie comprising virtual extended resources. - type: object - zone: - description: Zone of the expected node belonging to nodeGroup - type: string - required: - - capacity - - instanceType - - region - - zone - type: object - x-kubernetes-preserve-unknown-fields: true - provider: - description: Provider is the combination of name and location of cloud-specific - drivers. - type: string - providerSpec: - description: Provider-specific configuration to use during node creation. - type: object - x-kubernetes-preserve-unknown-fields: true - secretRef: - description: SecretRef stores the necessary secrets such as credentials - or userdata. - properties: - name: - description: name is unique within a namespace to reference a secret - resource. - type: string - namespace: - description: namespace defines the space within which the secret name - must be unique. - type: string - type: object - x-kubernetes-map-type: atomic - required: - - providerSpec - type: object - served: true - storage: true diff --git a/kubernetes/crds/machine.sapcloud.io_machinedeployments.yaml b/kubernetes/crds/machine.sapcloud.io_machinedeployments.yaml deleted file mode 100644 index abb36d1c4..000000000 --- a/kubernetes/crds/machine.sapcloud.io_machinedeployments.yaml +++ /dev/null @@ -1,562 +0,0 @@ ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.16.1 - name: machinedeployments.machine.sapcloud.io -spec: - group: machine.sapcloud.io - names: - kind: MachineDeployment - listKind: MachineDeploymentList - plural: machinedeployments - shortNames: - - mcd - singular: machinedeployment - scope: Namespaced - versions: - - additionalPrinterColumns: - - description: Total number of ready machines targeted by this machine deployment. - jsonPath: .status.readyReplicas - name: Ready - type: integer - - description: Number of desired machines. - jsonPath: .spec.replicas - name: Desired - type: integer - - description: Total number of non-terminated machines targeted by this machine - deployment that have the desired template spec. - jsonPath: .status.updatedReplicas - name: Up-to-date - type: integer - - description: Total number of available machines (ready for at least minReadySeconds) - targeted by this machine deployment. - jsonPath: .status.availableReplicas - name: Available - type: integer - - description: |- - CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. - Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - description: MachineDeployment enables declarative updates for machines and - MachineSets. - properties: - apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - type: string - kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - metadata: - type: object - spec: - description: Specification of the desired behavior of the MachineDeployment. - properties: - autoPreserveFailedMachineMax: - description: |- - The maximum number of machines in the machine deployment that will be auto-preserved. - In the gardener context, this number is derived from the AutoPreserveFailedMachineMax set at the worker level, distributed amongst the worker's machine deployments - format: int32 - type: integer - minReadySeconds: - description: |- - Minimum number of seconds for which a newly created machine should be ready - without any of its container crashing, for it to be considered available. - Defaults to 0 (machine will be considered available as soon as it is ready) - format: int32 - type: integer - paused: - description: |- - Indicates that the MachineDeployment is paused and will not be processed by the - MachineDeployment controller. - type: boolean - progressDeadlineSeconds: - description: |- - The maximum time in seconds for a MachineDeployment to make progress before it - is considered to be failed. The MachineDeployment controller will continue to - process failed MachineDeployments and a condition with a ProgressDeadlineExceeded - reason will be surfaced in the MachineDeployment status. Note that progress will - not be estimated during the time a MachineDeployment is paused. This is not set - by default, which is treated as infinite deadline. - format: int32 - type: integer - replicas: - description: |- - Number of desired machines. This is a pointer to distinguish between explicit - zero and not specified. Defaults to 0. - format: int32 - type: integer - revisionHistoryLimit: - description: |- - The number of old MachineSets to retain to allow rollback. - This is a pointer to distinguish between explicit zero and not specified. - format: int32 - type: integer - rollbackTo: - description: |- - DEPRECATED. - The config this MachineDeployment is rolling back to. Will be cleared after rollback is done. - properties: - revision: - description: The revision to rollback to. If set to 0, rollback - to the last revision. - format: int64 - type: integer - type: object - selector: - description: |- - Label selector for machines. Existing MachineSets whose machines are - selected by this will be the ones affected by this MachineDeployment. - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. - The requirements are ANDed. - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: |- - operator represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: |- - values is an array of string values. If the operator is In or NotIn, - the values array must be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. This array is replaced during a strategic - merge patch. - items: - type: string - type: array - x-kubernetes-list-type: atomic - required: - - key - - operator - type: object - type: array - x-kubernetes-list-type: atomic - matchLabels: - additionalProperties: - type: string - description: |- - matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, whose key field is "key", the - operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - strategy: - description: The MachineDeployment strategy to use to replace existing - machines with new ones. - properties: - inPlaceUpdate: - description: |- - InPlaceUpdate update config params. Present only if MachineDeploymentStrategyType = - InPlaceUpdate. - properties: - maxSurge: - anyOf: - - type: integer - - type: string - description: |- - The maximum number of machines that can be scheduled above the desired number of - machines. - Value can be an absolute number (ex: 5) or a percentage of desired machines (ex: 10%). - This can not be 0 if MaxUnavailable is 0. - Absolute number is calculated from percentage by rounding up. - Example: when this is set to 30%, the new machine set can be scaled up immediately when - the update starts, such that the total number of old and new machines does not exceed - 130% of desired machines. Once old machines have been killed, - new machine set can be scaled up further, ensuring that total number of machines running - at any time during the update is utmost 130% of desired machines. - x-kubernetes-int-or-string: true - maxUnavailable: - anyOf: - - type: integer - - type: string - description: |- - The maximum number of machines that can be unavailable during the update. - Value can be an absolute number (ex: 5) or a percentage of desired machines (ex: 10%). - Absolute number is calculated from percentage by rounding down. - This can not be 0 if MaxSurge is 0. - Example: when this is set to 30%, the old machine set can be scaled down to 70% of desired machines - immediately when the update starts. Once new machines are ready, old machine set - can be scaled down further, followed by scaling up the new machine set, ensuring - that the total number of machines available at all times during the update is at - least 70% of desired machines. - x-kubernetes-int-or-string: true - orchestrationType: - description: OrchestrationType specifies the orchestration - type for the inplace update. - type: string - type: object - rollingUpdate: - description: |- - Rolling update config params. Present only if MachineDeploymentStrategyType = - RollingUpdate. - properties: - maxSurge: - anyOf: - - type: integer - - type: string - description: |- - The maximum number of machines that can be scheduled above the desired number of - machines. - Value can be an absolute number (ex: 5) or a percentage of desired machines (ex: 10%). - This can not be 0 if MaxUnavailable is 0. - Absolute number is calculated from percentage by rounding up. - Example: when this is set to 30%, the new machine set can be scaled up immediately when - the update starts, such that the total number of old and new machines does not exceed - 130% of desired machines. Once old machines have been killed, - new machine set can be scaled up further, ensuring that total number of machines running - at any time during the update is utmost 130% of desired machines. - x-kubernetes-int-or-string: true - maxUnavailable: - anyOf: - - type: integer - - type: string - description: |- - The maximum number of machines that can be unavailable during the update. - Value can be an absolute number (ex: 5) or a percentage of desired machines (ex: 10%). - Absolute number is calculated from percentage by rounding down. - This can not be 0 if MaxSurge is 0. - Example: when this is set to 30%, the old machine set can be scaled down to 70% of desired machines - immediately when the update starts. Once new machines are ready, old machine set - can be scaled down further, followed by scaling up the new machine set, ensuring - that the total number of machines available at all times during the update is at - least 70% of desired machines. - x-kubernetes-int-or-string: true - type: object - type: - description: Type of MachineDeployment. Can be "Recreate" or "RollingUpdate". - Default is RollingUpdate. - type: string - type: object - template: - description: Template describes the machines that will be created. - properties: - metadata: - description: |- - Standard object's metadata. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - type: object - x-kubernetes-preserve-unknown-fields: true - spec: - description: |- - Specification of the desired behavior of the machine. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - properties: - class: - description: Class contains the machineclass attributes of - a machine - properties: - apiGroup: - description: API group to which it belongs - type: string - kind: - description: Kind for machine class - type: string - name: - description: Name of machine class - type: string - type: object - creationTimeout: - description: MachineCreationTimeout is the timeout after which - machinie creation is declared failed. - type: string - disableHealthTimeout: - description: |- - DisableHealthTimeout if set to true, health timeout will be ignored. Leading to machine never being declared failed. - This is intended to be used only for in-place updates. - type: boolean - drainTimeout: - description: MachineDraintimeout is the timeout after which - machine is forcefully deleted. - type: string - healthTimeout: - description: MachineHealthTimeout is the timeout after which - machine is declared unhealhty/failed. - type: string - inPlaceUpdateTimeout: - description: MachineInPlaceUpdateTimeout is the timeout after - which in-place update is declared failed. - type: string - machinePreserveTimeout: - description: MachinePreserveTimeout is the timeout after which - the machine preservation is stopped - type: string - maxEvictRetries: - description: MaxEvictRetries is the number of retries that - will be attempted while draining the node. - format: int32 - type: integer - nodeConditions: - description: NodeConditions are the set of conditions if set - to true for MachineHealthTimeOut, machine will be declared - failed. - type: string - nodeTemplate: - description: NodeTemplateSpec describes the data a node should - have when created from a template - properties: - metadata: - type: object - x-kubernetes-preserve-unknown-fields: true - spec: - description: NodeSpec describes the attributes that a - node is created with. - properties: - configSource: - description: 'Deprecated: Previously used to specify - the source of the node''s configuration for the - DynamicKubeletConfig feature. This feature is removed.' - properties: - configMap: - description: ConfigMap is a reference to a Node's - ConfigMap - properties: - kubeletConfigKey: - description: |- - KubeletConfigKey declares which key of the referenced ConfigMap corresponds to the KubeletConfiguration structure - This field is required in all cases. - type: string - name: - description: |- - Name is the metadata.name of the referenced ConfigMap. - This field is required in all cases. - type: string - namespace: - description: |- - Namespace is the metadata.namespace of the referenced ConfigMap. - This field is required in all cases. - type: string - resourceVersion: - description: |- - ResourceVersion is the metadata.ResourceVersion of the referenced ConfigMap. - This field is forbidden in Node.Spec, and required in Node.Status. - type: string - uid: - description: |- - UID is the metadata.UID of the referenced ConfigMap. - This field is forbidden in Node.Spec, and required in Node.Status. - type: string - required: - - kubeletConfigKey - - name - - namespace - type: object - type: object - externalID: - description: |- - Deprecated. Not all kubelets will set this field. Remove field after 1.13. - see: https://issues.k8s.io/61966 - type: string - podCIDR: - description: PodCIDR represents the pod IP range assigned - to the node. - type: string - podCIDRs: - description: |- - podCIDRs represents the IP ranges assigned to the node for usage by Pods on that node. If this - field is specified, the 0th entry must match the podCIDR field. It may contain at most 1 value for - each of IPv4 and IPv6. - items: - type: string - type: array - x-kubernetes-list-type: set - providerID: - description: 'ID of the node assigned by the cloud - provider in the format: ://' - type: string - taints: - description: If specified, the node's taints. - items: - description: |- - The node this Taint is attached to has the "effect" on - any pod that does not tolerate the Taint. - properties: - effect: - description: |- - Required. The effect of the taint on pods - that do not tolerate the taint. - Valid effects are NoSchedule, PreferNoSchedule and NoExecute. - type: string - key: - description: Required. The taint key to be applied - to a node. - type: string - timeAdded: - description: |- - TimeAdded represents the time at which the taint was added. - It is only written for NoExecute taints. - format: date-time - type: string - value: - description: The taint value corresponding to - the taint key. - type: string - required: - - effect - - key - type: object - type: array - x-kubernetes-list-type: atomic - unschedulable: - description: |- - Unschedulable controls node schedulability of new pods. By default, node is schedulable. - More info: https://kubernetes.io/docs/concepts/nodes/node/#manual-node-administration - type: boolean - type: object - type: object - providerID: - description: ProviderID represents the provider's unique ID - given to a machine - type: string - type: object - type: object - required: - - template - type: object - status: - description: Most recently observed status of the MachineDeployment. - properties: - availableReplicas: - description: Total number of available machines (ready for at least - minReadySeconds) targeted by this MachineDeployment. - format: int32 - type: integer - collisionCount: - description: |- - Count of hash collisions for the MachineDeployment. The MachineDeployment controller uses this - field as a collision avoidance mechanism when it needs to create the name for the - newest MachineSet. - format: int32 - type: integer - conditions: - description: Represents the latest available observations of a MachineDeployment's - current state. - items: - description: MachineDeploymentCondition describes the state of a - MachineDeployment at a certain point. - properties: - lastTransitionTime: - description: Last time the condition transitioned from one status - to another. - format: date-time - type: string - lastUpdateTime: - description: The last time this condition was updated. - format: date-time - type: string - message: - description: A human readable message indicating details about - the transition. - type: string - reason: - description: The reason for the condition's last transition. - type: string - status: - description: Status of the condition, one of True, False, Unknown. - type: string - type: - description: Type of MachineDeployment condition. - type: string - required: - - status - - type - type: object - type: array - failedMachines: - description: FailedMachines has summary of machines on which lastOperation - Failed - items: - description: MachineSummary store the summary of machine. - properties: - lastOperation: - description: Last operation refers to the status of the last - operation performed - properties: - description: - description: Description of the current operation - type: string - errorCode: - description: ErrorCode of the current operation if any - type: string - lastUpdateTime: - description: Last update time of current operation - format: date-time - type: string - state: - description: State of operation - type: string - type: - description: Type of operation - type: string - type: object - name: - description: Name of the machine object - type: string - ownerRef: - description: OwnerRef - type: string - providerID: - description: ProviderID represents the provider's unique ID - given to a machine - type: string - type: object - type: array - observedGeneration: - description: The generation observed by the MachineDeployment controller. - format: int64 - type: integer - readyReplicas: - description: Total number of ready machines targeted by this MachineDeployment. - format: int32 - type: integer - replicas: - description: Total number of non-terminated machines targeted by this - MachineDeployment (their labels match the selector). - format: int32 - type: integer - unavailableReplicas: - description: |- - Total number of unavailable machines targeted by this MachineDeployment. This is the total number of - machines that are still required for the MachineDeployment to have 100% available capacity. They may - either be machines that are running but not yet available or machines that still have not been created. - format: int32 - type: integer - updatedReplicas: - description: Total number of non-terminated machines targeted by this - MachineDeployment that have the desired template spec. - format: int32 - type: integer - type: object - type: object - served: true - storage: true - subresources: - scale: - specReplicasPath: .spec.replicas - statusReplicasPath: .status.replicas - status: {} diff --git a/kubernetes/crds/machine.sapcloud.io_machines.yaml b/kubernetes/crds/machine.sapcloud.io_machines.yaml deleted file mode 100644 index fcea16750..000000000 --- a/kubernetes/crds/machine.sapcloud.io_machines.yaml +++ /dev/null @@ -1,333 +0,0 @@ ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.16.1 - name: machines.machine.sapcloud.io -spec: - group: machine.sapcloud.io - names: - kind: Machine - listKind: MachineList - plural: machines - shortNames: - - mc - singular: machine - scope: Namespaced - versions: - - additionalPrinterColumns: - - description: Current status of the machine. - jsonPath: .status.currentStatus.phase - name: Status - type: string - - description: |- - CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. - Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - jsonPath: .metadata.creationTimestamp - name: Age - type: date - - description: Node backing the machine object - jsonPath: .metadata.labels.node - name: Node - type: string - - description: ProviderID of the infra instance backing the machine object - jsonPath: .spec.providerID - name: ProviderID - priority: 1 - type: string - name: v1alpha1 - schema: - openAPIV3Schema: - description: Machine is the representation of a physical or virtual machine. - properties: - apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - type: string - kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - metadata: - type: object - spec: - description: Spec contains the specification of the machine - properties: - class: - description: Class contains the machineclass attributes of a machine - properties: - apiGroup: - description: API group to which it belongs - type: string - kind: - description: Kind for machine class - type: string - name: - description: Name of machine class - type: string - type: object - creationTimeout: - description: MachineCreationTimeout is the timeout after which machinie - creation is declared failed. - type: string - disableHealthTimeout: - description: |- - DisableHealthTimeout if set to true, health timeout will be ignored. Leading to machine never being declared failed. - This is intended to be used only for in-place updates. - type: boolean - drainTimeout: - description: MachineDraintimeout is the timeout after which machine - is forcefully deleted. - type: string - healthTimeout: - description: MachineHealthTimeout is the timeout after which machine - is declared unhealhty/failed. - type: string - inPlaceUpdateTimeout: - description: MachineInPlaceUpdateTimeout is the timeout after which - in-place update is declared failed. - type: string - machinePreserveTimeout: - description: MachinePreserveTimeout is the timeout after which the - machine preservation is stopped - type: string - maxEvictRetries: - description: MaxEvictRetries is the number of retries that will be - attempted while draining the node. - format: int32 - type: integer - nodeConditions: - description: NodeConditions are the set of conditions if set to true - for MachineHealthTimeOut, machine will be declared failed. - type: string - nodeTemplate: - description: NodeTemplateSpec describes the data a node should have - when created from a template - properties: - metadata: - type: object - x-kubernetes-preserve-unknown-fields: true - spec: - description: NodeSpec describes the attributes that a node is - created with. - properties: - configSource: - description: 'Deprecated: Previously used to specify the source - of the node''s configuration for the DynamicKubeletConfig - feature. This feature is removed.' - properties: - configMap: - description: ConfigMap is a reference to a Node's ConfigMap - properties: - kubeletConfigKey: - description: |- - KubeletConfigKey declares which key of the referenced ConfigMap corresponds to the KubeletConfiguration structure - This field is required in all cases. - type: string - name: - description: |- - Name is the metadata.name of the referenced ConfigMap. - This field is required in all cases. - type: string - namespace: - description: |- - Namespace is the metadata.namespace of the referenced ConfigMap. - This field is required in all cases. - type: string - resourceVersion: - description: |- - ResourceVersion is the metadata.ResourceVersion of the referenced ConfigMap. - This field is forbidden in Node.Spec, and required in Node.Status. - type: string - uid: - description: |- - UID is the metadata.UID of the referenced ConfigMap. - This field is forbidden in Node.Spec, and required in Node.Status. - type: string - required: - - kubeletConfigKey - - name - - namespace - type: object - type: object - externalID: - description: |- - Deprecated. Not all kubelets will set this field. Remove field after 1.13. - see: https://issues.k8s.io/61966 - type: string - podCIDR: - description: PodCIDR represents the pod IP range assigned - to the node. - type: string - podCIDRs: - description: |- - podCIDRs represents the IP ranges assigned to the node for usage by Pods on that node. If this - field is specified, the 0th entry must match the podCIDR field. It may contain at most 1 value for - each of IPv4 and IPv6. - items: - type: string - type: array - x-kubernetes-list-type: set - providerID: - description: 'ID of the node assigned by the cloud provider - in the format: ://' - type: string - taints: - description: If specified, the node's taints. - items: - description: |- - The node this Taint is attached to has the "effect" on - any pod that does not tolerate the Taint. - properties: - effect: - description: |- - Required. The effect of the taint on pods - that do not tolerate the taint. - Valid effects are NoSchedule, PreferNoSchedule and NoExecute. - type: string - key: - description: Required. The taint key to be applied to - a node. - type: string - timeAdded: - description: |- - TimeAdded represents the time at which the taint was added. - It is only written for NoExecute taints. - format: date-time - type: string - value: - description: The taint value corresponding to the taint - key. - type: string - required: - - effect - - key - type: object - type: array - x-kubernetes-list-type: atomic - unschedulable: - description: |- - Unschedulable controls node schedulability of new pods. By default, node is schedulable. - More info: https://kubernetes.io/docs/concepts/nodes/node/#manual-node-administration - type: boolean - type: object - type: object - providerID: - description: ProviderID represents the provider's unique ID given - to a machine - type: string - type: object - status: - description: Status contains fields depicting the status - properties: - addresses: - description: |- - Addresses of this machines. This field is only present if the MCM provider runs without a target cluster and may - be used by clients to determine how to connect to the machine, instead of the `Node.status.addresses` field. - items: - description: NodeAddress contains information for the node's address. - properties: - address: - description: The node address. - type: string - type: - description: Node address type, one of Hostname, ExternalIP - or InternalIP. - type: string - required: - - address - - type - type: object - type: array - conditions: - description: Conditions of this machine, same as node - items: - description: NodeCondition contains condition information for a - node. - properties: - lastHeartbeatTime: - description: Last time we got an update on a given condition. - format: date-time - type: string - lastTransitionTime: - description: Last time the condition transit from one status - to another. - format: date-time - type: string - message: - description: Human readable message indicating details about - last transition. - type: string - reason: - description: (brief) reason for the condition's last transition. - type: string - status: - description: Status of the condition, one of True, False, Unknown. - type: string - type: - description: Type of node condition. - type: string - required: - - status - - type - type: object - type: array - currentStatus: - description: Current status of the machine object - properties: - lastUpdateTime: - description: Last update time of current status - format: date-time - type: string - phase: - description: MachinePhase is a label for the condition of a machine - at the current time. - type: string - preserveExpiryTime: - description: PreserveExpiryTime is the time at which MCM will - stop preserving the machine - format: date-time - type: string - timeoutActive: - type: boolean - type: object - lastKnownState: - description: |- - LastKnownState can store details of the last known state of the VM by the plugins. - It can be used by future operation calls to determine current infrastucture state - type: string - lastOperation: - description: Last operation refers to the status of the last operation - performed - properties: - description: - description: Description of the current operation - type: string - errorCode: - description: ErrorCode of the current operation if any - type: string - lastUpdateTime: - description: Last update time of current operation - format: date-time - type: string - state: - description: State of operation - type: string - type: - description: Type of operation - type: string - type: object - type: object - type: object - served: true - storage: true - subresources: - status: {} diff --git a/kubernetes/crds/machine.sapcloud.io_machinesets.yaml b/kubernetes/crds/machine.sapcloud.io_machinesets.yaml deleted file mode 100644 index 46445131f..000000000 --- a/kubernetes/crds/machine.sapcloud.io_machinesets.yaml +++ /dev/null @@ -1,447 +0,0 @@ ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.16.1 - name: machinesets.machine.sapcloud.io -spec: - group: machine.sapcloud.io - names: - kind: MachineSet - listKind: MachineSetList - plural: machinesets - shortNames: - - mcs - singular: machineset - scope: Namespaced - versions: - - additionalPrinterColumns: - - description: Number of desired replicas. - jsonPath: .spec.replicas - name: Desired - type: integer - - description: Number of actual replicas. - jsonPath: .status.replicas - name: Current - type: integer - - description: Number of ready replicas for this machine set. - jsonPath: .status.readyReplicas - name: Ready - type: integer - - description: |- - CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. - Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - description: MachineSet TODO - properties: - apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - type: string - kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - metadata: - type: object - spec: - description: MachineSetSpec is the specification of a MachineSet. - properties: - autoPreserveFailedMachineMax: - format: int32 - type: integer - machineClass: - description: ClassSpec is the class specification of machine - properties: - apiGroup: - description: API group to which it belongs - type: string - kind: - description: Kind for machine class - type: string - name: - description: Name of machine class - type: string - type: object - minReadySeconds: - format: int32 - type: integer - replicas: - format: int32 - type: integer - selector: - description: |- - A label selector is a label query over a set of resources. The result of matchLabels and - matchExpressions are ANDed. An empty label selector matches all objects. A null - label selector matches no objects. - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. - The requirements are ANDed. - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - properties: - key: - description: key is the label key that the selector applies - to. - type: string - operator: - description: |- - operator represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: |- - values is an array of string values. If the operator is In or NotIn, - the values array must be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. This array is replaced during a strategic - merge patch. - items: - type: string - type: array - x-kubernetes-list-type: atomic - required: - - key - - operator - type: object - type: array - x-kubernetes-list-type: atomic - matchLabels: - additionalProperties: - type: string - description: |- - matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, whose key field is "key", the - operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - template: - description: MachineTemplateSpec describes the data a machine should - have when created from a template - properties: - metadata: - description: |- - Standard object's metadata. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - type: object - x-kubernetes-preserve-unknown-fields: true - spec: - description: |- - Specification of the desired behavior of the machine. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - properties: - class: - description: Class contains the machineclass attributes of - a machine - properties: - apiGroup: - description: API group to which it belongs - type: string - kind: - description: Kind for machine class - type: string - name: - description: Name of machine class - type: string - type: object - creationTimeout: - description: MachineCreationTimeout is the timeout after which - machinie creation is declared failed. - type: string - disableHealthTimeout: - description: |- - DisableHealthTimeout if set to true, health timeout will be ignored. Leading to machine never being declared failed. - This is intended to be used only for in-place updates. - type: boolean - drainTimeout: - description: MachineDraintimeout is the timeout after which - machine is forcefully deleted. - type: string - healthTimeout: - description: MachineHealthTimeout is the timeout after which - machine is declared unhealhty/failed. - type: string - inPlaceUpdateTimeout: - description: MachineInPlaceUpdateTimeout is the timeout after - which in-place update is declared failed. - type: string - machinePreserveTimeout: - description: MachinePreserveTimeout is the timeout after which - the machine preservation is stopped - type: string - maxEvictRetries: - description: MaxEvictRetries is the number of retries that - will be attempted while draining the node. - format: int32 - type: integer - nodeConditions: - description: NodeConditions are the set of conditions if set - to true for MachineHealthTimeOut, machine will be declared - failed. - type: string - nodeTemplate: - description: NodeTemplateSpec describes the data a node should - have when created from a template - properties: - metadata: - type: object - x-kubernetes-preserve-unknown-fields: true - spec: - description: NodeSpec describes the attributes that a - node is created with. - properties: - configSource: - description: 'Deprecated: Previously used to specify - the source of the node''s configuration for the - DynamicKubeletConfig feature. This feature is removed.' - properties: - configMap: - description: ConfigMap is a reference to a Node's - ConfigMap - properties: - kubeletConfigKey: - description: |- - KubeletConfigKey declares which key of the referenced ConfigMap corresponds to the KubeletConfiguration structure - This field is required in all cases. - type: string - name: - description: |- - Name is the metadata.name of the referenced ConfigMap. - This field is required in all cases. - type: string - namespace: - description: |- - Namespace is the metadata.namespace of the referenced ConfigMap. - This field is required in all cases. - type: string - resourceVersion: - description: |- - ResourceVersion is the metadata.ResourceVersion of the referenced ConfigMap. - This field is forbidden in Node.Spec, and required in Node.Status. - type: string - uid: - description: |- - UID is the metadata.UID of the referenced ConfigMap. - This field is forbidden in Node.Spec, and required in Node.Status. - type: string - required: - - kubeletConfigKey - - name - - namespace - type: object - type: object - externalID: - description: |- - Deprecated. Not all kubelets will set this field. Remove field after 1.13. - see: https://issues.k8s.io/61966 - type: string - podCIDR: - description: PodCIDR represents the pod IP range assigned - to the node. - type: string - podCIDRs: - description: |- - podCIDRs represents the IP ranges assigned to the node for usage by Pods on that node. If this - field is specified, the 0th entry must match the podCIDR field. It may contain at most 1 value for - each of IPv4 and IPv6. - items: - type: string - type: array - x-kubernetes-list-type: set - providerID: - description: 'ID of the node assigned by the cloud - provider in the format: ://' - type: string - taints: - description: If specified, the node's taints. - items: - description: |- - The node this Taint is attached to has the "effect" on - any pod that does not tolerate the Taint. - properties: - effect: - description: |- - Required. The effect of the taint on pods - that do not tolerate the taint. - Valid effects are NoSchedule, PreferNoSchedule and NoExecute. - type: string - key: - description: Required. The taint key to be applied - to a node. - type: string - timeAdded: - description: |- - TimeAdded represents the time at which the taint was added. - It is only written for NoExecute taints. - format: date-time - type: string - value: - description: The taint value corresponding to - the taint key. - type: string - required: - - effect - - key - type: object - type: array - x-kubernetes-list-type: atomic - unschedulable: - description: |- - Unschedulable controls node schedulability of new pods. By default, node is schedulable. - More info: https://kubernetes.io/docs/concepts/nodes/node/#manual-node-administration - type: boolean - type: object - type: object - providerID: - description: ProviderID represents the provider's unique ID - given to a machine - type: string - type: object - type: object - type: object - status: - description: MachineSetStatus holds the most recently observed status - of MachineSet. - properties: - autoPreserveFailedMachineCount: - description: AutoPreserveFailedMachineCount has a count of the number - of failed machines in the machineset that have been auto-preserved - format: int32 - type: integer - availableReplicas: - description: The number of available replicas (ready for at least - minReadySeconds) for this replica set. - format: int32 - type: integer - failedMachines: - description: FailedMachines has summary of machines on which lastOperation - Failed - items: - description: MachineSummary store the summary of machine. - properties: - lastOperation: - description: Last operation refers to the status of the last - operation performed - properties: - description: - description: Description of the current operation - type: string - errorCode: - description: ErrorCode of the current operation if any - type: string - lastUpdateTime: - description: Last update time of current operation - format: date-time - type: string - state: - description: State of operation - type: string - type: - description: Type of operation - type: string - type: object - name: - description: Name of the machine object - type: string - ownerRef: - description: OwnerRef - type: string - providerID: - description: ProviderID represents the provider's unique ID - given to a machine - type: string - type: object - type: array - fullyLabeledReplicas: - description: The number of pods that have labels matching the labels - of the pod template of the replicaset. - format: int32 - type: integer - lastOperation: - description: LastOperation performed - properties: - description: - description: Description of the current operation - type: string - errorCode: - description: ErrorCode of the current operation if any - type: string - lastUpdateTime: - description: Last update time of current operation - format: date-time - type: string - state: - description: State of operation - type: string - type: - description: Type of operation - type: string - type: object - machineSetCondition: - description: Represents the latest available observations of a replica - set's current state. - items: - description: MachineSetCondition describes the state of a machine - set at a certain point. - properties: - lastTransitionTime: - description: The last time the condition transitioned from one - status to another. - format: date-time - type: string - message: - description: A human readable message indicating details about - the transition. - type: string - reason: - description: The reason for the condition's last transition. - type: string - status: - description: Status of the condition, one of True, False, Unknown. - type: string - type: - description: Type of machine set condition. - type: string - required: - - status - - type - type: object - type: array - observedGeneration: - description: ObservedGeneration is the most recent generation observed - by the controller. - format: int64 - type: integer - readyReplicas: - description: The number of ready replicas for this replica set. - format: int32 - type: integer - replicas: - description: Replicas is the number of actual replicas. - format: int32 - type: integer - type: object - type: object - served: true - storage: true - subresources: - scale: - specReplicasPath: .spec.replicas - statusReplicasPath: .status.replicas - status: {} diff --git a/pkg/apis/machine/types.go b/pkg/apis/machine/types.go index c2e535bf7..d9ae90a19 100644 --- a/pkg/apis/machine/types.go +++ b/pkg/apis/machine/types.go @@ -162,7 +162,7 @@ type CurrentStatus struct { LastUpdateTime metav1.Time // PreserveExpiryTime is the time at which MCM will stop preserving the machine - PreserveExpiryTime metav1.Time + PreserveExpiryTime *metav1.Time } // MachineStatus holds the most recently observed status of Machine. @@ -357,7 +357,7 @@ type MachineSetSpec struct { MinReadySeconds int32 - AutoPreserveFailedMachineMax int32 + AutoPreserveFailedMachineMax *int32 } // MachineSetConditionType is the condition on machineset object @@ -418,7 +418,7 @@ type MachineSetStatus struct { FailedMachines *[]MachineSummary // AutoPreserveFailedMachineCount has a count of the number of failed machines in the machineset that have been auto-preserved - AutoPreserveFailedMachineCount int32 + AutoPreserveFailedMachineCount *int32 } // MachineSummary store the summary of machine. @@ -500,7 +500,7 @@ type MachineDeploymentSpec struct { // The maximum number of machines in the machine deployment that will be auto-preserved. // In the gardener context, this number is derived from the AutoPreserveFailedMachineMax set at the worker level, distributed amongst the worker's machine deployments - AutoPreserveFailedMachineMax int32 + AutoPreserveFailedMachineMax *int32 } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object diff --git a/pkg/apis/machine/v1alpha1/machine_types.go b/pkg/apis/machine/v1alpha1/machine_types.go index 654256d32..3744534f3 100644 --- a/pkg/apis/machine/v1alpha1/machine_types.go +++ b/pkg/apis/machine/v1alpha1/machine_types.go @@ -274,7 +274,7 @@ type CurrentStatus struct { LastUpdateTime metav1.Time `json:"lastUpdateTime,omitempty"` // PreserveExpiryTime is the time at which MCM will stop preserving the machine - PreserveExpiryTime metav1.Time `json:"preserveExpiryTime,omitempty"` + PreserveExpiryTime *metav1.Time `json:"preserveExpiryTime,omitempty"` } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object diff --git a/pkg/apis/machine/v1alpha1/machinedeployment_types.go b/pkg/apis/machine/v1alpha1/machinedeployment_types.go index 6cebcd1a1..3fc6487f7 100644 --- a/pkg/apis/machine/v1alpha1/machinedeployment_types.go +++ b/pkg/apis/machine/v1alpha1/machinedeployment_types.go @@ -95,7 +95,7 @@ type MachineDeploymentSpec struct { // The maximum number of machines in the machine deployment that will be auto-preserved. // In the gardener context, this number is derived from the AutoPreserveFailedMachineMax set at the worker level, distributed amongst the worker's machine deployments // +optional - AutoPreserveFailedMachineMax int32 `json:"autoPreserveFailedMachineMax,omitempty"` + AutoPreserveFailedMachineMax *int32 `json:"autoPreserveFailedMachineMax,omitempty"` } const ( diff --git a/pkg/apis/machine/v1alpha1/machineset_types.go b/pkg/apis/machine/v1alpha1/machineset_types.go index 8cd73d58e..2e6d24bd7 100644 --- a/pkg/apis/machine/v1alpha1/machineset_types.go +++ b/pkg/apis/machine/v1alpha1/machineset_types.go @@ -70,7 +70,7 @@ type MachineSetSpec struct { MinReadySeconds int32 `json:"minReadySeconds,omitempty"` // +optional - AutoPreserveFailedMachineMax int32 `json:"autoPreserveFailedMachineMax,omitempty"` + AutoPreserveFailedMachineMax *int32 `json:"autoPreserveFailedMachineMax,omitempty"` } // MachineSetConditionType is the condition on machineset object @@ -141,5 +141,5 @@ type MachineSetStatus struct { // AutoPreserveFailedMachineCount has a count of the number of failed machines in the machineset that have been auto-preserved // +optional - AutoPreserveFailedMachineCount int32 `json:"autoPreserveFailedMachineCount,omitempty"` + AutoPreserveFailedMachineCount *int32 `json:"autoPreserveFailedMachineCount,omitempty"` } diff --git a/pkg/apis/machine/v1alpha1/zz_generated.conversion.go b/pkg/apis/machine/v1alpha1/zz_generated.conversion.go deleted file mode 100644 index 1990c2f03..000000000 --- a/pkg/apis/machine/v1alpha1/zz_generated.conversion.go +++ /dev/null @@ -1,1179 +0,0 @@ -//go:build !ignore_autogenerated -// +build !ignore_autogenerated - -// SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors -// -// SPDX-License-Identifier: Apache-2.0 - -// Code generated by conversion-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - unsafe "unsafe" - - machine "github.com/gardener/machine-controller-manager/pkg/apis/machine" - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - conversion "k8s.io/apimachinery/pkg/conversion" - runtime "k8s.io/apimachinery/pkg/runtime" - intstr "k8s.io/apimachinery/pkg/util/intstr" -) - -func init() { - localSchemeBuilder.Register(RegisterConversions) -} - -// RegisterConversions adds conversion functions to the given scheme. -// Public to allow building arbitrary schemes. -func RegisterConversions(s *runtime.Scheme) error { - if err := s.AddGeneratedConversionFunc((*ClassSpec)(nil), (*machine.ClassSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_ClassSpec_To_machine_ClassSpec(a.(*ClassSpec), b.(*machine.ClassSpec), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*machine.ClassSpec)(nil), (*ClassSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_machine_ClassSpec_To_v1alpha1_ClassSpec(a.(*machine.ClassSpec), b.(*ClassSpec), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*CurrentStatus)(nil), (*machine.CurrentStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_CurrentStatus_To_machine_CurrentStatus(a.(*CurrentStatus), b.(*machine.CurrentStatus), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*machine.CurrentStatus)(nil), (*CurrentStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_machine_CurrentStatus_To_v1alpha1_CurrentStatus(a.(*machine.CurrentStatus), b.(*CurrentStatus), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*InPlaceUpdateMachineDeployment)(nil), (*machine.InPlaceUpdateMachineDeployment)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_InPlaceUpdateMachineDeployment_To_machine_InPlaceUpdateMachineDeployment(a.(*InPlaceUpdateMachineDeployment), b.(*machine.InPlaceUpdateMachineDeployment), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*machine.InPlaceUpdateMachineDeployment)(nil), (*InPlaceUpdateMachineDeployment)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_machine_InPlaceUpdateMachineDeployment_To_v1alpha1_InPlaceUpdateMachineDeployment(a.(*machine.InPlaceUpdateMachineDeployment), b.(*InPlaceUpdateMachineDeployment), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*LastOperation)(nil), (*machine.LastOperation)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_LastOperation_To_machine_LastOperation(a.(*LastOperation), b.(*machine.LastOperation), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*machine.LastOperation)(nil), (*LastOperation)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_machine_LastOperation_To_v1alpha1_LastOperation(a.(*machine.LastOperation), b.(*LastOperation), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*Machine)(nil), (*machine.Machine)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_Machine_To_machine_Machine(a.(*Machine), b.(*machine.Machine), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*machine.Machine)(nil), (*Machine)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_machine_Machine_To_v1alpha1_Machine(a.(*machine.Machine), b.(*Machine), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*MachineClass)(nil), (*machine.MachineClass)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_MachineClass_To_machine_MachineClass(a.(*MachineClass), b.(*machine.MachineClass), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*machine.MachineClass)(nil), (*MachineClass)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_machine_MachineClass_To_v1alpha1_MachineClass(a.(*machine.MachineClass), b.(*MachineClass), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*MachineClassList)(nil), (*machine.MachineClassList)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_MachineClassList_To_machine_MachineClassList(a.(*MachineClassList), b.(*machine.MachineClassList), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*machine.MachineClassList)(nil), (*MachineClassList)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_machine_MachineClassList_To_v1alpha1_MachineClassList(a.(*machine.MachineClassList), b.(*MachineClassList), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*MachineConfiguration)(nil), (*machine.MachineConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_MachineConfiguration_To_machine_MachineConfiguration(a.(*MachineConfiguration), b.(*machine.MachineConfiguration), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*machine.MachineConfiguration)(nil), (*MachineConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_machine_MachineConfiguration_To_v1alpha1_MachineConfiguration(a.(*machine.MachineConfiguration), b.(*MachineConfiguration), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*MachineDeployment)(nil), (*machine.MachineDeployment)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_MachineDeployment_To_machine_MachineDeployment(a.(*MachineDeployment), b.(*machine.MachineDeployment), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*machine.MachineDeployment)(nil), (*MachineDeployment)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_machine_MachineDeployment_To_v1alpha1_MachineDeployment(a.(*machine.MachineDeployment), b.(*MachineDeployment), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*MachineDeploymentCondition)(nil), (*machine.MachineDeploymentCondition)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_MachineDeploymentCondition_To_machine_MachineDeploymentCondition(a.(*MachineDeploymentCondition), b.(*machine.MachineDeploymentCondition), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*machine.MachineDeploymentCondition)(nil), (*MachineDeploymentCondition)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_machine_MachineDeploymentCondition_To_v1alpha1_MachineDeploymentCondition(a.(*machine.MachineDeploymentCondition), b.(*MachineDeploymentCondition), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*MachineDeploymentList)(nil), (*machine.MachineDeploymentList)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_MachineDeploymentList_To_machine_MachineDeploymentList(a.(*MachineDeploymentList), b.(*machine.MachineDeploymentList), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*machine.MachineDeploymentList)(nil), (*MachineDeploymentList)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_machine_MachineDeploymentList_To_v1alpha1_MachineDeploymentList(a.(*machine.MachineDeploymentList), b.(*MachineDeploymentList), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*MachineDeploymentSpec)(nil), (*machine.MachineDeploymentSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_MachineDeploymentSpec_To_machine_MachineDeploymentSpec(a.(*MachineDeploymentSpec), b.(*machine.MachineDeploymentSpec), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*machine.MachineDeploymentSpec)(nil), (*MachineDeploymentSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_machine_MachineDeploymentSpec_To_v1alpha1_MachineDeploymentSpec(a.(*machine.MachineDeploymentSpec), b.(*MachineDeploymentSpec), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*MachineDeploymentStatus)(nil), (*machine.MachineDeploymentStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_MachineDeploymentStatus_To_machine_MachineDeploymentStatus(a.(*MachineDeploymentStatus), b.(*machine.MachineDeploymentStatus), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*machine.MachineDeploymentStatus)(nil), (*MachineDeploymentStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_machine_MachineDeploymentStatus_To_v1alpha1_MachineDeploymentStatus(a.(*machine.MachineDeploymentStatus), b.(*MachineDeploymentStatus), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*MachineDeploymentStrategy)(nil), (*machine.MachineDeploymentStrategy)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_MachineDeploymentStrategy_To_machine_MachineDeploymentStrategy(a.(*MachineDeploymentStrategy), b.(*machine.MachineDeploymentStrategy), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*machine.MachineDeploymentStrategy)(nil), (*MachineDeploymentStrategy)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_machine_MachineDeploymentStrategy_To_v1alpha1_MachineDeploymentStrategy(a.(*machine.MachineDeploymentStrategy), b.(*MachineDeploymentStrategy), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*MachineList)(nil), (*machine.MachineList)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_MachineList_To_machine_MachineList(a.(*MachineList), b.(*machine.MachineList), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*machine.MachineList)(nil), (*MachineList)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_machine_MachineList_To_v1alpha1_MachineList(a.(*machine.MachineList), b.(*MachineList), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*MachineSet)(nil), (*machine.MachineSet)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_MachineSet_To_machine_MachineSet(a.(*MachineSet), b.(*machine.MachineSet), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*machine.MachineSet)(nil), (*MachineSet)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_machine_MachineSet_To_v1alpha1_MachineSet(a.(*machine.MachineSet), b.(*MachineSet), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*MachineSetCondition)(nil), (*machine.MachineSetCondition)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_MachineSetCondition_To_machine_MachineSetCondition(a.(*MachineSetCondition), b.(*machine.MachineSetCondition), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*machine.MachineSetCondition)(nil), (*MachineSetCondition)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_machine_MachineSetCondition_To_v1alpha1_MachineSetCondition(a.(*machine.MachineSetCondition), b.(*MachineSetCondition), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*MachineSetList)(nil), (*machine.MachineSetList)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_MachineSetList_To_machine_MachineSetList(a.(*MachineSetList), b.(*machine.MachineSetList), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*machine.MachineSetList)(nil), (*MachineSetList)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_machine_MachineSetList_To_v1alpha1_MachineSetList(a.(*machine.MachineSetList), b.(*MachineSetList), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*MachineSetSpec)(nil), (*machine.MachineSetSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_MachineSetSpec_To_machine_MachineSetSpec(a.(*MachineSetSpec), b.(*machine.MachineSetSpec), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*machine.MachineSetSpec)(nil), (*MachineSetSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_machine_MachineSetSpec_To_v1alpha1_MachineSetSpec(a.(*machine.MachineSetSpec), b.(*MachineSetSpec), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*MachineSetStatus)(nil), (*machine.MachineSetStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_MachineSetStatus_To_machine_MachineSetStatus(a.(*MachineSetStatus), b.(*machine.MachineSetStatus), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*machine.MachineSetStatus)(nil), (*MachineSetStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_machine_MachineSetStatus_To_v1alpha1_MachineSetStatus(a.(*machine.MachineSetStatus), b.(*MachineSetStatus), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*MachineSpec)(nil), (*machine.MachineSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_MachineSpec_To_machine_MachineSpec(a.(*MachineSpec), b.(*machine.MachineSpec), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*machine.MachineSpec)(nil), (*MachineSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_machine_MachineSpec_To_v1alpha1_MachineSpec(a.(*machine.MachineSpec), b.(*MachineSpec), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*MachineStatus)(nil), (*machine.MachineStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_MachineStatus_To_machine_MachineStatus(a.(*MachineStatus), b.(*machine.MachineStatus), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*machine.MachineStatus)(nil), (*MachineStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_machine_MachineStatus_To_v1alpha1_MachineStatus(a.(*machine.MachineStatus), b.(*MachineStatus), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*MachineSummary)(nil), (*machine.MachineSummary)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_MachineSummary_To_machine_MachineSummary(a.(*MachineSummary), b.(*machine.MachineSummary), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*machine.MachineSummary)(nil), (*MachineSummary)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_machine_MachineSummary_To_v1alpha1_MachineSummary(a.(*machine.MachineSummary), b.(*MachineSummary), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*MachineTemplateSpec)(nil), (*machine.MachineTemplateSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_MachineTemplateSpec_To_machine_MachineTemplateSpec(a.(*MachineTemplateSpec), b.(*machine.MachineTemplateSpec), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*machine.MachineTemplateSpec)(nil), (*MachineTemplateSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_machine_MachineTemplateSpec_To_v1alpha1_MachineTemplateSpec(a.(*machine.MachineTemplateSpec), b.(*MachineTemplateSpec), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*NodeTemplate)(nil), (*machine.NodeTemplate)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_NodeTemplate_To_machine_NodeTemplate(a.(*NodeTemplate), b.(*machine.NodeTemplate), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*machine.NodeTemplate)(nil), (*NodeTemplate)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_machine_NodeTemplate_To_v1alpha1_NodeTemplate(a.(*machine.NodeTemplate), b.(*NodeTemplate), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*NodeTemplateSpec)(nil), (*machine.NodeTemplateSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_NodeTemplateSpec_To_machine_NodeTemplateSpec(a.(*NodeTemplateSpec), b.(*machine.NodeTemplateSpec), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*machine.NodeTemplateSpec)(nil), (*NodeTemplateSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_machine_NodeTemplateSpec_To_v1alpha1_NodeTemplateSpec(a.(*machine.NodeTemplateSpec), b.(*NodeTemplateSpec), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*RollbackConfig)(nil), (*machine.RollbackConfig)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_RollbackConfig_To_machine_RollbackConfig(a.(*RollbackConfig), b.(*machine.RollbackConfig), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*machine.RollbackConfig)(nil), (*RollbackConfig)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_machine_RollbackConfig_To_v1alpha1_RollbackConfig(a.(*machine.RollbackConfig), b.(*RollbackConfig), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*RollingUpdateMachineDeployment)(nil), (*machine.RollingUpdateMachineDeployment)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_RollingUpdateMachineDeployment_To_machine_RollingUpdateMachineDeployment(a.(*RollingUpdateMachineDeployment), b.(*machine.RollingUpdateMachineDeployment), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*machine.RollingUpdateMachineDeployment)(nil), (*RollingUpdateMachineDeployment)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_machine_RollingUpdateMachineDeployment_To_v1alpha1_RollingUpdateMachineDeployment(a.(*machine.RollingUpdateMachineDeployment), b.(*RollingUpdateMachineDeployment), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*UpdateConfiguration)(nil), (*machine.UpdateConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_UpdateConfiguration_To_machine_UpdateConfiguration(a.(*UpdateConfiguration), b.(*machine.UpdateConfiguration), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*machine.UpdateConfiguration)(nil), (*UpdateConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_machine_UpdateConfiguration_To_v1alpha1_UpdateConfiguration(a.(*machine.UpdateConfiguration), b.(*UpdateConfiguration), scope) - }); err != nil { - return err - } - return nil -} - -func autoConvert_v1alpha1_ClassSpec_To_machine_ClassSpec(in *ClassSpec, out *machine.ClassSpec, s conversion.Scope) error { - out.APIGroup = in.APIGroup - out.Kind = in.Kind - out.Name = in.Name - return nil -} - -// Convert_v1alpha1_ClassSpec_To_machine_ClassSpec is an autogenerated conversion function. -func Convert_v1alpha1_ClassSpec_To_machine_ClassSpec(in *ClassSpec, out *machine.ClassSpec, s conversion.Scope) error { - return autoConvert_v1alpha1_ClassSpec_To_machine_ClassSpec(in, out, s) -} - -func autoConvert_machine_ClassSpec_To_v1alpha1_ClassSpec(in *machine.ClassSpec, out *ClassSpec, s conversion.Scope) error { - out.APIGroup = in.APIGroup - out.Kind = in.Kind - out.Name = in.Name - return nil -} - -// Convert_machine_ClassSpec_To_v1alpha1_ClassSpec is an autogenerated conversion function. -func Convert_machine_ClassSpec_To_v1alpha1_ClassSpec(in *machine.ClassSpec, out *ClassSpec, s conversion.Scope) error { - return autoConvert_machine_ClassSpec_To_v1alpha1_ClassSpec(in, out, s) -} - -func autoConvert_v1alpha1_CurrentStatus_To_machine_CurrentStatus(in *CurrentStatus, out *machine.CurrentStatus, s conversion.Scope) error { - out.Phase = machine.MachinePhase(in.Phase) - out.TimeoutActive = in.TimeoutActive - out.LastUpdateTime = in.LastUpdateTime - out.PreserveExpiryTime = in.PreserveExpiryTime - return nil -} - -// Convert_v1alpha1_CurrentStatus_To_machine_CurrentStatus is an autogenerated conversion function. -func Convert_v1alpha1_CurrentStatus_To_machine_CurrentStatus(in *CurrentStatus, out *machine.CurrentStatus, s conversion.Scope) error { - return autoConvert_v1alpha1_CurrentStatus_To_machine_CurrentStatus(in, out, s) -} - -func autoConvert_machine_CurrentStatus_To_v1alpha1_CurrentStatus(in *machine.CurrentStatus, out *CurrentStatus, s conversion.Scope) error { - out.Phase = MachinePhase(in.Phase) - out.TimeoutActive = in.TimeoutActive - out.LastUpdateTime = in.LastUpdateTime - out.PreserveExpiryTime = in.PreserveExpiryTime - return nil -} - -// Convert_machine_CurrentStatus_To_v1alpha1_CurrentStatus is an autogenerated conversion function. -func Convert_machine_CurrentStatus_To_v1alpha1_CurrentStatus(in *machine.CurrentStatus, out *CurrentStatus, s conversion.Scope) error { - return autoConvert_machine_CurrentStatus_To_v1alpha1_CurrentStatus(in, out, s) -} - -func autoConvert_v1alpha1_InPlaceUpdateMachineDeployment_To_machine_InPlaceUpdateMachineDeployment(in *InPlaceUpdateMachineDeployment, out *machine.InPlaceUpdateMachineDeployment, s conversion.Scope) error { - if err := Convert_v1alpha1_UpdateConfiguration_To_machine_UpdateConfiguration(&in.UpdateConfiguration, &out.UpdateConfiguration, s); err != nil { - return err - } - out.OrchestrationType = machine.OrchestrationType(in.OrchestrationType) - return nil -} - -// Convert_v1alpha1_InPlaceUpdateMachineDeployment_To_machine_InPlaceUpdateMachineDeployment is an autogenerated conversion function. -func Convert_v1alpha1_InPlaceUpdateMachineDeployment_To_machine_InPlaceUpdateMachineDeployment(in *InPlaceUpdateMachineDeployment, out *machine.InPlaceUpdateMachineDeployment, s conversion.Scope) error { - return autoConvert_v1alpha1_InPlaceUpdateMachineDeployment_To_machine_InPlaceUpdateMachineDeployment(in, out, s) -} - -func autoConvert_machine_InPlaceUpdateMachineDeployment_To_v1alpha1_InPlaceUpdateMachineDeployment(in *machine.InPlaceUpdateMachineDeployment, out *InPlaceUpdateMachineDeployment, s conversion.Scope) error { - if err := Convert_machine_UpdateConfiguration_To_v1alpha1_UpdateConfiguration(&in.UpdateConfiguration, &out.UpdateConfiguration, s); err != nil { - return err - } - out.OrchestrationType = OrchestrationType(in.OrchestrationType) - return nil -} - -// Convert_machine_InPlaceUpdateMachineDeployment_To_v1alpha1_InPlaceUpdateMachineDeployment is an autogenerated conversion function. -func Convert_machine_InPlaceUpdateMachineDeployment_To_v1alpha1_InPlaceUpdateMachineDeployment(in *machine.InPlaceUpdateMachineDeployment, out *InPlaceUpdateMachineDeployment, s conversion.Scope) error { - return autoConvert_machine_InPlaceUpdateMachineDeployment_To_v1alpha1_InPlaceUpdateMachineDeployment(in, out, s) -} - -func autoConvert_v1alpha1_LastOperation_To_machine_LastOperation(in *LastOperation, out *machine.LastOperation, s conversion.Scope) error { - out.Description = in.Description - out.ErrorCode = in.ErrorCode - out.LastUpdateTime = in.LastUpdateTime - out.State = machine.MachineState(in.State) - out.Type = machine.MachineOperationType(in.Type) - return nil -} - -// Convert_v1alpha1_LastOperation_To_machine_LastOperation is an autogenerated conversion function. -func Convert_v1alpha1_LastOperation_To_machine_LastOperation(in *LastOperation, out *machine.LastOperation, s conversion.Scope) error { - return autoConvert_v1alpha1_LastOperation_To_machine_LastOperation(in, out, s) -} - -func autoConvert_machine_LastOperation_To_v1alpha1_LastOperation(in *machine.LastOperation, out *LastOperation, s conversion.Scope) error { - out.Description = in.Description - out.ErrorCode = in.ErrorCode - out.LastUpdateTime = in.LastUpdateTime - out.State = MachineState(in.State) - out.Type = MachineOperationType(in.Type) - return nil -} - -// Convert_machine_LastOperation_To_v1alpha1_LastOperation is an autogenerated conversion function. -func Convert_machine_LastOperation_To_v1alpha1_LastOperation(in *machine.LastOperation, out *LastOperation, s conversion.Scope) error { - return autoConvert_machine_LastOperation_To_v1alpha1_LastOperation(in, out, s) -} - -func autoConvert_v1alpha1_Machine_To_machine_Machine(in *Machine, out *machine.Machine, s conversion.Scope) error { - out.ObjectMeta = in.ObjectMeta - if err := Convert_v1alpha1_MachineSpec_To_machine_MachineSpec(&in.Spec, &out.Spec, s); err != nil { - return err - } - if err := Convert_v1alpha1_MachineStatus_To_machine_MachineStatus(&in.Status, &out.Status, s); err != nil { - return err - } - return nil -} - -// Convert_v1alpha1_Machine_To_machine_Machine is an autogenerated conversion function. -func Convert_v1alpha1_Machine_To_machine_Machine(in *Machine, out *machine.Machine, s conversion.Scope) error { - return autoConvert_v1alpha1_Machine_To_machine_Machine(in, out, s) -} - -func autoConvert_machine_Machine_To_v1alpha1_Machine(in *machine.Machine, out *Machine, s conversion.Scope) error { - out.ObjectMeta = in.ObjectMeta - if err := Convert_machine_MachineSpec_To_v1alpha1_MachineSpec(&in.Spec, &out.Spec, s); err != nil { - return err - } - if err := Convert_machine_MachineStatus_To_v1alpha1_MachineStatus(&in.Status, &out.Status, s); err != nil { - return err - } - return nil -} - -// Convert_machine_Machine_To_v1alpha1_Machine is an autogenerated conversion function. -func Convert_machine_Machine_To_v1alpha1_Machine(in *machine.Machine, out *Machine, s conversion.Scope) error { - return autoConvert_machine_Machine_To_v1alpha1_Machine(in, out, s) -} - -func autoConvert_v1alpha1_MachineClass_To_machine_MachineClass(in *MachineClass, out *machine.MachineClass, s conversion.Scope) error { - out.ObjectMeta = in.ObjectMeta - out.NodeTemplate = (*machine.NodeTemplate)(unsafe.Pointer(in.NodeTemplate)) - out.CredentialsSecretRef = (*v1.SecretReference)(unsafe.Pointer(in.CredentialsSecretRef)) - out.ProviderSpec = in.ProviderSpec - out.Provider = in.Provider - out.SecretRef = (*v1.SecretReference)(unsafe.Pointer(in.SecretRef)) - return nil -} - -// Convert_v1alpha1_MachineClass_To_machine_MachineClass is an autogenerated conversion function. -func Convert_v1alpha1_MachineClass_To_machine_MachineClass(in *MachineClass, out *machine.MachineClass, s conversion.Scope) error { - return autoConvert_v1alpha1_MachineClass_To_machine_MachineClass(in, out, s) -} - -func autoConvert_machine_MachineClass_To_v1alpha1_MachineClass(in *machine.MachineClass, out *MachineClass, s conversion.Scope) error { - out.ObjectMeta = in.ObjectMeta - out.NodeTemplate = (*NodeTemplate)(unsafe.Pointer(in.NodeTemplate)) - out.CredentialsSecretRef = (*v1.SecretReference)(unsafe.Pointer(in.CredentialsSecretRef)) - out.Provider = in.Provider - out.ProviderSpec = in.ProviderSpec - out.SecretRef = (*v1.SecretReference)(unsafe.Pointer(in.SecretRef)) - return nil -} - -// Convert_machine_MachineClass_To_v1alpha1_MachineClass is an autogenerated conversion function. -func Convert_machine_MachineClass_To_v1alpha1_MachineClass(in *machine.MachineClass, out *MachineClass, s conversion.Scope) error { - return autoConvert_machine_MachineClass_To_v1alpha1_MachineClass(in, out, s) -} - -func autoConvert_v1alpha1_MachineClassList_To_machine_MachineClassList(in *MachineClassList, out *machine.MachineClassList, s conversion.Scope) error { - out.ListMeta = in.ListMeta - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]machine.MachineClass, len(*in)) - for i := range *in { - if err := Convert_v1alpha1_MachineClass_To_machine_MachineClass(&(*in)[i], &(*out)[i], s); err != nil { - return err - } - } - } else { - out.Items = nil - } - return nil -} - -// Convert_v1alpha1_MachineClassList_To_machine_MachineClassList is an autogenerated conversion function. -func Convert_v1alpha1_MachineClassList_To_machine_MachineClassList(in *MachineClassList, out *machine.MachineClassList, s conversion.Scope) error { - return autoConvert_v1alpha1_MachineClassList_To_machine_MachineClassList(in, out, s) -} - -func autoConvert_machine_MachineClassList_To_v1alpha1_MachineClassList(in *machine.MachineClassList, out *MachineClassList, s conversion.Scope) error { - out.ListMeta = in.ListMeta - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]MachineClass, len(*in)) - for i := range *in { - if err := Convert_machine_MachineClass_To_v1alpha1_MachineClass(&(*in)[i], &(*out)[i], s); err != nil { - return err - } - } - } else { - out.Items = nil - } - return nil -} - -// Convert_machine_MachineClassList_To_v1alpha1_MachineClassList is an autogenerated conversion function. -func Convert_machine_MachineClassList_To_v1alpha1_MachineClassList(in *machine.MachineClassList, out *MachineClassList, s conversion.Scope) error { - return autoConvert_machine_MachineClassList_To_v1alpha1_MachineClassList(in, out, s) -} - -func autoConvert_v1alpha1_MachineConfiguration_To_machine_MachineConfiguration(in *MachineConfiguration, out *machine.MachineConfiguration, s conversion.Scope) error { - out.MachineDrainTimeout = (*metav1.Duration)(unsafe.Pointer(in.MachineDrainTimeout)) - out.MachineHealthTimeout = (*metav1.Duration)(unsafe.Pointer(in.MachineHealthTimeout)) - out.MachineCreationTimeout = (*metav1.Duration)(unsafe.Pointer(in.MachineCreationTimeout)) - out.MachineInPlaceUpdateTimeout = (*metav1.Duration)(unsafe.Pointer(in.MachineInPlaceUpdateTimeout)) - out.MachinePreserveTimeout = (*metav1.Duration)(unsafe.Pointer(in.MachinePreserveTimeout)) - out.DisableHealthTimeout = (*bool)(unsafe.Pointer(in.DisableHealthTimeout)) - out.MaxEvictRetries = (*int32)(unsafe.Pointer(in.MaxEvictRetries)) - out.NodeConditions = (*string)(unsafe.Pointer(in.NodeConditions)) - return nil -} - -// Convert_v1alpha1_MachineConfiguration_To_machine_MachineConfiguration is an autogenerated conversion function. -func Convert_v1alpha1_MachineConfiguration_To_machine_MachineConfiguration(in *MachineConfiguration, out *machine.MachineConfiguration, s conversion.Scope) error { - return autoConvert_v1alpha1_MachineConfiguration_To_machine_MachineConfiguration(in, out, s) -} - -func autoConvert_machine_MachineConfiguration_To_v1alpha1_MachineConfiguration(in *machine.MachineConfiguration, out *MachineConfiguration, s conversion.Scope) error { - out.MachineDrainTimeout = (*metav1.Duration)(unsafe.Pointer(in.MachineDrainTimeout)) - out.MachineHealthTimeout = (*metav1.Duration)(unsafe.Pointer(in.MachineHealthTimeout)) - out.MachineCreationTimeout = (*metav1.Duration)(unsafe.Pointer(in.MachineCreationTimeout)) - out.MachineInPlaceUpdateTimeout = (*metav1.Duration)(unsafe.Pointer(in.MachineInPlaceUpdateTimeout)) - out.MachinePreserveTimeout = (*metav1.Duration)(unsafe.Pointer(in.MachinePreserveTimeout)) - out.DisableHealthTimeout = (*bool)(unsafe.Pointer(in.DisableHealthTimeout)) - out.MaxEvictRetries = (*int32)(unsafe.Pointer(in.MaxEvictRetries)) - out.NodeConditions = (*string)(unsafe.Pointer(in.NodeConditions)) - return nil -} - -// Convert_machine_MachineConfiguration_To_v1alpha1_MachineConfiguration is an autogenerated conversion function. -func Convert_machine_MachineConfiguration_To_v1alpha1_MachineConfiguration(in *machine.MachineConfiguration, out *MachineConfiguration, s conversion.Scope) error { - return autoConvert_machine_MachineConfiguration_To_v1alpha1_MachineConfiguration(in, out, s) -} - -func autoConvert_v1alpha1_MachineDeployment_To_machine_MachineDeployment(in *MachineDeployment, out *machine.MachineDeployment, s conversion.Scope) error { - out.ObjectMeta = in.ObjectMeta - if err := Convert_v1alpha1_MachineDeploymentSpec_To_machine_MachineDeploymentSpec(&in.Spec, &out.Spec, s); err != nil { - return err - } - if err := Convert_v1alpha1_MachineDeploymentStatus_To_machine_MachineDeploymentStatus(&in.Status, &out.Status, s); err != nil { - return err - } - return nil -} - -// Convert_v1alpha1_MachineDeployment_To_machine_MachineDeployment is an autogenerated conversion function. -func Convert_v1alpha1_MachineDeployment_To_machine_MachineDeployment(in *MachineDeployment, out *machine.MachineDeployment, s conversion.Scope) error { - return autoConvert_v1alpha1_MachineDeployment_To_machine_MachineDeployment(in, out, s) -} - -func autoConvert_machine_MachineDeployment_To_v1alpha1_MachineDeployment(in *machine.MachineDeployment, out *MachineDeployment, s conversion.Scope) error { - out.ObjectMeta = in.ObjectMeta - if err := Convert_machine_MachineDeploymentSpec_To_v1alpha1_MachineDeploymentSpec(&in.Spec, &out.Spec, s); err != nil { - return err - } - if err := Convert_machine_MachineDeploymentStatus_To_v1alpha1_MachineDeploymentStatus(&in.Status, &out.Status, s); err != nil { - return err - } - return nil -} - -// Convert_machine_MachineDeployment_To_v1alpha1_MachineDeployment is an autogenerated conversion function. -func Convert_machine_MachineDeployment_To_v1alpha1_MachineDeployment(in *machine.MachineDeployment, out *MachineDeployment, s conversion.Scope) error { - return autoConvert_machine_MachineDeployment_To_v1alpha1_MachineDeployment(in, out, s) -} - -func autoConvert_v1alpha1_MachineDeploymentCondition_To_machine_MachineDeploymentCondition(in *MachineDeploymentCondition, out *machine.MachineDeploymentCondition, s conversion.Scope) error { - out.Type = machine.MachineDeploymentConditionType(in.Type) - out.Status = machine.ConditionStatus(in.Status) - out.LastUpdateTime = in.LastUpdateTime - out.LastTransitionTime = in.LastTransitionTime - out.Reason = in.Reason - out.Message = in.Message - return nil -} - -// Convert_v1alpha1_MachineDeploymentCondition_To_machine_MachineDeploymentCondition is an autogenerated conversion function. -func Convert_v1alpha1_MachineDeploymentCondition_To_machine_MachineDeploymentCondition(in *MachineDeploymentCondition, out *machine.MachineDeploymentCondition, s conversion.Scope) error { - return autoConvert_v1alpha1_MachineDeploymentCondition_To_machine_MachineDeploymentCondition(in, out, s) -} - -func autoConvert_machine_MachineDeploymentCondition_To_v1alpha1_MachineDeploymentCondition(in *machine.MachineDeploymentCondition, out *MachineDeploymentCondition, s conversion.Scope) error { - out.Type = MachineDeploymentConditionType(in.Type) - out.Status = ConditionStatus(in.Status) - out.LastUpdateTime = in.LastUpdateTime - out.LastTransitionTime = in.LastTransitionTime - out.Reason = in.Reason - out.Message = in.Message - return nil -} - -// Convert_machine_MachineDeploymentCondition_To_v1alpha1_MachineDeploymentCondition is an autogenerated conversion function. -func Convert_machine_MachineDeploymentCondition_To_v1alpha1_MachineDeploymentCondition(in *machine.MachineDeploymentCondition, out *MachineDeploymentCondition, s conversion.Scope) error { - return autoConvert_machine_MachineDeploymentCondition_To_v1alpha1_MachineDeploymentCondition(in, out, s) -} - -func autoConvert_v1alpha1_MachineDeploymentList_To_machine_MachineDeploymentList(in *MachineDeploymentList, out *machine.MachineDeploymentList, s conversion.Scope) error { - out.ListMeta = in.ListMeta - out.Items = *(*[]machine.MachineDeployment)(unsafe.Pointer(&in.Items)) - return nil -} - -// Convert_v1alpha1_MachineDeploymentList_To_machine_MachineDeploymentList is an autogenerated conversion function. -func Convert_v1alpha1_MachineDeploymentList_To_machine_MachineDeploymentList(in *MachineDeploymentList, out *machine.MachineDeploymentList, s conversion.Scope) error { - return autoConvert_v1alpha1_MachineDeploymentList_To_machine_MachineDeploymentList(in, out, s) -} - -func autoConvert_machine_MachineDeploymentList_To_v1alpha1_MachineDeploymentList(in *machine.MachineDeploymentList, out *MachineDeploymentList, s conversion.Scope) error { - out.ListMeta = in.ListMeta - out.Items = *(*[]MachineDeployment)(unsafe.Pointer(&in.Items)) - return nil -} - -// Convert_machine_MachineDeploymentList_To_v1alpha1_MachineDeploymentList is an autogenerated conversion function. -func Convert_machine_MachineDeploymentList_To_v1alpha1_MachineDeploymentList(in *machine.MachineDeploymentList, out *MachineDeploymentList, s conversion.Scope) error { - return autoConvert_machine_MachineDeploymentList_To_v1alpha1_MachineDeploymentList(in, out, s) -} - -func autoConvert_v1alpha1_MachineDeploymentSpec_To_machine_MachineDeploymentSpec(in *MachineDeploymentSpec, out *machine.MachineDeploymentSpec, s conversion.Scope) error { - out.Replicas = in.Replicas - out.Selector = (*metav1.LabelSelector)(unsafe.Pointer(in.Selector)) - if err := Convert_v1alpha1_MachineTemplateSpec_To_machine_MachineTemplateSpec(&in.Template, &out.Template, s); err != nil { - return err - } - if err := Convert_v1alpha1_MachineDeploymentStrategy_To_machine_MachineDeploymentStrategy(&in.Strategy, &out.Strategy, s); err != nil { - return err - } - out.MinReadySeconds = in.MinReadySeconds - out.RevisionHistoryLimit = (*int32)(unsafe.Pointer(in.RevisionHistoryLimit)) - out.Paused = in.Paused - out.RollbackTo = (*machine.RollbackConfig)(unsafe.Pointer(in.RollbackTo)) - out.ProgressDeadlineSeconds = (*int32)(unsafe.Pointer(in.ProgressDeadlineSeconds)) - out.AutoPreserveFailedMachineMax = in.AutoPreserveFailedMachineMax - return nil -} - -// Convert_v1alpha1_MachineDeploymentSpec_To_machine_MachineDeploymentSpec is an autogenerated conversion function. -func Convert_v1alpha1_MachineDeploymentSpec_To_machine_MachineDeploymentSpec(in *MachineDeploymentSpec, out *machine.MachineDeploymentSpec, s conversion.Scope) error { - return autoConvert_v1alpha1_MachineDeploymentSpec_To_machine_MachineDeploymentSpec(in, out, s) -} - -func autoConvert_machine_MachineDeploymentSpec_To_v1alpha1_MachineDeploymentSpec(in *machine.MachineDeploymentSpec, out *MachineDeploymentSpec, s conversion.Scope) error { - out.Replicas = in.Replicas - out.Selector = (*metav1.LabelSelector)(unsafe.Pointer(in.Selector)) - if err := Convert_machine_MachineTemplateSpec_To_v1alpha1_MachineTemplateSpec(&in.Template, &out.Template, s); err != nil { - return err - } - if err := Convert_machine_MachineDeploymentStrategy_To_v1alpha1_MachineDeploymentStrategy(&in.Strategy, &out.Strategy, s); err != nil { - return err - } - out.MinReadySeconds = in.MinReadySeconds - out.RevisionHistoryLimit = (*int32)(unsafe.Pointer(in.RevisionHistoryLimit)) - out.Paused = in.Paused - out.RollbackTo = (*RollbackConfig)(unsafe.Pointer(in.RollbackTo)) - out.ProgressDeadlineSeconds = (*int32)(unsafe.Pointer(in.ProgressDeadlineSeconds)) - out.AutoPreserveFailedMachineMax = in.AutoPreserveFailedMachineMax - return nil -} - -// Convert_machine_MachineDeploymentSpec_To_v1alpha1_MachineDeploymentSpec is an autogenerated conversion function. -func Convert_machine_MachineDeploymentSpec_To_v1alpha1_MachineDeploymentSpec(in *machine.MachineDeploymentSpec, out *MachineDeploymentSpec, s conversion.Scope) error { - return autoConvert_machine_MachineDeploymentSpec_To_v1alpha1_MachineDeploymentSpec(in, out, s) -} - -func autoConvert_v1alpha1_MachineDeploymentStatus_To_machine_MachineDeploymentStatus(in *MachineDeploymentStatus, out *machine.MachineDeploymentStatus, s conversion.Scope) error { - out.ObservedGeneration = in.ObservedGeneration - out.Replicas = in.Replicas - out.UpdatedReplicas = in.UpdatedReplicas - out.ReadyReplicas = in.ReadyReplicas - out.AvailableReplicas = in.AvailableReplicas - out.UnavailableReplicas = in.UnavailableReplicas - out.Conditions = *(*[]machine.MachineDeploymentCondition)(unsafe.Pointer(&in.Conditions)) - out.CollisionCount = (*int32)(unsafe.Pointer(in.CollisionCount)) - out.FailedMachines = *(*[]*machine.MachineSummary)(unsafe.Pointer(&in.FailedMachines)) - return nil -} - -// Convert_v1alpha1_MachineDeploymentStatus_To_machine_MachineDeploymentStatus is an autogenerated conversion function. -func Convert_v1alpha1_MachineDeploymentStatus_To_machine_MachineDeploymentStatus(in *MachineDeploymentStatus, out *machine.MachineDeploymentStatus, s conversion.Scope) error { - return autoConvert_v1alpha1_MachineDeploymentStatus_To_machine_MachineDeploymentStatus(in, out, s) -} - -func autoConvert_machine_MachineDeploymentStatus_To_v1alpha1_MachineDeploymentStatus(in *machine.MachineDeploymentStatus, out *MachineDeploymentStatus, s conversion.Scope) error { - out.ObservedGeneration = in.ObservedGeneration - out.Replicas = in.Replicas - out.UpdatedReplicas = in.UpdatedReplicas - out.ReadyReplicas = in.ReadyReplicas - out.AvailableReplicas = in.AvailableReplicas - out.UnavailableReplicas = in.UnavailableReplicas - out.Conditions = *(*[]MachineDeploymentCondition)(unsafe.Pointer(&in.Conditions)) - out.CollisionCount = (*int32)(unsafe.Pointer(in.CollisionCount)) - out.FailedMachines = *(*[]*MachineSummary)(unsafe.Pointer(&in.FailedMachines)) - return nil -} - -// Convert_machine_MachineDeploymentStatus_To_v1alpha1_MachineDeploymentStatus is an autogenerated conversion function. -func Convert_machine_MachineDeploymentStatus_To_v1alpha1_MachineDeploymentStatus(in *machine.MachineDeploymentStatus, out *MachineDeploymentStatus, s conversion.Scope) error { - return autoConvert_machine_MachineDeploymentStatus_To_v1alpha1_MachineDeploymentStatus(in, out, s) -} - -func autoConvert_v1alpha1_MachineDeploymentStrategy_To_machine_MachineDeploymentStrategy(in *MachineDeploymentStrategy, out *machine.MachineDeploymentStrategy, s conversion.Scope) error { - out.Type = machine.MachineDeploymentStrategyType(in.Type) - out.RollingUpdate = (*machine.RollingUpdateMachineDeployment)(unsafe.Pointer(in.RollingUpdate)) - out.InPlaceUpdate = (*machine.InPlaceUpdateMachineDeployment)(unsafe.Pointer(in.InPlaceUpdate)) - return nil -} - -// Convert_v1alpha1_MachineDeploymentStrategy_To_machine_MachineDeploymentStrategy is an autogenerated conversion function. -func Convert_v1alpha1_MachineDeploymentStrategy_To_machine_MachineDeploymentStrategy(in *MachineDeploymentStrategy, out *machine.MachineDeploymentStrategy, s conversion.Scope) error { - return autoConvert_v1alpha1_MachineDeploymentStrategy_To_machine_MachineDeploymentStrategy(in, out, s) -} - -func autoConvert_machine_MachineDeploymentStrategy_To_v1alpha1_MachineDeploymentStrategy(in *machine.MachineDeploymentStrategy, out *MachineDeploymentStrategy, s conversion.Scope) error { - out.Type = MachineDeploymentStrategyType(in.Type) - out.RollingUpdate = (*RollingUpdateMachineDeployment)(unsafe.Pointer(in.RollingUpdate)) - out.InPlaceUpdate = (*InPlaceUpdateMachineDeployment)(unsafe.Pointer(in.InPlaceUpdate)) - return nil -} - -// Convert_machine_MachineDeploymentStrategy_To_v1alpha1_MachineDeploymentStrategy is an autogenerated conversion function. -func Convert_machine_MachineDeploymentStrategy_To_v1alpha1_MachineDeploymentStrategy(in *machine.MachineDeploymentStrategy, out *MachineDeploymentStrategy, s conversion.Scope) error { - return autoConvert_machine_MachineDeploymentStrategy_To_v1alpha1_MachineDeploymentStrategy(in, out, s) -} - -func autoConvert_v1alpha1_MachineList_To_machine_MachineList(in *MachineList, out *machine.MachineList, s conversion.Scope) error { - out.ListMeta = in.ListMeta - out.Items = *(*[]machine.Machine)(unsafe.Pointer(&in.Items)) - return nil -} - -// Convert_v1alpha1_MachineList_To_machine_MachineList is an autogenerated conversion function. -func Convert_v1alpha1_MachineList_To_machine_MachineList(in *MachineList, out *machine.MachineList, s conversion.Scope) error { - return autoConvert_v1alpha1_MachineList_To_machine_MachineList(in, out, s) -} - -func autoConvert_machine_MachineList_To_v1alpha1_MachineList(in *machine.MachineList, out *MachineList, s conversion.Scope) error { - out.ListMeta = in.ListMeta - out.Items = *(*[]Machine)(unsafe.Pointer(&in.Items)) - return nil -} - -// Convert_machine_MachineList_To_v1alpha1_MachineList is an autogenerated conversion function. -func Convert_machine_MachineList_To_v1alpha1_MachineList(in *machine.MachineList, out *MachineList, s conversion.Scope) error { - return autoConvert_machine_MachineList_To_v1alpha1_MachineList(in, out, s) -} - -func autoConvert_v1alpha1_MachineSet_To_machine_MachineSet(in *MachineSet, out *machine.MachineSet, s conversion.Scope) error { - out.ObjectMeta = in.ObjectMeta - if err := Convert_v1alpha1_MachineSetSpec_To_machine_MachineSetSpec(&in.Spec, &out.Spec, s); err != nil { - return err - } - if err := Convert_v1alpha1_MachineSetStatus_To_machine_MachineSetStatus(&in.Status, &out.Status, s); err != nil { - return err - } - return nil -} - -// Convert_v1alpha1_MachineSet_To_machine_MachineSet is an autogenerated conversion function. -func Convert_v1alpha1_MachineSet_To_machine_MachineSet(in *MachineSet, out *machine.MachineSet, s conversion.Scope) error { - return autoConvert_v1alpha1_MachineSet_To_machine_MachineSet(in, out, s) -} - -func autoConvert_machine_MachineSet_To_v1alpha1_MachineSet(in *machine.MachineSet, out *MachineSet, s conversion.Scope) error { - out.ObjectMeta = in.ObjectMeta - if err := Convert_machine_MachineSetSpec_To_v1alpha1_MachineSetSpec(&in.Spec, &out.Spec, s); err != nil { - return err - } - if err := Convert_machine_MachineSetStatus_To_v1alpha1_MachineSetStatus(&in.Status, &out.Status, s); err != nil { - return err - } - return nil -} - -// Convert_machine_MachineSet_To_v1alpha1_MachineSet is an autogenerated conversion function. -func Convert_machine_MachineSet_To_v1alpha1_MachineSet(in *machine.MachineSet, out *MachineSet, s conversion.Scope) error { - return autoConvert_machine_MachineSet_To_v1alpha1_MachineSet(in, out, s) -} - -func autoConvert_v1alpha1_MachineSetCondition_To_machine_MachineSetCondition(in *MachineSetCondition, out *machine.MachineSetCondition, s conversion.Scope) error { - out.Type = machine.MachineSetConditionType(in.Type) - out.Status = machine.ConditionStatus(in.Status) - out.LastTransitionTime = in.LastTransitionTime - out.Reason = in.Reason - out.Message = in.Message - return nil -} - -// Convert_v1alpha1_MachineSetCondition_To_machine_MachineSetCondition is an autogenerated conversion function. -func Convert_v1alpha1_MachineSetCondition_To_machine_MachineSetCondition(in *MachineSetCondition, out *machine.MachineSetCondition, s conversion.Scope) error { - return autoConvert_v1alpha1_MachineSetCondition_To_machine_MachineSetCondition(in, out, s) -} - -func autoConvert_machine_MachineSetCondition_To_v1alpha1_MachineSetCondition(in *machine.MachineSetCondition, out *MachineSetCondition, s conversion.Scope) error { - out.Type = MachineSetConditionType(in.Type) - out.Status = ConditionStatus(in.Status) - out.LastTransitionTime = in.LastTransitionTime - out.Reason = in.Reason - out.Message = in.Message - return nil -} - -// Convert_machine_MachineSetCondition_To_v1alpha1_MachineSetCondition is an autogenerated conversion function. -func Convert_machine_MachineSetCondition_To_v1alpha1_MachineSetCondition(in *machine.MachineSetCondition, out *MachineSetCondition, s conversion.Scope) error { - return autoConvert_machine_MachineSetCondition_To_v1alpha1_MachineSetCondition(in, out, s) -} - -func autoConvert_v1alpha1_MachineSetList_To_machine_MachineSetList(in *MachineSetList, out *machine.MachineSetList, s conversion.Scope) error { - out.ListMeta = in.ListMeta - out.Items = *(*[]machine.MachineSet)(unsafe.Pointer(&in.Items)) - return nil -} - -// Convert_v1alpha1_MachineSetList_To_machine_MachineSetList is an autogenerated conversion function. -func Convert_v1alpha1_MachineSetList_To_machine_MachineSetList(in *MachineSetList, out *machine.MachineSetList, s conversion.Scope) error { - return autoConvert_v1alpha1_MachineSetList_To_machine_MachineSetList(in, out, s) -} - -func autoConvert_machine_MachineSetList_To_v1alpha1_MachineSetList(in *machine.MachineSetList, out *MachineSetList, s conversion.Scope) error { - out.ListMeta = in.ListMeta - out.Items = *(*[]MachineSet)(unsafe.Pointer(&in.Items)) - return nil -} - -// Convert_machine_MachineSetList_To_v1alpha1_MachineSetList is an autogenerated conversion function. -func Convert_machine_MachineSetList_To_v1alpha1_MachineSetList(in *machine.MachineSetList, out *MachineSetList, s conversion.Scope) error { - return autoConvert_machine_MachineSetList_To_v1alpha1_MachineSetList(in, out, s) -} - -func autoConvert_v1alpha1_MachineSetSpec_To_machine_MachineSetSpec(in *MachineSetSpec, out *machine.MachineSetSpec, s conversion.Scope) error { - out.Replicas = in.Replicas - out.Selector = (*metav1.LabelSelector)(unsafe.Pointer(in.Selector)) - if err := Convert_v1alpha1_ClassSpec_To_machine_ClassSpec(&in.MachineClass, &out.MachineClass, s); err != nil { - return err - } - if err := Convert_v1alpha1_MachineTemplateSpec_To_machine_MachineTemplateSpec(&in.Template, &out.Template, s); err != nil { - return err - } - out.MinReadySeconds = in.MinReadySeconds - out.AutoPreserveFailedMachineMax = in.AutoPreserveFailedMachineMax - return nil -} - -// Convert_v1alpha1_MachineSetSpec_To_machine_MachineSetSpec is an autogenerated conversion function. -func Convert_v1alpha1_MachineSetSpec_To_machine_MachineSetSpec(in *MachineSetSpec, out *machine.MachineSetSpec, s conversion.Scope) error { - return autoConvert_v1alpha1_MachineSetSpec_To_machine_MachineSetSpec(in, out, s) -} - -func autoConvert_machine_MachineSetSpec_To_v1alpha1_MachineSetSpec(in *machine.MachineSetSpec, out *MachineSetSpec, s conversion.Scope) error { - out.Replicas = in.Replicas - out.Selector = (*metav1.LabelSelector)(unsafe.Pointer(in.Selector)) - if err := Convert_machine_ClassSpec_To_v1alpha1_ClassSpec(&in.MachineClass, &out.MachineClass, s); err != nil { - return err - } - if err := Convert_machine_MachineTemplateSpec_To_v1alpha1_MachineTemplateSpec(&in.Template, &out.Template, s); err != nil { - return err - } - out.MinReadySeconds = in.MinReadySeconds - out.AutoPreserveFailedMachineMax = in.AutoPreserveFailedMachineMax - return nil -} - -// Convert_machine_MachineSetSpec_To_v1alpha1_MachineSetSpec is an autogenerated conversion function. -func Convert_machine_MachineSetSpec_To_v1alpha1_MachineSetSpec(in *machine.MachineSetSpec, out *MachineSetSpec, s conversion.Scope) error { - return autoConvert_machine_MachineSetSpec_To_v1alpha1_MachineSetSpec(in, out, s) -} - -func autoConvert_v1alpha1_MachineSetStatus_To_machine_MachineSetStatus(in *MachineSetStatus, out *machine.MachineSetStatus, s conversion.Scope) error { - out.Replicas = in.Replicas - out.FullyLabeledReplicas = in.FullyLabeledReplicas - out.ReadyReplicas = in.ReadyReplicas - out.AvailableReplicas = in.AvailableReplicas - out.ObservedGeneration = in.ObservedGeneration - out.Conditions = *(*[]machine.MachineSetCondition)(unsafe.Pointer(&in.Conditions)) - if err := Convert_v1alpha1_LastOperation_To_machine_LastOperation(&in.LastOperation, &out.LastOperation, s); err != nil { - return err - } - out.FailedMachines = (*[]machine.MachineSummary)(unsafe.Pointer(in.FailedMachines)) - out.AutoPreserveFailedMachineCount = in.AutoPreserveFailedMachineCount - return nil -} - -// Convert_v1alpha1_MachineSetStatus_To_machine_MachineSetStatus is an autogenerated conversion function. -func Convert_v1alpha1_MachineSetStatus_To_machine_MachineSetStatus(in *MachineSetStatus, out *machine.MachineSetStatus, s conversion.Scope) error { - return autoConvert_v1alpha1_MachineSetStatus_To_machine_MachineSetStatus(in, out, s) -} - -func autoConvert_machine_MachineSetStatus_To_v1alpha1_MachineSetStatus(in *machine.MachineSetStatus, out *MachineSetStatus, s conversion.Scope) error { - out.Replicas = in.Replicas - out.FullyLabeledReplicas = in.FullyLabeledReplicas - out.ReadyReplicas = in.ReadyReplicas - out.AvailableReplicas = in.AvailableReplicas - out.ObservedGeneration = in.ObservedGeneration - out.Conditions = *(*[]MachineSetCondition)(unsafe.Pointer(&in.Conditions)) - if err := Convert_machine_LastOperation_To_v1alpha1_LastOperation(&in.LastOperation, &out.LastOperation, s); err != nil { - return err - } - out.FailedMachines = (*[]MachineSummary)(unsafe.Pointer(in.FailedMachines)) - out.AutoPreserveFailedMachineCount = in.AutoPreserveFailedMachineCount - return nil -} - -// Convert_machine_MachineSetStatus_To_v1alpha1_MachineSetStatus is an autogenerated conversion function. -func Convert_machine_MachineSetStatus_To_v1alpha1_MachineSetStatus(in *machine.MachineSetStatus, out *MachineSetStatus, s conversion.Scope) error { - return autoConvert_machine_MachineSetStatus_To_v1alpha1_MachineSetStatus(in, out, s) -} - -func autoConvert_v1alpha1_MachineSpec_To_machine_MachineSpec(in *MachineSpec, out *machine.MachineSpec, s conversion.Scope) error { - if err := Convert_v1alpha1_ClassSpec_To_machine_ClassSpec(&in.Class, &out.Class, s); err != nil { - return err - } - out.ProviderID = in.ProviderID - if err := Convert_v1alpha1_NodeTemplateSpec_To_machine_NodeTemplateSpec(&in.NodeTemplateSpec, &out.NodeTemplateSpec, s); err != nil { - return err - } - out.MachineConfiguration = (*machine.MachineConfiguration)(unsafe.Pointer(in.MachineConfiguration)) - return nil -} - -// Convert_v1alpha1_MachineSpec_To_machine_MachineSpec is an autogenerated conversion function. -func Convert_v1alpha1_MachineSpec_To_machine_MachineSpec(in *MachineSpec, out *machine.MachineSpec, s conversion.Scope) error { - return autoConvert_v1alpha1_MachineSpec_To_machine_MachineSpec(in, out, s) -} - -func autoConvert_machine_MachineSpec_To_v1alpha1_MachineSpec(in *machine.MachineSpec, out *MachineSpec, s conversion.Scope) error { - if err := Convert_machine_ClassSpec_To_v1alpha1_ClassSpec(&in.Class, &out.Class, s); err != nil { - return err - } - out.ProviderID = in.ProviderID - if err := Convert_machine_NodeTemplateSpec_To_v1alpha1_NodeTemplateSpec(&in.NodeTemplateSpec, &out.NodeTemplateSpec, s); err != nil { - return err - } - out.MachineConfiguration = (*MachineConfiguration)(unsafe.Pointer(in.MachineConfiguration)) - return nil -} - -// Convert_machine_MachineSpec_To_v1alpha1_MachineSpec is an autogenerated conversion function. -func Convert_machine_MachineSpec_To_v1alpha1_MachineSpec(in *machine.MachineSpec, out *MachineSpec, s conversion.Scope) error { - return autoConvert_machine_MachineSpec_To_v1alpha1_MachineSpec(in, out, s) -} - -func autoConvert_v1alpha1_MachineStatus_To_machine_MachineStatus(in *MachineStatus, out *machine.MachineStatus, s conversion.Scope) error { - out.Addresses = *(*[]v1.NodeAddress)(unsafe.Pointer(&in.Addresses)) - out.Conditions = *(*[]v1.NodeCondition)(unsafe.Pointer(&in.Conditions)) - if err := Convert_v1alpha1_LastOperation_To_machine_LastOperation(&in.LastOperation, &out.LastOperation, s); err != nil { - return err - } - if err := Convert_v1alpha1_CurrentStatus_To_machine_CurrentStatus(&in.CurrentStatus, &out.CurrentStatus, s); err != nil { - return err - } - out.LastKnownState = in.LastKnownState - return nil -} - -// Convert_v1alpha1_MachineStatus_To_machine_MachineStatus is an autogenerated conversion function. -func Convert_v1alpha1_MachineStatus_To_machine_MachineStatus(in *MachineStatus, out *machine.MachineStatus, s conversion.Scope) error { - return autoConvert_v1alpha1_MachineStatus_To_machine_MachineStatus(in, out, s) -} - -func autoConvert_machine_MachineStatus_To_v1alpha1_MachineStatus(in *machine.MachineStatus, out *MachineStatus, s conversion.Scope) error { - out.Addresses = *(*[]v1.NodeAddress)(unsafe.Pointer(&in.Addresses)) - out.Conditions = *(*[]v1.NodeCondition)(unsafe.Pointer(&in.Conditions)) - if err := Convert_machine_LastOperation_To_v1alpha1_LastOperation(&in.LastOperation, &out.LastOperation, s); err != nil { - return err - } - if err := Convert_machine_CurrentStatus_To_v1alpha1_CurrentStatus(&in.CurrentStatus, &out.CurrentStatus, s); err != nil { - return err - } - out.LastKnownState = in.LastKnownState - return nil -} - -// Convert_machine_MachineStatus_To_v1alpha1_MachineStatus is an autogenerated conversion function. -func Convert_machine_MachineStatus_To_v1alpha1_MachineStatus(in *machine.MachineStatus, out *MachineStatus, s conversion.Scope) error { - return autoConvert_machine_MachineStatus_To_v1alpha1_MachineStatus(in, out, s) -} - -func autoConvert_v1alpha1_MachineSummary_To_machine_MachineSummary(in *MachineSummary, out *machine.MachineSummary, s conversion.Scope) error { - out.Name = in.Name - out.ProviderID = in.ProviderID - if err := Convert_v1alpha1_LastOperation_To_machine_LastOperation(&in.LastOperation, &out.LastOperation, s); err != nil { - return err - } - out.OwnerRef = in.OwnerRef - return nil -} - -// Convert_v1alpha1_MachineSummary_To_machine_MachineSummary is an autogenerated conversion function. -func Convert_v1alpha1_MachineSummary_To_machine_MachineSummary(in *MachineSummary, out *machine.MachineSummary, s conversion.Scope) error { - return autoConvert_v1alpha1_MachineSummary_To_machine_MachineSummary(in, out, s) -} - -func autoConvert_machine_MachineSummary_To_v1alpha1_MachineSummary(in *machine.MachineSummary, out *MachineSummary, s conversion.Scope) error { - out.Name = in.Name - out.ProviderID = in.ProviderID - if err := Convert_machine_LastOperation_To_v1alpha1_LastOperation(&in.LastOperation, &out.LastOperation, s); err != nil { - return err - } - out.OwnerRef = in.OwnerRef - return nil -} - -// Convert_machine_MachineSummary_To_v1alpha1_MachineSummary is an autogenerated conversion function. -func Convert_machine_MachineSummary_To_v1alpha1_MachineSummary(in *machine.MachineSummary, out *MachineSummary, s conversion.Scope) error { - return autoConvert_machine_MachineSummary_To_v1alpha1_MachineSummary(in, out, s) -} - -func autoConvert_v1alpha1_MachineTemplateSpec_To_machine_MachineTemplateSpec(in *MachineTemplateSpec, out *machine.MachineTemplateSpec, s conversion.Scope) error { - out.ObjectMeta = in.ObjectMeta - if err := Convert_v1alpha1_MachineSpec_To_machine_MachineSpec(&in.Spec, &out.Spec, s); err != nil { - return err - } - return nil -} - -// Convert_v1alpha1_MachineTemplateSpec_To_machine_MachineTemplateSpec is an autogenerated conversion function. -func Convert_v1alpha1_MachineTemplateSpec_To_machine_MachineTemplateSpec(in *MachineTemplateSpec, out *machine.MachineTemplateSpec, s conversion.Scope) error { - return autoConvert_v1alpha1_MachineTemplateSpec_To_machine_MachineTemplateSpec(in, out, s) -} - -func autoConvert_machine_MachineTemplateSpec_To_v1alpha1_MachineTemplateSpec(in *machine.MachineTemplateSpec, out *MachineTemplateSpec, s conversion.Scope) error { - out.ObjectMeta = in.ObjectMeta - if err := Convert_machine_MachineSpec_To_v1alpha1_MachineSpec(&in.Spec, &out.Spec, s); err != nil { - return err - } - return nil -} - -// Convert_machine_MachineTemplateSpec_To_v1alpha1_MachineTemplateSpec is an autogenerated conversion function. -func Convert_machine_MachineTemplateSpec_To_v1alpha1_MachineTemplateSpec(in *machine.MachineTemplateSpec, out *MachineTemplateSpec, s conversion.Scope) error { - return autoConvert_machine_MachineTemplateSpec_To_v1alpha1_MachineTemplateSpec(in, out, s) -} - -func autoConvert_v1alpha1_NodeTemplate_To_machine_NodeTemplate(in *NodeTemplate, out *machine.NodeTemplate, s conversion.Scope) error { - out.Capacity = *(*v1.ResourceList)(unsafe.Pointer(&in.Capacity)) - out.VirtualCapacity = *(*v1.ResourceList)(unsafe.Pointer(&in.VirtualCapacity)) - out.InstanceType = in.InstanceType - out.Region = in.Region - out.Zone = in.Zone - out.Architecture = (*string)(unsafe.Pointer(in.Architecture)) - return nil -} - -// Convert_v1alpha1_NodeTemplate_To_machine_NodeTemplate is an autogenerated conversion function. -func Convert_v1alpha1_NodeTemplate_To_machine_NodeTemplate(in *NodeTemplate, out *machine.NodeTemplate, s conversion.Scope) error { - return autoConvert_v1alpha1_NodeTemplate_To_machine_NodeTemplate(in, out, s) -} - -func autoConvert_machine_NodeTemplate_To_v1alpha1_NodeTemplate(in *machine.NodeTemplate, out *NodeTemplate, s conversion.Scope) error { - out.Capacity = *(*v1.ResourceList)(unsafe.Pointer(&in.Capacity)) - out.VirtualCapacity = *(*v1.ResourceList)(unsafe.Pointer(&in.VirtualCapacity)) - out.InstanceType = in.InstanceType - out.Region = in.Region - out.Zone = in.Zone - out.Architecture = (*string)(unsafe.Pointer(in.Architecture)) - return nil -} - -// Convert_machine_NodeTemplate_To_v1alpha1_NodeTemplate is an autogenerated conversion function. -func Convert_machine_NodeTemplate_To_v1alpha1_NodeTemplate(in *machine.NodeTemplate, out *NodeTemplate, s conversion.Scope) error { - return autoConvert_machine_NodeTemplate_To_v1alpha1_NodeTemplate(in, out, s) -} - -func autoConvert_v1alpha1_NodeTemplateSpec_To_machine_NodeTemplateSpec(in *NodeTemplateSpec, out *machine.NodeTemplateSpec, s conversion.Scope) error { - out.ObjectMeta = in.ObjectMeta - out.Spec = in.Spec - return nil -} - -// Convert_v1alpha1_NodeTemplateSpec_To_machine_NodeTemplateSpec is an autogenerated conversion function. -func Convert_v1alpha1_NodeTemplateSpec_To_machine_NodeTemplateSpec(in *NodeTemplateSpec, out *machine.NodeTemplateSpec, s conversion.Scope) error { - return autoConvert_v1alpha1_NodeTemplateSpec_To_machine_NodeTemplateSpec(in, out, s) -} - -func autoConvert_machine_NodeTemplateSpec_To_v1alpha1_NodeTemplateSpec(in *machine.NodeTemplateSpec, out *NodeTemplateSpec, s conversion.Scope) error { - out.ObjectMeta = in.ObjectMeta - out.Spec = in.Spec - return nil -} - -// Convert_machine_NodeTemplateSpec_To_v1alpha1_NodeTemplateSpec is an autogenerated conversion function. -func Convert_machine_NodeTemplateSpec_To_v1alpha1_NodeTemplateSpec(in *machine.NodeTemplateSpec, out *NodeTemplateSpec, s conversion.Scope) error { - return autoConvert_machine_NodeTemplateSpec_To_v1alpha1_NodeTemplateSpec(in, out, s) -} - -func autoConvert_v1alpha1_RollbackConfig_To_machine_RollbackConfig(in *RollbackConfig, out *machine.RollbackConfig, s conversion.Scope) error { - out.Revision = in.Revision - return nil -} - -// Convert_v1alpha1_RollbackConfig_To_machine_RollbackConfig is an autogenerated conversion function. -func Convert_v1alpha1_RollbackConfig_To_machine_RollbackConfig(in *RollbackConfig, out *machine.RollbackConfig, s conversion.Scope) error { - return autoConvert_v1alpha1_RollbackConfig_To_machine_RollbackConfig(in, out, s) -} - -func autoConvert_machine_RollbackConfig_To_v1alpha1_RollbackConfig(in *machine.RollbackConfig, out *RollbackConfig, s conversion.Scope) error { - out.Revision = in.Revision - return nil -} - -// Convert_machine_RollbackConfig_To_v1alpha1_RollbackConfig is an autogenerated conversion function. -func Convert_machine_RollbackConfig_To_v1alpha1_RollbackConfig(in *machine.RollbackConfig, out *RollbackConfig, s conversion.Scope) error { - return autoConvert_machine_RollbackConfig_To_v1alpha1_RollbackConfig(in, out, s) -} - -func autoConvert_v1alpha1_RollingUpdateMachineDeployment_To_machine_RollingUpdateMachineDeployment(in *RollingUpdateMachineDeployment, out *machine.RollingUpdateMachineDeployment, s conversion.Scope) error { - if err := Convert_v1alpha1_UpdateConfiguration_To_machine_UpdateConfiguration(&in.UpdateConfiguration, &out.UpdateConfiguration, s); err != nil { - return err - } - return nil -} - -// Convert_v1alpha1_RollingUpdateMachineDeployment_To_machine_RollingUpdateMachineDeployment is an autogenerated conversion function. -func Convert_v1alpha1_RollingUpdateMachineDeployment_To_machine_RollingUpdateMachineDeployment(in *RollingUpdateMachineDeployment, out *machine.RollingUpdateMachineDeployment, s conversion.Scope) error { - return autoConvert_v1alpha1_RollingUpdateMachineDeployment_To_machine_RollingUpdateMachineDeployment(in, out, s) -} - -func autoConvert_machine_RollingUpdateMachineDeployment_To_v1alpha1_RollingUpdateMachineDeployment(in *machine.RollingUpdateMachineDeployment, out *RollingUpdateMachineDeployment, s conversion.Scope) error { - if err := Convert_machine_UpdateConfiguration_To_v1alpha1_UpdateConfiguration(&in.UpdateConfiguration, &out.UpdateConfiguration, s); err != nil { - return err - } - return nil -} - -// Convert_machine_RollingUpdateMachineDeployment_To_v1alpha1_RollingUpdateMachineDeployment is an autogenerated conversion function. -func Convert_machine_RollingUpdateMachineDeployment_To_v1alpha1_RollingUpdateMachineDeployment(in *machine.RollingUpdateMachineDeployment, out *RollingUpdateMachineDeployment, s conversion.Scope) error { - return autoConvert_machine_RollingUpdateMachineDeployment_To_v1alpha1_RollingUpdateMachineDeployment(in, out, s) -} - -func autoConvert_v1alpha1_UpdateConfiguration_To_machine_UpdateConfiguration(in *UpdateConfiguration, out *machine.UpdateConfiguration, s conversion.Scope) error { - out.MaxUnavailable = (*intstr.IntOrString)(unsafe.Pointer(in.MaxUnavailable)) - out.MaxSurge = (*intstr.IntOrString)(unsafe.Pointer(in.MaxSurge)) - return nil -} - -// Convert_v1alpha1_UpdateConfiguration_To_machine_UpdateConfiguration is an autogenerated conversion function. -func Convert_v1alpha1_UpdateConfiguration_To_machine_UpdateConfiguration(in *UpdateConfiguration, out *machine.UpdateConfiguration, s conversion.Scope) error { - return autoConvert_v1alpha1_UpdateConfiguration_To_machine_UpdateConfiguration(in, out, s) -} - -func autoConvert_machine_UpdateConfiguration_To_v1alpha1_UpdateConfiguration(in *machine.UpdateConfiguration, out *UpdateConfiguration, s conversion.Scope) error { - out.MaxUnavailable = (*intstr.IntOrString)(unsafe.Pointer(in.MaxUnavailable)) - out.MaxSurge = (*intstr.IntOrString)(unsafe.Pointer(in.MaxSurge)) - return nil -} - -// Convert_machine_UpdateConfiguration_To_v1alpha1_UpdateConfiguration is an autogenerated conversion function. -func Convert_machine_UpdateConfiguration_To_v1alpha1_UpdateConfiguration(in *machine.UpdateConfiguration, out *UpdateConfiguration, s conversion.Scope) error { - return autoConvert_machine_UpdateConfiguration_To_v1alpha1_UpdateConfiguration(in, out, s) -} diff --git a/pkg/apis/machine/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/machine/v1alpha1/zz_generated.deepcopy.go deleted file mode 100644 index 13aab59e2..000000000 --- a/pkg/apis/machine/v1alpha1/zz_generated.deepcopy.go +++ /dev/null @@ -1,795 +0,0 @@ -//go:build !ignore_autogenerated -// +build !ignore_autogenerated - -// SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors -// -// SPDX-License-Identifier: Apache-2.0 - -// Code generated by deepcopy-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" - intstr "k8s.io/apimachinery/pkg/util/intstr" -) - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ClassSpec) DeepCopyInto(out *ClassSpec) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClassSpec. -func (in *ClassSpec) DeepCopy() *ClassSpec { - if in == nil { - return nil - } - out := new(ClassSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *CurrentStatus) DeepCopyInto(out *CurrentStatus) { - *out = *in - in.LastUpdateTime.DeepCopyInto(&out.LastUpdateTime) - in.PreserveExpiryTime.DeepCopyInto(&out.PreserveExpiryTime) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CurrentStatus. -func (in *CurrentStatus) DeepCopy() *CurrentStatus { - if in == nil { - return nil - } - out := new(CurrentStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InPlaceUpdateMachineDeployment) DeepCopyInto(out *InPlaceUpdateMachineDeployment) { - *out = *in - in.UpdateConfiguration.DeepCopyInto(&out.UpdateConfiguration) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InPlaceUpdateMachineDeployment. -func (in *InPlaceUpdateMachineDeployment) DeepCopy() *InPlaceUpdateMachineDeployment { - if in == nil { - return nil - } - out := new(InPlaceUpdateMachineDeployment) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *LastOperation) DeepCopyInto(out *LastOperation) { - *out = *in - in.LastUpdateTime.DeepCopyInto(&out.LastUpdateTime) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LastOperation. -func (in *LastOperation) DeepCopy() *LastOperation { - if in == nil { - return nil - } - out := new(LastOperation) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Machine) DeepCopyInto(out *Machine) { - *out = *in - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - out.TypeMeta = in.TypeMeta - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Machine. -func (in *Machine) DeepCopy() *Machine { - if in == nil { - return nil - } - out := new(Machine) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *Machine) 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 *MachineClass) DeepCopyInto(out *MachineClass) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - if in.NodeTemplate != nil { - in, out := &in.NodeTemplate, &out.NodeTemplate - *out = new(NodeTemplate) - (*in).DeepCopyInto(*out) - } - if in.CredentialsSecretRef != nil { - in, out := &in.CredentialsSecretRef, &out.CredentialsSecretRef - *out = new(v1.SecretReference) - **out = **in - } - in.ProviderSpec.DeepCopyInto(&out.ProviderSpec) - if in.SecretRef != nil { - in, out := &in.SecretRef, &out.SecretRef - *out = new(v1.SecretReference) - **out = **in - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineClass. -func (in *MachineClass) DeepCopy() *MachineClass { - if in == nil { - return nil - } - out := new(MachineClass) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *MachineClass) 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 *MachineClassList) DeepCopyInto(out *MachineClassList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]MachineClass, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineClassList. -func (in *MachineClassList) DeepCopy() *MachineClassList { - if in == nil { - return nil - } - out := new(MachineClassList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *MachineClassList) 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 *MachineConfiguration) DeepCopyInto(out *MachineConfiguration) { - *out = *in - if in.MachineDrainTimeout != nil { - in, out := &in.MachineDrainTimeout, &out.MachineDrainTimeout - *out = new(metav1.Duration) - **out = **in - } - if in.MachineHealthTimeout != nil { - in, out := &in.MachineHealthTimeout, &out.MachineHealthTimeout - *out = new(metav1.Duration) - **out = **in - } - if in.MachineCreationTimeout != nil { - in, out := &in.MachineCreationTimeout, &out.MachineCreationTimeout - *out = new(metav1.Duration) - **out = **in - } - if in.MachineInPlaceUpdateTimeout != nil { - in, out := &in.MachineInPlaceUpdateTimeout, &out.MachineInPlaceUpdateTimeout - *out = new(metav1.Duration) - **out = **in - } - if in.MachinePreserveTimeout != nil { - in, out := &in.MachinePreserveTimeout, &out.MachinePreserveTimeout - *out = new(metav1.Duration) - **out = **in - } - if in.DisableHealthTimeout != nil { - in, out := &in.DisableHealthTimeout, &out.DisableHealthTimeout - *out = new(bool) - **out = **in - } - if in.MaxEvictRetries != nil { - in, out := &in.MaxEvictRetries, &out.MaxEvictRetries - *out = new(int32) - **out = **in - } - if in.NodeConditions != nil { - in, out := &in.NodeConditions, &out.NodeConditions - *out = new(string) - **out = **in - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineConfiguration. -func (in *MachineConfiguration) DeepCopy() *MachineConfiguration { - if in == nil { - return nil - } - out := new(MachineConfiguration) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MachineDeployment) DeepCopyInto(out *MachineDeployment) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineDeployment. -func (in *MachineDeployment) DeepCopy() *MachineDeployment { - if in == nil { - return nil - } - out := new(MachineDeployment) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *MachineDeployment) 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 *MachineDeploymentCondition) DeepCopyInto(out *MachineDeploymentCondition) { - *out = *in - in.LastUpdateTime.DeepCopyInto(&out.LastUpdateTime) - in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineDeploymentCondition. -func (in *MachineDeploymentCondition) DeepCopy() *MachineDeploymentCondition { - if in == nil { - return nil - } - out := new(MachineDeploymentCondition) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MachineDeploymentList) DeepCopyInto(out *MachineDeploymentList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]MachineDeployment, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineDeploymentList. -func (in *MachineDeploymentList) DeepCopy() *MachineDeploymentList { - if in == nil { - return nil - } - out := new(MachineDeploymentList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *MachineDeploymentList) 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 *MachineDeploymentSpec) DeepCopyInto(out *MachineDeploymentSpec) { - *out = *in - if in.Selector != nil { - in, out := &in.Selector, &out.Selector - *out = new(metav1.LabelSelector) - (*in).DeepCopyInto(*out) - } - in.Template.DeepCopyInto(&out.Template) - in.Strategy.DeepCopyInto(&out.Strategy) - if in.RevisionHistoryLimit != nil { - in, out := &in.RevisionHistoryLimit, &out.RevisionHistoryLimit - *out = new(int32) - **out = **in - } - if in.RollbackTo != nil { - in, out := &in.RollbackTo, &out.RollbackTo - *out = new(RollbackConfig) - **out = **in - } - if in.ProgressDeadlineSeconds != nil { - in, out := &in.ProgressDeadlineSeconds, &out.ProgressDeadlineSeconds - *out = new(int32) - **out = **in - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineDeploymentSpec. -func (in *MachineDeploymentSpec) DeepCopy() *MachineDeploymentSpec { - if in == nil { - return nil - } - out := new(MachineDeploymentSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MachineDeploymentStatus) DeepCopyInto(out *MachineDeploymentStatus) { - *out = *in - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]MachineDeploymentCondition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.CollisionCount != nil { - in, out := &in.CollisionCount, &out.CollisionCount - *out = new(int32) - **out = **in - } - if in.FailedMachines != nil { - in, out := &in.FailedMachines, &out.FailedMachines - *out = make([]*MachineSummary, len(*in)) - for i := range *in { - if (*in)[i] != nil { - in, out := &(*in)[i], &(*out)[i] - *out = new(MachineSummary) - (*in).DeepCopyInto(*out) - } - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineDeploymentStatus. -func (in *MachineDeploymentStatus) DeepCopy() *MachineDeploymentStatus { - if in == nil { - return nil - } - out := new(MachineDeploymentStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MachineDeploymentStrategy) DeepCopyInto(out *MachineDeploymentStrategy) { - *out = *in - if in.RollingUpdate != nil { - in, out := &in.RollingUpdate, &out.RollingUpdate - *out = new(RollingUpdateMachineDeployment) - (*in).DeepCopyInto(*out) - } - if in.InPlaceUpdate != nil { - in, out := &in.InPlaceUpdate, &out.InPlaceUpdate - *out = new(InPlaceUpdateMachineDeployment) - (*in).DeepCopyInto(*out) - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineDeploymentStrategy. -func (in *MachineDeploymentStrategy) DeepCopy() *MachineDeploymentStrategy { - if in == nil { - return nil - } - out := new(MachineDeploymentStrategy) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MachineList) DeepCopyInto(out *MachineList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]Machine, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineList. -func (in *MachineList) DeepCopy() *MachineList { - if in == nil { - return nil - } - out := new(MachineList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *MachineList) 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 *MachineSet) DeepCopyInto(out *MachineSet) { - *out = *in - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - out.TypeMeta = in.TypeMeta - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineSet. -func (in *MachineSet) DeepCopy() *MachineSet { - if in == nil { - return nil - } - out := new(MachineSet) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *MachineSet) 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 *MachineSetCondition) DeepCopyInto(out *MachineSetCondition) { - *out = *in - in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineSetCondition. -func (in *MachineSetCondition) DeepCopy() *MachineSetCondition { - if in == nil { - return nil - } - out := new(MachineSetCondition) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MachineSetList) DeepCopyInto(out *MachineSetList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]MachineSet, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineSetList. -func (in *MachineSetList) DeepCopy() *MachineSetList { - if in == nil { - return nil - } - out := new(MachineSetList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *MachineSetList) 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 *MachineSetSpec) DeepCopyInto(out *MachineSetSpec) { - *out = *in - if in.Selector != nil { - in, out := &in.Selector, &out.Selector - *out = new(metav1.LabelSelector) - (*in).DeepCopyInto(*out) - } - out.MachineClass = in.MachineClass - in.Template.DeepCopyInto(&out.Template) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineSetSpec. -func (in *MachineSetSpec) DeepCopy() *MachineSetSpec { - if in == nil { - return nil - } - out := new(MachineSetSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MachineSetStatus) DeepCopyInto(out *MachineSetStatus) { - *out = *in - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]MachineSetCondition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - in.LastOperation.DeepCopyInto(&out.LastOperation) - if in.FailedMachines != nil { - in, out := &in.FailedMachines, &out.FailedMachines - *out = new([]MachineSummary) - if **in != nil { - in, out := *in, *out - *out = make([]MachineSummary, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineSetStatus. -func (in *MachineSetStatus) DeepCopy() *MachineSetStatus { - if in == nil { - return nil - } - out := new(MachineSetStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MachineSpec) DeepCopyInto(out *MachineSpec) { - *out = *in - out.Class = in.Class - in.NodeTemplateSpec.DeepCopyInto(&out.NodeTemplateSpec) - if in.MachineConfiguration != nil { - in, out := &in.MachineConfiguration, &out.MachineConfiguration - *out = new(MachineConfiguration) - (*in).DeepCopyInto(*out) - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineSpec. -func (in *MachineSpec) DeepCopy() *MachineSpec { - if in == nil { - return nil - } - out := new(MachineSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MachineStatus) DeepCopyInto(out *MachineStatus) { - *out = *in - if in.Addresses != nil { - in, out := &in.Addresses, &out.Addresses - *out = make([]v1.NodeAddress, len(*in)) - copy(*out, *in) - } - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]v1.NodeCondition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - in.LastOperation.DeepCopyInto(&out.LastOperation) - in.CurrentStatus.DeepCopyInto(&out.CurrentStatus) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineStatus. -func (in *MachineStatus) DeepCopy() *MachineStatus { - if in == nil { - return nil - } - out := new(MachineStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MachineSummary) DeepCopyInto(out *MachineSummary) { - *out = *in - in.LastOperation.DeepCopyInto(&out.LastOperation) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineSummary. -func (in *MachineSummary) DeepCopy() *MachineSummary { - if in == nil { - return nil - } - out := new(MachineSummary) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MachineTemplateSpec) DeepCopyInto(out *MachineTemplateSpec) { - *out = *in - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineTemplateSpec. -func (in *MachineTemplateSpec) DeepCopy() *MachineTemplateSpec { - if in == nil { - return nil - } - out := new(MachineTemplateSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NodeTemplate) DeepCopyInto(out *NodeTemplate) { - *out = *in - if in.Capacity != nil { - in, out := &in.Capacity, &out.Capacity - *out = make(v1.ResourceList, len(*in)) - for key, val := range *in { - (*out)[key] = val.DeepCopy() - } - } - if in.VirtualCapacity != nil { - in, out := &in.VirtualCapacity, &out.VirtualCapacity - *out = make(v1.ResourceList, len(*in)) - for key, val := range *in { - (*out)[key] = val.DeepCopy() - } - } - if in.Architecture != nil { - in, out := &in.Architecture, &out.Architecture - *out = new(string) - **out = **in - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeTemplate. -func (in *NodeTemplate) DeepCopy() *NodeTemplate { - if in == nil { - return nil - } - out := new(NodeTemplate) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NodeTemplateSpec) DeepCopyInto(out *NodeTemplateSpec) { - *out = *in - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeTemplateSpec. -func (in *NodeTemplateSpec) DeepCopy() *NodeTemplateSpec { - if in == nil { - return nil - } - out := new(NodeTemplateSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RollbackConfig) DeepCopyInto(out *RollbackConfig) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RollbackConfig. -func (in *RollbackConfig) DeepCopy() *RollbackConfig { - if in == nil { - return nil - } - out := new(RollbackConfig) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RollingUpdateMachineDeployment) DeepCopyInto(out *RollingUpdateMachineDeployment) { - *out = *in - in.UpdateConfiguration.DeepCopyInto(&out.UpdateConfiguration) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RollingUpdateMachineDeployment. -func (in *RollingUpdateMachineDeployment) DeepCopy() *RollingUpdateMachineDeployment { - if in == nil { - return nil - } - out := new(RollingUpdateMachineDeployment) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *UpdateConfiguration) DeepCopyInto(out *UpdateConfiguration) { - *out = *in - if in.MaxUnavailable != nil { - in, out := &in.MaxUnavailable, &out.MaxUnavailable - *out = new(intstr.IntOrString) - **out = **in - } - if in.MaxSurge != nil { - in, out := &in.MaxSurge, &out.MaxSurge - *out = new(intstr.IntOrString) - **out = **in - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UpdateConfiguration. -func (in *UpdateConfiguration) DeepCopy() *UpdateConfiguration { - if in == nil { - return nil - } - out := new(UpdateConfiguration) - in.DeepCopyInto(out) - return out -} diff --git a/pkg/apis/machine/v1alpha1/zz_generated.defaults.go b/pkg/apis/machine/v1alpha1/zz_generated.defaults.go deleted file mode 100644 index dce68e638..000000000 --- a/pkg/apis/machine/v1alpha1/zz_generated.defaults.go +++ /dev/null @@ -1,21 +0,0 @@ -//go:build !ignore_autogenerated -// +build !ignore_autogenerated - -// SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors -// -// SPDX-License-Identifier: Apache-2.0 - -// Code generated by defaulter-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - runtime "k8s.io/apimachinery/pkg/runtime" -) - -// RegisterDefaults adds defaulters functions to the given scheme. -// Public to allow building arbitrary schemes. -// All generated defaulters are covering - they call all nested defaulters. -func RegisterDefaults(scheme *runtime.Scheme) error { - return nil -} diff --git a/pkg/apis/machine/zz_generated.deepcopy.go b/pkg/apis/machine/zz_generated.deepcopy.go deleted file mode 100644 index 90aa57743..000000000 --- a/pkg/apis/machine/zz_generated.deepcopy.go +++ /dev/null @@ -1,888 +0,0 @@ -//go:build !ignore_autogenerated -// +build !ignore_autogenerated - -// SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors -// -// SPDX-License-Identifier: Apache-2.0 - -// Code generated by deepcopy-gen. DO NOT EDIT. - -package machine - -import ( - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" - intstr "k8s.io/apimachinery/pkg/util/intstr" -) - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ClassSpec) DeepCopyInto(out *ClassSpec) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClassSpec. -func (in *ClassSpec) DeepCopy() *ClassSpec { - if in == nil { - return nil - } - out := new(ClassSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *CurrentStatus) DeepCopyInto(out *CurrentStatus) { - *out = *in - in.LastUpdateTime.DeepCopyInto(&out.LastUpdateTime) - in.PreserveExpiryTime.DeepCopyInto(&out.PreserveExpiryTime) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CurrentStatus. -func (in *CurrentStatus) DeepCopy() *CurrentStatus { - if in == nil { - return nil - } - out := new(CurrentStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InPlaceUpdateMachineDeployment) DeepCopyInto(out *InPlaceUpdateMachineDeployment) { - *out = *in - in.UpdateConfiguration.DeepCopyInto(&out.UpdateConfiguration) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InPlaceUpdateMachineDeployment. -func (in *InPlaceUpdateMachineDeployment) DeepCopy() *InPlaceUpdateMachineDeployment { - if in == nil { - return nil - } - out := new(InPlaceUpdateMachineDeployment) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *LastOperation) DeepCopyInto(out *LastOperation) { - *out = *in - in.LastUpdateTime.DeepCopyInto(&out.LastUpdateTime) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LastOperation. -func (in *LastOperation) DeepCopy() *LastOperation { - if in == nil { - return nil - } - out := new(LastOperation) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Machine) DeepCopyInto(out *Machine) { - *out = *in - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - out.TypeMeta = in.TypeMeta - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Machine. -func (in *Machine) DeepCopy() *Machine { - if in == nil { - return nil - } - out := new(Machine) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *Machine) 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 *MachineClass) DeepCopyInto(out *MachineClass) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - if in.NodeTemplate != nil { - in, out := &in.NodeTemplate, &out.NodeTemplate - *out = new(NodeTemplate) - (*in).DeepCopyInto(*out) - } - if in.CredentialsSecretRef != nil { - in, out := &in.CredentialsSecretRef, &out.CredentialsSecretRef - *out = new(v1.SecretReference) - **out = **in - } - in.ProviderSpec.DeepCopyInto(&out.ProviderSpec) - if in.SecretRef != nil { - in, out := &in.SecretRef, &out.SecretRef - *out = new(v1.SecretReference) - **out = **in - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineClass. -func (in *MachineClass) DeepCopy() *MachineClass { - if in == nil { - return nil - } - out := new(MachineClass) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *MachineClass) 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 *MachineClassList) DeepCopyInto(out *MachineClassList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]MachineClass, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineClassList. -func (in *MachineClassList) DeepCopy() *MachineClassList { - if in == nil { - return nil - } - out := new(MachineClassList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *MachineClassList) 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 *MachineConfiguration) DeepCopyInto(out *MachineConfiguration) { - *out = *in - if in.MachineDrainTimeout != nil { - in, out := &in.MachineDrainTimeout, &out.MachineDrainTimeout - *out = new(metav1.Duration) - **out = **in - } - if in.MachineHealthTimeout != nil { - in, out := &in.MachineHealthTimeout, &out.MachineHealthTimeout - *out = new(metav1.Duration) - **out = **in - } - if in.MachineCreationTimeout != nil { - in, out := &in.MachineCreationTimeout, &out.MachineCreationTimeout - *out = new(metav1.Duration) - **out = **in - } - if in.MachineInPlaceUpdateTimeout != nil { - in, out := &in.MachineInPlaceUpdateTimeout, &out.MachineInPlaceUpdateTimeout - *out = new(metav1.Duration) - **out = **in - } - if in.MachinePreserveTimeout != nil { - in, out := &in.MachinePreserveTimeout, &out.MachinePreserveTimeout - *out = new(metav1.Duration) - **out = **in - } - if in.DisableHealthTimeout != nil { - in, out := &in.DisableHealthTimeout, &out.DisableHealthTimeout - *out = new(bool) - **out = **in - } - if in.MaxEvictRetries != nil { - in, out := &in.MaxEvictRetries, &out.MaxEvictRetries - *out = new(int32) - **out = **in - } - if in.NodeConditions != nil { - in, out := &in.NodeConditions, &out.NodeConditions - *out = new(string) - **out = **in - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineConfiguration. -func (in *MachineConfiguration) DeepCopy() *MachineConfiguration { - if in == nil { - return nil - } - out := new(MachineConfiguration) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MachineDeployment) DeepCopyInto(out *MachineDeployment) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineDeployment. -func (in *MachineDeployment) DeepCopy() *MachineDeployment { - if in == nil { - return nil - } - out := new(MachineDeployment) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *MachineDeployment) 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 *MachineDeploymentCondition) DeepCopyInto(out *MachineDeploymentCondition) { - *out = *in - in.LastUpdateTime.DeepCopyInto(&out.LastUpdateTime) - in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineDeploymentCondition. -func (in *MachineDeploymentCondition) DeepCopy() *MachineDeploymentCondition { - if in == nil { - return nil - } - out := new(MachineDeploymentCondition) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MachineDeploymentList) DeepCopyInto(out *MachineDeploymentList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]MachineDeployment, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineDeploymentList. -func (in *MachineDeploymentList) DeepCopy() *MachineDeploymentList { - if in == nil { - return nil - } - out := new(MachineDeploymentList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *MachineDeploymentList) 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 *MachineDeploymentRollback) DeepCopyInto(out *MachineDeploymentRollback) { - *out = *in - out.TypeMeta = in.TypeMeta - if in.UpdatedAnnotations != nil { - in, out := &in.UpdatedAnnotations, &out.UpdatedAnnotations - *out = make(map[string]string, len(*in)) - for key, val := range *in { - (*out)[key] = val - } - } - out.RollbackTo = in.RollbackTo - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineDeploymentRollback. -func (in *MachineDeploymentRollback) DeepCopy() *MachineDeploymentRollback { - if in == nil { - return nil - } - out := new(MachineDeploymentRollback) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *MachineDeploymentRollback) 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 *MachineDeploymentSpec) DeepCopyInto(out *MachineDeploymentSpec) { - *out = *in - if in.Selector != nil { - in, out := &in.Selector, &out.Selector - *out = new(metav1.LabelSelector) - (*in).DeepCopyInto(*out) - } - in.Template.DeepCopyInto(&out.Template) - in.Strategy.DeepCopyInto(&out.Strategy) - if in.RevisionHistoryLimit != nil { - in, out := &in.RevisionHistoryLimit, &out.RevisionHistoryLimit - *out = new(int32) - **out = **in - } - if in.RollbackTo != nil { - in, out := &in.RollbackTo, &out.RollbackTo - *out = new(RollbackConfig) - **out = **in - } - if in.ProgressDeadlineSeconds != nil { - in, out := &in.ProgressDeadlineSeconds, &out.ProgressDeadlineSeconds - *out = new(int32) - **out = **in - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineDeploymentSpec. -func (in *MachineDeploymentSpec) DeepCopy() *MachineDeploymentSpec { - if in == nil { - return nil - } - out := new(MachineDeploymentSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MachineDeploymentStatus) DeepCopyInto(out *MachineDeploymentStatus) { - *out = *in - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]MachineDeploymentCondition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.CollisionCount != nil { - in, out := &in.CollisionCount, &out.CollisionCount - *out = new(int32) - **out = **in - } - if in.FailedMachines != nil { - in, out := &in.FailedMachines, &out.FailedMachines - *out = make([]*MachineSummary, len(*in)) - for i := range *in { - if (*in)[i] != nil { - in, out := &(*in)[i], &(*out)[i] - *out = new(MachineSummary) - (*in).DeepCopyInto(*out) - } - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineDeploymentStatus. -func (in *MachineDeploymentStatus) DeepCopy() *MachineDeploymentStatus { - if in == nil { - return nil - } - out := new(MachineDeploymentStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MachineDeploymentStrategy) DeepCopyInto(out *MachineDeploymentStrategy) { - *out = *in - if in.RollingUpdate != nil { - in, out := &in.RollingUpdate, &out.RollingUpdate - *out = new(RollingUpdateMachineDeployment) - (*in).DeepCopyInto(*out) - } - if in.InPlaceUpdate != nil { - in, out := &in.InPlaceUpdate, &out.InPlaceUpdate - *out = new(InPlaceUpdateMachineDeployment) - (*in).DeepCopyInto(*out) - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineDeploymentStrategy. -func (in *MachineDeploymentStrategy) DeepCopy() *MachineDeploymentStrategy { - if in == nil { - return nil - } - out := new(MachineDeploymentStrategy) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MachineList) DeepCopyInto(out *MachineList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]Machine, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineList. -func (in *MachineList) DeepCopy() *MachineList { - if in == nil { - return nil - } - out := new(MachineList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *MachineList) 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 *MachineSet) DeepCopyInto(out *MachineSet) { - *out = *in - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - out.TypeMeta = in.TypeMeta - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineSet. -func (in *MachineSet) DeepCopy() *MachineSet { - if in == nil { - return nil - } - out := new(MachineSet) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *MachineSet) 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 *MachineSetCondition) DeepCopyInto(out *MachineSetCondition) { - *out = *in - in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineSetCondition. -func (in *MachineSetCondition) DeepCopy() *MachineSetCondition { - if in == nil { - return nil - } - out := new(MachineSetCondition) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MachineSetList) DeepCopyInto(out *MachineSetList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]MachineSet, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineSetList. -func (in *MachineSetList) DeepCopy() *MachineSetList { - if in == nil { - return nil - } - out := new(MachineSetList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *MachineSetList) 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 *MachineSetSpec) DeepCopyInto(out *MachineSetSpec) { - *out = *in - if in.Selector != nil { - in, out := &in.Selector, &out.Selector - *out = new(metav1.LabelSelector) - (*in).DeepCopyInto(*out) - } - out.MachineClass = in.MachineClass - in.Template.DeepCopyInto(&out.Template) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineSetSpec. -func (in *MachineSetSpec) DeepCopy() *MachineSetSpec { - if in == nil { - return nil - } - out := new(MachineSetSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MachineSetStatus) DeepCopyInto(out *MachineSetStatus) { - *out = *in - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]MachineSetCondition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - in.LastOperation.DeepCopyInto(&out.LastOperation) - if in.FailedMachines != nil { - in, out := &in.FailedMachines, &out.FailedMachines - *out = new([]MachineSummary) - if **in != nil { - in, out := *in, *out - *out = make([]MachineSummary, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineSetStatus. -func (in *MachineSetStatus) DeepCopy() *MachineSetStatus { - if in == nil { - return nil - } - out := new(MachineSetStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MachineSpec) DeepCopyInto(out *MachineSpec) { - *out = *in - out.Class = in.Class - in.NodeTemplateSpec.DeepCopyInto(&out.NodeTemplateSpec) - if in.MachineConfiguration != nil { - in, out := &in.MachineConfiguration, &out.MachineConfiguration - *out = new(MachineConfiguration) - (*in).DeepCopyInto(*out) - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineSpec. -func (in *MachineSpec) DeepCopy() *MachineSpec { - if in == nil { - return nil - } - out := new(MachineSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MachineStatus) DeepCopyInto(out *MachineStatus) { - *out = *in - if in.Addresses != nil { - in, out := &in.Addresses, &out.Addresses - *out = make([]v1.NodeAddress, len(*in)) - copy(*out, *in) - } - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]v1.NodeCondition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - in.LastOperation.DeepCopyInto(&out.LastOperation) - in.CurrentStatus.DeepCopyInto(&out.CurrentStatus) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineStatus. -func (in *MachineStatus) DeepCopy() *MachineStatus { - if in == nil { - return nil - } - out := new(MachineStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MachineSummary) DeepCopyInto(out *MachineSummary) { - *out = *in - in.LastOperation.DeepCopyInto(&out.LastOperation) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineSummary. -func (in *MachineSummary) DeepCopy() *MachineSummary { - if in == nil { - return nil - } - out := new(MachineSummary) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MachineTemplate) DeepCopyInto(out *MachineTemplate) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Template.DeepCopyInto(&out.Template) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineTemplate. -func (in *MachineTemplate) DeepCopy() *MachineTemplate { - if in == nil { - return nil - } - out := new(MachineTemplate) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *MachineTemplate) 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 *MachineTemplateList) DeepCopyInto(out *MachineTemplateList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]MachineTemplate, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineTemplateList. -func (in *MachineTemplateList) DeepCopy() *MachineTemplateList { - if in == nil { - return nil - } - out := new(MachineTemplateList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *MachineTemplateList) 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 *MachineTemplateSpec) DeepCopyInto(out *MachineTemplateSpec) { - *out = *in - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineTemplateSpec. -func (in *MachineTemplateSpec) DeepCopy() *MachineTemplateSpec { - if in == nil { - return nil - } - out := new(MachineTemplateSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NodeTemplate) DeepCopyInto(out *NodeTemplate) { - *out = *in - if in.Capacity != nil { - in, out := &in.Capacity, &out.Capacity - *out = make(v1.ResourceList, len(*in)) - for key, val := range *in { - (*out)[key] = val.DeepCopy() - } - } - if in.VirtualCapacity != nil { - in, out := &in.VirtualCapacity, &out.VirtualCapacity - *out = make(v1.ResourceList, len(*in)) - for key, val := range *in { - (*out)[key] = val.DeepCopy() - } - } - if in.Architecture != nil { - in, out := &in.Architecture, &out.Architecture - *out = new(string) - **out = **in - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeTemplate. -func (in *NodeTemplate) DeepCopy() *NodeTemplate { - if in == nil { - return nil - } - out := new(NodeTemplate) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NodeTemplateSpec) DeepCopyInto(out *NodeTemplateSpec) { - *out = *in - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeTemplateSpec. -func (in *NodeTemplateSpec) DeepCopy() *NodeTemplateSpec { - if in == nil { - return nil - } - out := new(NodeTemplateSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RollbackConfig) DeepCopyInto(out *RollbackConfig) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RollbackConfig. -func (in *RollbackConfig) DeepCopy() *RollbackConfig { - if in == nil { - return nil - } - out := new(RollbackConfig) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RollingUpdateMachineDeployment) DeepCopyInto(out *RollingUpdateMachineDeployment) { - *out = *in - in.UpdateConfiguration.DeepCopyInto(&out.UpdateConfiguration) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RollingUpdateMachineDeployment. -func (in *RollingUpdateMachineDeployment) DeepCopy() *RollingUpdateMachineDeployment { - if in == nil { - return nil - } - out := new(RollingUpdateMachineDeployment) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *UpdateConfiguration) DeepCopyInto(out *UpdateConfiguration) { - *out = *in - if in.MaxUnavailable != nil { - in, out := &in.MaxUnavailable, &out.MaxUnavailable - *out = new(intstr.IntOrString) - **out = **in - } - if in.MaxSurge != nil { - in, out := &in.MaxSurge, &out.MaxSurge - *out = new(intstr.IntOrString) - **out = **in - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UpdateConfiguration. -func (in *UpdateConfiguration) DeepCopy() *UpdateConfiguration { - if in == nil { - return nil - } - out := new(UpdateConfiguration) - in.DeepCopyInto(out) - return out -} diff --git a/pkg/controller/deployment_machineset_util.go b/pkg/controller/deployment_machineset_util.go index e44505393..6d352ca48 100644 --- a/pkg/controller/deployment_machineset_util.go +++ b/pkg/controller/deployment_machineset_util.go @@ -25,6 +25,7 @@ package controller import ( "context" "fmt" + "k8s.io/utils/ptr" "reflect" "k8s.io/klog/v2" @@ -160,7 +161,7 @@ func calculateMachineSetStatus(is *v1alpha1.MachineSet, filteredMachines []*v1al newStatus.ReadyReplicas = int32(readyReplicasCount) // #nosec G115 (CWE-190) -- number of machines will not exceed MaxInt32 newStatus.AvailableReplicas = int32(availableReplicasCount) // #nosec G115 (CWE-190) -- number of machines will not exceed MaxInt32 newStatus.LastOperation.LastUpdateTime = metav1.Now() - newStatus.AutoPreserveFailedMachineCount = int32(autoPreserveFailedMachineCount) // #nosec G115 (CWE-190) -- number of machines will not exceed MaxInt32 + newStatus.AutoPreserveFailedMachineCount = ptr.To(int32(autoPreserveFailedMachineCount)) // #nosec G115 (CWE-190) -- number of machines will not exceed MaxInt32 return newStatus } diff --git a/pkg/controller/machineset.go b/pkg/controller/machineset.go index 1d1023cc5..120d39b06 100644 --- a/pkg/controller/machineset.go +++ b/pkg/controller/machineset.go @@ -508,7 +508,7 @@ func (c *controller) isMachineCandidateForPreservation(ctx context.Context, mach return false, nil } } - if machineSet.Status.AutoPreserveFailedMachineCount < machineSet.Spec.AutoPreserveFailedMachineMax { + if *machineSet.Status.AutoPreserveFailedMachineCount < *machineSet.Spec.AutoPreserveFailedMachineMax { err := c.annotateMachineForAutoPreservation(ctx, machine) if err != nil { return true, err diff --git a/pkg/openapi/api_violations.report b/pkg/openapi/api_violations.report index 5cb955c9e..0861c8d4c 100644 --- a/pkg/openapi/api_violations.report +++ b/pkg/openapi/api_violations.report @@ -7,7 +7,6 @@ API rule violation: names_match,github.com/gardener/machine-controller-manager/p API rule violation: names_match,github.com/gardener/machine-controller-manager/pkg/apis/machine/v1alpha1,MachineConfiguration,MachineDrainTimeout API rule violation: names_match,github.com/gardener/machine-controller-manager/pkg/apis/machine/v1alpha1,MachineConfiguration,MachineHealthTimeout API rule violation: names_match,github.com/gardener/machine-controller-manager/pkg/apis/machine/v1alpha1,MachineConfiguration,MachineInPlaceUpdateTimeout -API rule violation: names_match,github.com/gardener/machine-controller-manager/pkg/apis/machine/v1alpha1,MachineConfiguration,MachinePreserveTimeout API rule violation: names_match,github.com/gardener/machine-controller-manager/pkg/apis/machine/v1alpha1,MachineSetStatus,Conditions API rule violation: names_match,github.com/gardener/machine-controller-manager/pkg/apis/machine/v1alpha1,MachineSpec,NodeTemplateSpec API rule violation: names_match,k8s.io/api/core/v1,AzureDiskVolumeSource,DataDiskURI diff --git a/pkg/openapi/openapi_generated.go b/pkg/openapi/openapi_generated.go index b0cd12043..0db94f5b6 100644 --- a/pkg/openapi/openapi_generated.go +++ b/pkg/openapi/openapi_generated.go @@ -688,7 +688,7 @@ func schema_pkg_apis_machine_v1alpha1_MachineConfiguration(ref common.ReferenceC Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Duration"), }, }, - "preserveTimeout": { + "machinePreserveTimeout": { SchemaProps: spec.SchemaProps{ Description: "MachinePreserveTimeout is the timeout after which the machine preservation is stopped", Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Duration"), @@ -1494,7 +1494,7 @@ func schema_pkg_apis_machine_v1alpha1_MachineSpec(ref common.ReferenceCallback) Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Duration"), }, }, - "preserveTimeout": { + "machinePreserveTimeout": { SchemaProps: spec.SchemaProps{ Description: "MachinePreserveTimeout is the timeout after which the machine preservation is stopped", Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Duration"), diff --git a/pkg/util/provider/machinecontroller/machine_test.go b/pkg/util/provider/machinecontroller/machine_test.go index 10eaad4de..62a6b7ed1 100644 --- a/pkg/util/provider/machinecontroller/machine_test.go +++ b/pkg/util/provider/machinecontroller/machine_test.go @@ -4036,9 +4036,9 @@ var _ = Describe("machine", func() { machine.Status.CurrentStatus.Phase = tc.setup.phase } if tc.setup.oldPreserveValue == machineutils.PreserveMachineAnnotationValueNow || tc.setup.oldPreserveValue == machineutils.PreserveMachineAnnotationValuePreservedByMCM { - machine.Status.CurrentStatus.PreserveExpiryTime = metav1.NewTime(metav1.Now().Add(1 * time.Hour)) + machine.Status.CurrentStatus.PreserveExpiryTime = &metav1.Time{Time: metav1.Now().Add(1 * time.Hour)} } else if tc.setup.oldPreserveValue == machineutils.PreserveMachineAnnotationValueWhenFailed && machineutils.IsMachineFailed(machine) { - machine.Status.CurrentStatus.PreserveExpiryTime = metav1.NewTime(metav1.Now().Add(1 * time.Hour)) + machine.Status.CurrentStatus.PreserveExpiryTime = &metav1.Time{Time: metav1.Now().Add(1 * time.Hour)} } controlMachineObjects := []runtime.Object{machine} @@ -4273,7 +4273,7 @@ var _ = Describe("machine", func() { nodeAnnotationValue string nodeName string machinePhase v1alpha1.MachinePhase - preserveExpiryTime metav1.Time + preserveExpiryTime *metav1.Time } type expect struct { retry machineutils.RetryPeriod @@ -4450,7 +4450,7 @@ var _ = Describe("machine", func() { nodeAnnotationValue: "false", nodeName: "node-1", machinePhase: v1alpha1.MachineRunning, - preserveExpiryTime: metav1.NewTime(metav1.Now().Add(1 * time.Hour)), + preserveExpiryTime: &metav1.Time{Time: metav1.Now().Add(1 * time.Hour)}, }, expect: expect{ preserveExpiryTimeIsSet: false, @@ -4479,7 +4479,7 @@ var _ = Describe("machine", func() { nodeAnnotationValue: machineutils.PreserveMachineAnnotationValueNow, nodeName: "node-1", machinePhase: v1alpha1.MachineRunning, - preserveExpiryTime: metav1.NewTime(metav1.Now().Add(-1 * time.Minute)), + preserveExpiryTime: &metav1.Time{Time: metav1.Now().Add(-1 * time.Minute)}, }, expect: expect{ preserveExpiryTimeIsSet: false, diff --git a/pkg/util/provider/machinecontroller/machine_util.go b/pkg/util/provider/machinecontroller/machine_util.go index ceea0339a..fe8bdaa97 100644 --- a/pkg/util/provider/machinecontroller/machine_util.go +++ b/pkg/util/provider/machinecontroller/machine_util.go @@ -1305,7 +1305,7 @@ func (c *controller) setMachineTerminationStatus(ctx context.Context, deleteMach Phase: v1alpha1.MachineTerminating, // TimeoutActive: false, LastUpdateTime: metav1.Now(), - PreserveExpiryTime: metav1.Time{}, + PreserveExpiryTime: nil, } _, err := c.controlMachineClient.Machines(clone.Namespace).UpdateStatus(ctx, clone, metav1.UpdateOptions{}) @@ -2439,7 +2439,7 @@ func (c *controller) setPreserveExpiryTimeOnMachine(ctx context.Context, machine Phase: machine.Status.CurrentStatus.Phase, TimeoutActive: machine.Status.CurrentStatus.TimeoutActive, LastUpdateTime: metav1.Now(), - PreserveExpiryTime: metav1.NewTime(metav1.Now().Add(c.getEffectiveMachinePreserveTimeout(machine).Duration)), + PreserveExpiryTime: &metav1.Time{Time: metav1.Now().Add(c.getEffectiveMachinePreserveTimeout(machine).Duration)}, } machine.Status.CurrentStatus = preservedCurrentStatus @@ -2565,7 +2565,7 @@ func (c *controller) stopMachinePreservation(ctx context.Context, machine *v1alp } // Step 3: update machine status to set preserve expiry time to metav1.Time{} clone := machine.DeepCopy() - clone.Status.CurrentStatus.PreserveExpiryTime = metav1.Time{} + clone.Status.CurrentStatus.PreserveExpiryTime = nil clone.Status.CurrentStatus.LastUpdateTime = metav1.Now() _, err := c.controlMachineClient.Machines(clone.Namespace).UpdateStatus(ctx, clone, metav1.UpdateOptions{}) if err != nil { diff --git a/pkg/util/provider/machinecontroller/machine_util_test.go b/pkg/util/provider/machinecontroller/machine_util_test.go index 87581bda6..7e25d5ed2 100644 --- a/pkg/util/provider/machinecontroller/machine_util_test.go +++ b/pkg/util/provider/machinecontroller/machine_util_test.go @@ -3961,7 +3961,6 @@ var _ = Describe("machine_util", func() { Describe("#preserveMachine", func() { type setup struct { machinePhase machinev1.MachinePhase - preserveExpiryTime metav1.Time nodeName string preserveValue string isCAAnnotationPresent bool @@ -3998,7 +3997,7 @@ var _ = Describe("machine_util", func() { CurrentStatus: machinev1.CurrentStatus{ Phase: tc.setup.machinePhase, LastUpdateTime: metav1.Now(), - PreserveExpiryTime: tc.setup.preserveExpiryTime, + PreserveExpiryTime: nil, }, }, } @@ -4244,7 +4243,7 @@ var _ = Describe("machine_util", func() { CurrentStatus: machinev1.CurrentStatus{ Phase: machinev1.MachineFailed, LastUpdateTime: metav1.Now(), - PreserveExpiryTime: metav1.NewTime(time.Now().Add(10 * time.Minute)), + PreserveExpiryTime: &metav1.Time{Time: time.Now().Add(10 * time.Minute)}, }, }, } From 179fae036dbc32ce0de025913ecaf085d5cb6294 Mon Sep 17 00:00:00 2001 From: thiyyakat Date: Thu, 8 Jan 2026 12:24:57 +0530 Subject: [PATCH 41/43] Fix Makefile --- Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 6b0f4f913..aba0236ac 100644 --- a/Makefile +++ b/Makefile @@ -172,9 +172,9 @@ test-clean: .PHONY: generate generate: $(VGOPATH) $(DEEPCOPY_GEN) $(DEFAULTER_GEN) $(CONVERSION_GEN) $(OPENAPI_GEN) $(CONTROLLER_GEN) $(GEN_CRD_API_REFERENCE_DOCS) - GOFLAGS="-buildvcs=false" $(CONTROLLER_GEN) crd paths=./pkg/apis/machine/v1alpha1/... output:crd:dir=kubernetes/crds output:stdout - @GOFLAGS="-buildvcs=false" ./hack/generate-code - @GOFLAGS="-buildvcs=false" ./hack/api-reference/generate-spec-doc.sh + $(CONTROLLER_GEN) crd paths=./pkg/apis/machine/v1alpha1/... output:crd:dir=kubernetes/crds output:stdout + @./hack/generate-code + @./hack/api-reference/generate-spec-doc.sh .PHONY: add-license-headers add-license-headers: $(GO_ADD_LICENSE) From 0a825f8208caca52dbf8491eae775fc08dec9df5 Mon Sep 17 00:00:00 2001 From: thiyyakat Date: Thu, 8 Jan 2026 13:54:32 +0530 Subject: [PATCH 42/43] Add crds --- .../machine.sapcloud.io_machineclasses.yaml | 127 ++ ...achine.sapcloud.io_machinedeployments.yaml | 562 ++++++++ .../crds/machine.sapcloud.io_machines.yaml | 333 +++++ .../crds/machine.sapcloud.io_machinesets.yaml | 447 +++++++ .../v1alpha1/zz_generated.conversion.go | 1179 +++++++++++++++++ .../machine/v1alpha1/zz_generated.deepcopy.go | 813 ++++++++++++ .../machine/v1alpha1/zz_generated.defaults.go | 21 + pkg/apis/machine/zz_generated.deepcopy.go | 906 +++++++++++++ 8 files changed, 4388 insertions(+) create mode 100644 kubernetes/crds/machine.sapcloud.io_machineclasses.yaml create mode 100644 kubernetes/crds/machine.sapcloud.io_machinedeployments.yaml create mode 100644 kubernetes/crds/machine.sapcloud.io_machines.yaml create mode 100644 kubernetes/crds/machine.sapcloud.io_machinesets.yaml create mode 100644 pkg/apis/machine/v1alpha1/zz_generated.conversion.go create mode 100644 pkg/apis/machine/v1alpha1/zz_generated.deepcopy.go create mode 100644 pkg/apis/machine/v1alpha1/zz_generated.defaults.go create mode 100644 pkg/apis/machine/zz_generated.deepcopy.go diff --git a/kubernetes/crds/machine.sapcloud.io_machineclasses.yaml b/kubernetes/crds/machine.sapcloud.io_machineclasses.yaml new file mode 100644 index 000000000..f0cd9d515 --- /dev/null +++ b/kubernetes/crds/machine.sapcloud.io_machineclasses.yaml @@ -0,0 +1,127 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.1 + name: machineclasses.machine.sapcloud.io +spec: + group: machine.sapcloud.io + names: + kind: MachineClass + listKind: MachineClassList + plural: machineclasses + shortNames: + - mcc + singular: machineclass + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: |- + MachineClass can be used to templatize and re-use provider configuration + across multiple Machines / MachineSets / MachineDeployments. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + credentialsSecretRef: + description: |- + CredentialsSecretRef can optionally store the credentials (in this case the SecretRef does not need to store them). + This might be useful if multiple machine classes with the same credentials but different user-datas are used. + properties: + name: + description: name is unique within a namespace to reference a secret + resource. + type: string + namespace: + description: namespace defines the space within which the secret name + must be unique. + type: string + type: object + x-kubernetes-map-type: atomic + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + nodeTemplate: + description: NodeTemplate contains subfields to track all node resources + and other node info required to scale nodegroup from zero + properties: + architecture: + description: CPU Architecture of the node belonging to nodeGroup + type: string + capacity: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: Capacity contains subfields to track all node resources + required to scale nodegroup from zero + type: object + instanceType: + description: Instance type of the node belonging to nodeGroup + type: string + region: + description: Region of the expected node belonging to nodeGroup + type: string + virtualCapacity: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: VirtualCapacity represents the expected Node 'virtual' + capacity ie comprising virtual extended resources. + type: object + zone: + description: Zone of the expected node belonging to nodeGroup + type: string + required: + - capacity + - instanceType + - region + - zone + type: object + x-kubernetes-preserve-unknown-fields: true + provider: + description: Provider is the combination of name and location of cloud-specific + drivers. + type: string + providerSpec: + description: Provider-specific configuration to use during node creation. + type: object + x-kubernetes-preserve-unknown-fields: true + secretRef: + description: SecretRef stores the necessary secrets such as credentials + or userdata. + properties: + name: + description: name is unique within a namespace to reference a secret + resource. + type: string + namespace: + description: namespace defines the space within which the secret name + must be unique. + type: string + type: object + x-kubernetes-map-type: atomic + required: + - providerSpec + type: object + served: true + storage: true diff --git a/kubernetes/crds/machine.sapcloud.io_machinedeployments.yaml b/kubernetes/crds/machine.sapcloud.io_machinedeployments.yaml new file mode 100644 index 000000000..abb36d1c4 --- /dev/null +++ b/kubernetes/crds/machine.sapcloud.io_machinedeployments.yaml @@ -0,0 +1,562 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.1 + name: machinedeployments.machine.sapcloud.io +spec: + group: machine.sapcloud.io + names: + kind: MachineDeployment + listKind: MachineDeploymentList + plural: machinedeployments + shortNames: + - mcd + singular: machinedeployment + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Total number of ready machines targeted by this machine deployment. + jsonPath: .status.readyReplicas + name: Ready + type: integer + - description: Number of desired machines. + jsonPath: .spec.replicas + name: Desired + type: integer + - description: Total number of non-terminated machines targeted by this machine + deployment that have the desired template spec. + jsonPath: .status.updatedReplicas + name: Up-to-date + type: integer + - description: Total number of available machines (ready for at least minReadySeconds) + targeted by this machine deployment. + jsonPath: .status.availableReplicas + name: Available + type: integer + - description: |- + CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. + Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: MachineDeployment enables declarative updates for machines and + MachineSets. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Specification of the desired behavior of the MachineDeployment. + properties: + autoPreserveFailedMachineMax: + description: |- + The maximum number of machines in the machine deployment that will be auto-preserved. + In the gardener context, this number is derived from the AutoPreserveFailedMachineMax set at the worker level, distributed amongst the worker's machine deployments + format: int32 + type: integer + minReadySeconds: + description: |- + Minimum number of seconds for which a newly created machine should be ready + without any of its container crashing, for it to be considered available. + Defaults to 0 (machine will be considered available as soon as it is ready) + format: int32 + type: integer + paused: + description: |- + Indicates that the MachineDeployment is paused and will not be processed by the + MachineDeployment controller. + type: boolean + progressDeadlineSeconds: + description: |- + The maximum time in seconds for a MachineDeployment to make progress before it + is considered to be failed. The MachineDeployment controller will continue to + process failed MachineDeployments and a condition with a ProgressDeadlineExceeded + reason will be surfaced in the MachineDeployment status. Note that progress will + not be estimated during the time a MachineDeployment is paused. This is not set + by default, which is treated as infinite deadline. + format: int32 + type: integer + replicas: + description: |- + Number of desired machines. This is a pointer to distinguish between explicit + zero and not specified. Defaults to 0. + format: int32 + type: integer + revisionHistoryLimit: + description: |- + The number of old MachineSets to retain to allow rollback. + This is a pointer to distinguish between explicit zero and not specified. + format: int32 + type: integer + rollbackTo: + description: |- + DEPRECATED. + The config this MachineDeployment is rolling back to. Will be cleared after rollback is done. + properties: + revision: + description: The revision to rollback to. If set to 0, rollback + to the last revision. + format: int64 + type: integer + type: object + selector: + description: |- + Label selector for machines. Existing MachineSets whose machines are + selected by this will be the ones affected by this MachineDeployment. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + strategy: + description: The MachineDeployment strategy to use to replace existing + machines with new ones. + properties: + inPlaceUpdate: + description: |- + InPlaceUpdate update config params. Present only if MachineDeploymentStrategyType = + InPlaceUpdate. + properties: + maxSurge: + anyOf: + - type: integer + - type: string + description: |- + The maximum number of machines that can be scheduled above the desired number of + machines. + Value can be an absolute number (ex: 5) or a percentage of desired machines (ex: 10%). + This can not be 0 if MaxUnavailable is 0. + Absolute number is calculated from percentage by rounding up. + Example: when this is set to 30%, the new machine set can be scaled up immediately when + the update starts, such that the total number of old and new machines does not exceed + 130% of desired machines. Once old machines have been killed, + new machine set can be scaled up further, ensuring that total number of machines running + at any time during the update is utmost 130% of desired machines. + x-kubernetes-int-or-string: true + maxUnavailable: + anyOf: + - type: integer + - type: string + description: |- + The maximum number of machines that can be unavailable during the update. + Value can be an absolute number (ex: 5) or a percentage of desired machines (ex: 10%). + Absolute number is calculated from percentage by rounding down. + This can not be 0 if MaxSurge is 0. + Example: when this is set to 30%, the old machine set can be scaled down to 70% of desired machines + immediately when the update starts. Once new machines are ready, old machine set + can be scaled down further, followed by scaling up the new machine set, ensuring + that the total number of machines available at all times during the update is at + least 70% of desired machines. + x-kubernetes-int-or-string: true + orchestrationType: + description: OrchestrationType specifies the orchestration + type for the inplace update. + type: string + type: object + rollingUpdate: + description: |- + Rolling update config params. Present only if MachineDeploymentStrategyType = + RollingUpdate. + properties: + maxSurge: + anyOf: + - type: integer + - type: string + description: |- + The maximum number of machines that can be scheduled above the desired number of + machines. + Value can be an absolute number (ex: 5) or a percentage of desired machines (ex: 10%). + This can not be 0 if MaxUnavailable is 0. + Absolute number is calculated from percentage by rounding up. + Example: when this is set to 30%, the new machine set can be scaled up immediately when + the update starts, such that the total number of old and new machines does not exceed + 130% of desired machines. Once old machines have been killed, + new machine set can be scaled up further, ensuring that total number of machines running + at any time during the update is utmost 130% of desired machines. + x-kubernetes-int-or-string: true + maxUnavailable: + anyOf: + - type: integer + - type: string + description: |- + The maximum number of machines that can be unavailable during the update. + Value can be an absolute number (ex: 5) or a percentage of desired machines (ex: 10%). + Absolute number is calculated from percentage by rounding down. + This can not be 0 if MaxSurge is 0. + Example: when this is set to 30%, the old machine set can be scaled down to 70% of desired machines + immediately when the update starts. Once new machines are ready, old machine set + can be scaled down further, followed by scaling up the new machine set, ensuring + that the total number of machines available at all times during the update is at + least 70% of desired machines. + x-kubernetes-int-or-string: true + type: object + type: + description: Type of MachineDeployment. Can be "Recreate" or "RollingUpdate". + Default is RollingUpdate. + type: string + type: object + template: + description: Template describes the machines that will be created. + properties: + metadata: + description: |- + Standard object's metadata. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata + type: object + x-kubernetes-preserve-unknown-fields: true + spec: + description: |- + Specification of the desired behavior of the machine. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status + properties: + class: + description: Class contains the machineclass attributes of + a machine + properties: + apiGroup: + description: API group to which it belongs + type: string + kind: + description: Kind for machine class + type: string + name: + description: Name of machine class + type: string + type: object + creationTimeout: + description: MachineCreationTimeout is the timeout after which + machinie creation is declared failed. + type: string + disableHealthTimeout: + description: |- + DisableHealthTimeout if set to true, health timeout will be ignored. Leading to machine never being declared failed. + This is intended to be used only for in-place updates. + type: boolean + drainTimeout: + description: MachineDraintimeout is the timeout after which + machine is forcefully deleted. + type: string + healthTimeout: + description: MachineHealthTimeout is the timeout after which + machine is declared unhealhty/failed. + type: string + inPlaceUpdateTimeout: + description: MachineInPlaceUpdateTimeout is the timeout after + which in-place update is declared failed. + type: string + machinePreserveTimeout: + description: MachinePreserveTimeout is the timeout after which + the machine preservation is stopped + type: string + maxEvictRetries: + description: MaxEvictRetries is the number of retries that + will be attempted while draining the node. + format: int32 + type: integer + nodeConditions: + description: NodeConditions are the set of conditions if set + to true for MachineHealthTimeOut, machine will be declared + failed. + type: string + nodeTemplate: + description: NodeTemplateSpec describes the data a node should + have when created from a template + properties: + metadata: + type: object + x-kubernetes-preserve-unknown-fields: true + spec: + description: NodeSpec describes the attributes that a + node is created with. + properties: + configSource: + description: 'Deprecated: Previously used to specify + the source of the node''s configuration for the + DynamicKubeletConfig feature. This feature is removed.' + properties: + configMap: + description: ConfigMap is a reference to a Node's + ConfigMap + properties: + kubeletConfigKey: + description: |- + KubeletConfigKey declares which key of the referenced ConfigMap corresponds to the KubeletConfiguration structure + This field is required in all cases. + type: string + name: + description: |- + Name is the metadata.name of the referenced ConfigMap. + This field is required in all cases. + type: string + namespace: + description: |- + Namespace is the metadata.namespace of the referenced ConfigMap. + This field is required in all cases. + type: string + resourceVersion: + description: |- + ResourceVersion is the metadata.ResourceVersion of the referenced ConfigMap. + This field is forbidden in Node.Spec, and required in Node.Status. + type: string + uid: + description: |- + UID is the metadata.UID of the referenced ConfigMap. + This field is forbidden in Node.Spec, and required in Node.Status. + type: string + required: + - kubeletConfigKey + - name + - namespace + type: object + type: object + externalID: + description: |- + Deprecated. Not all kubelets will set this field. Remove field after 1.13. + see: https://issues.k8s.io/61966 + type: string + podCIDR: + description: PodCIDR represents the pod IP range assigned + to the node. + type: string + podCIDRs: + description: |- + podCIDRs represents the IP ranges assigned to the node for usage by Pods on that node. If this + field is specified, the 0th entry must match the podCIDR field. It may contain at most 1 value for + each of IPv4 and IPv6. + items: + type: string + type: array + x-kubernetes-list-type: set + providerID: + description: 'ID of the node assigned by the cloud + provider in the format: ://' + type: string + taints: + description: If specified, the node's taints. + items: + description: |- + The node this Taint is attached to has the "effect" on + any pod that does not tolerate the Taint. + properties: + effect: + description: |- + Required. The effect of the taint on pods + that do not tolerate the taint. + Valid effects are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: Required. The taint key to be applied + to a node. + type: string + timeAdded: + description: |- + TimeAdded represents the time at which the taint was added. + It is only written for NoExecute taints. + format: date-time + type: string + value: + description: The taint value corresponding to + the taint key. + type: string + required: + - effect + - key + type: object + type: array + x-kubernetes-list-type: atomic + unschedulable: + description: |- + Unschedulable controls node schedulability of new pods. By default, node is schedulable. + More info: https://kubernetes.io/docs/concepts/nodes/node/#manual-node-administration + type: boolean + type: object + type: object + providerID: + description: ProviderID represents the provider's unique ID + given to a machine + type: string + type: object + type: object + required: + - template + type: object + status: + description: Most recently observed status of the MachineDeployment. + properties: + availableReplicas: + description: Total number of available machines (ready for at least + minReadySeconds) targeted by this MachineDeployment. + format: int32 + type: integer + collisionCount: + description: |- + Count of hash collisions for the MachineDeployment. The MachineDeployment controller uses this + field as a collision avoidance mechanism when it needs to create the name for the + newest MachineSet. + format: int32 + type: integer + conditions: + description: Represents the latest available observations of a MachineDeployment's + current state. + items: + description: MachineDeploymentCondition describes the state of a + MachineDeployment at a certain point. + properties: + lastTransitionTime: + description: Last time the condition transitioned from one status + to another. + format: date-time + type: string + lastUpdateTime: + description: The last time this condition was updated. + format: date-time + type: string + message: + description: A human readable message indicating details about + the transition. + type: string + reason: + description: The reason for the condition's last transition. + type: string + status: + description: Status of the condition, one of True, False, Unknown. + type: string + type: + description: Type of MachineDeployment condition. + type: string + required: + - status + - type + type: object + type: array + failedMachines: + description: FailedMachines has summary of machines on which lastOperation + Failed + items: + description: MachineSummary store the summary of machine. + properties: + lastOperation: + description: Last operation refers to the status of the last + operation performed + properties: + description: + description: Description of the current operation + type: string + errorCode: + description: ErrorCode of the current operation if any + type: string + lastUpdateTime: + description: Last update time of current operation + format: date-time + type: string + state: + description: State of operation + type: string + type: + description: Type of operation + type: string + type: object + name: + description: Name of the machine object + type: string + ownerRef: + description: OwnerRef + type: string + providerID: + description: ProviderID represents the provider's unique ID + given to a machine + type: string + type: object + type: array + observedGeneration: + description: The generation observed by the MachineDeployment controller. + format: int64 + type: integer + readyReplicas: + description: Total number of ready machines targeted by this MachineDeployment. + format: int32 + type: integer + replicas: + description: Total number of non-terminated machines targeted by this + MachineDeployment (their labels match the selector). + format: int32 + type: integer + unavailableReplicas: + description: |- + Total number of unavailable machines targeted by this MachineDeployment. This is the total number of + machines that are still required for the MachineDeployment to have 100% available capacity. They may + either be machines that are running but not yet available or machines that still have not been created. + format: int32 + type: integer + updatedReplicas: + description: Total number of non-terminated machines targeted by this + MachineDeployment that have the desired template spec. + format: int32 + type: integer + type: object + type: object + served: true + storage: true + subresources: + scale: + specReplicasPath: .spec.replicas + statusReplicasPath: .status.replicas + status: {} diff --git a/kubernetes/crds/machine.sapcloud.io_machines.yaml b/kubernetes/crds/machine.sapcloud.io_machines.yaml new file mode 100644 index 000000000..fcea16750 --- /dev/null +++ b/kubernetes/crds/machine.sapcloud.io_machines.yaml @@ -0,0 +1,333 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.1 + name: machines.machine.sapcloud.io +spec: + group: machine.sapcloud.io + names: + kind: Machine + listKind: MachineList + plural: machines + shortNames: + - mc + singular: machine + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Current status of the machine. + jsonPath: .status.currentStatus.phase + name: Status + type: string + - description: |- + CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. + Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata + jsonPath: .metadata.creationTimestamp + name: Age + type: date + - description: Node backing the machine object + jsonPath: .metadata.labels.node + name: Node + type: string + - description: ProviderID of the infra instance backing the machine object + jsonPath: .spec.providerID + name: ProviderID + priority: 1 + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: Machine is the representation of a physical or virtual machine. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Spec contains the specification of the machine + properties: + class: + description: Class contains the machineclass attributes of a machine + properties: + apiGroup: + description: API group to which it belongs + type: string + kind: + description: Kind for machine class + type: string + name: + description: Name of machine class + type: string + type: object + creationTimeout: + description: MachineCreationTimeout is the timeout after which machinie + creation is declared failed. + type: string + disableHealthTimeout: + description: |- + DisableHealthTimeout if set to true, health timeout will be ignored. Leading to machine never being declared failed. + This is intended to be used only for in-place updates. + type: boolean + drainTimeout: + description: MachineDraintimeout is the timeout after which machine + is forcefully deleted. + type: string + healthTimeout: + description: MachineHealthTimeout is the timeout after which machine + is declared unhealhty/failed. + type: string + inPlaceUpdateTimeout: + description: MachineInPlaceUpdateTimeout is the timeout after which + in-place update is declared failed. + type: string + machinePreserveTimeout: + description: MachinePreserveTimeout is the timeout after which the + machine preservation is stopped + type: string + maxEvictRetries: + description: MaxEvictRetries is the number of retries that will be + attempted while draining the node. + format: int32 + type: integer + nodeConditions: + description: NodeConditions are the set of conditions if set to true + for MachineHealthTimeOut, machine will be declared failed. + type: string + nodeTemplate: + description: NodeTemplateSpec describes the data a node should have + when created from a template + properties: + metadata: + type: object + x-kubernetes-preserve-unknown-fields: true + spec: + description: NodeSpec describes the attributes that a node is + created with. + properties: + configSource: + description: 'Deprecated: Previously used to specify the source + of the node''s configuration for the DynamicKubeletConfig + feature. This feature is removed.' + properties: + configMap: + description: ConfigMap is a reference to a Node's ConfigMap + properties: + kubeletConfigKey: + description: |- + KubeletConfigKey declares which key of the referenced ConfigMap corresponds to the KubeletConfiguration structure + This field is required in all cases. + type: string + name: + description: |- + Name is the metadata.name of the referenced ConfigMap. + This field is required in all cases. + type: string + namespace: + description: |- + Namespace is the metadata.namespace of the referenced ConfigMap. + This field is required in all cases. + type: string + resourceVersion: + description: |- + ResourceVersion is the metadata.ResourceVersion of the referenced ConfigMap. + This field is forbidden in Node.Spec, and required in Node.Status. + type: string + uid: + description: |- + UID is the metadata.UID of the referenced ConfigMap. + This field is forbidden in Node.Spec, and required in Node.Status. + type: string + required: + - kubeletConfigKey + - name + - namespace + type: object + type: object + externalID: + description: |- + Deprecated. Not all kubelets will set this field. Remove field after 1.13. + see: https://issues.k8s.io/61966 + type: string + podCIDR: + description: PodCIDR represents the pod IP range assigned + to the node. + type: string + podCIDRs: + description: |- + podCIDRs represents the IP ranges assigned to the node for usage by Pods on that node. If this + field is specified, the 0th entry must match the podCIDR field. It may contain at most 1 value for + each of IPv4 and IPv6. + items: + type: string + type: array + x-kubernetes-list-type: set + providerID: + description: 'ID of the node assigned by the cloud provider + in the format: ://' + type: string + taints: + description: If specified, the node's taints. + items: + description: |- + The node this Taint is attached to has the "effect" on + any pod that does not tolerate the Taint. + properties: + effect: + description: |- + Required. The effect of the taint on pods + that do not tolerate the taint. + Valid effects are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: Required. The taint key to be applied to + a node. + type: string + timeAdded: + description: |- + TimeAdded represents the time at which the taint was added. + It is only written for NoExecute taints. + format: date-time + type: string + value: + description: The taint value corresponding to the taint + key. + type: string + required: + - effect + - key + type: object + type: array + x-kubernetes-list-type: atomic + unschedulable: + description: |- + Unschedulable controls node schedulability of new pods. By default, node is schedulable. + More info: https://kubernetes.io/docs/concepts/nodes/node/#manual-node-administration + type: boolean + type: object + type: object + providerID: + description: ProviderID represents the provider's unique ID given + to a machine + type: string + type: object + status: + description: Status contains fields depicting the status + properties: + addresses: + description: |- + Addresses of this machines. This field is only present if the MCM provider runs without a target cluster and may + be used by clients to determine how to connect to the machine, instead of the `Node.status.addresses` field. + items: + description: NodeAddress contains information for the node's address. + properties: + address: + description: The node address. + type: string + type: + description: Node address type, one of Hostname, ExternalIP + or InternalIP. + type: string + required: + - address + - type + type: object + type: array + conditions: + description: Conditions of this machine, same as node + items: + description: NodeCondition contains condition information for a + node. + properties: + lastHeartbeatTime: + description: Last time we got an update on a given condition. + format: date-time + type: string + lastTransitionTime: + description: Last time the condition transit from one status + to another. + format: date-time + type: string + message: + description: Human readable message indicating details about + last transition. + type: string + reason: + description: (brief) reason for the condition's last transition. + type: string + status: + description: Status of the condition, one of True, False, Unknown. + type: string + type: + description: Type of node condition. + type: string + required: + - status + - type + type: object + type: array + currentStatus: + description: Current status of the machine object + properties: + lastUpdateTime: + description: Last update time of current status + format: date-time + type: string + phase: + description: MachinePhase is a label for the condition of a machine + at the current time. + type: string + preserveExpiryTime: + description: PreserveExpiryTime is the time at which MCM will + stop preserving the machine + format: date-time + type: string + timeoutActive: + type: boolean + type: object + lastKnownState: + description: |- + LastKnownState can store details of the last known state of the VM by the plugins. + It can be used by future operation calls to determine current infrastucture state + type: string + lastOperation: + description: Last operation refers to the status of the last operation + performed + properties: + description: + description: Description of the current operation + type: string + errorCode: + description: ErrorCode of the current operation if any + type: string + lastUpdateTime: + description: Last update time of current operation + format: date-time + type: string + state: + description: State of operation + type: string + type: + description: Type of operation + type: string + type: object + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/kubernetes/crds/machine.sapcloud.io_machinesets.yaml b/kubernetes/crds/machine.sapcloud.io_machinesets.yaml new file mode 100644 index 000000000..46445131f --- /dev/null +++ b/kubernetes/crds/machine.sapcloud.io_machinesets.yaml @@ -0,0 +1,447 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.1 + name: machinesets.machine.sapcloud.io +spec: + group: machine.sapcloud.io + names: + kind: MachineSet + listKind: MachineSetList + plural: machinesets + shortNames: + - mcs + singular: machineset + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Number of desired replicas. + jsonPath: .spec.replicas + name: Desired + type: integer + - description: Number of actual replicas. + jsonPath: .status.replicas + name: Current + type: integer + - description: Number of ready replicas for this machine set. + jsonPath: .status.readyReplicas + name: Ready + type: integer + - description: |- + CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. + Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: MachineSet TODO + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: MachineSetSpec is the specification of a MachineSet. + properties: + autoPreserveFailedMachineMax: + format: int32 + type: integer + machineClass: + description: ClassSpec is the class specification of machine + properties: + apiGroup: + description: API group to which it belongs + type: string + kind: + description: Kind for machine class + type: string + name: + description: Name of machine class + type: string + type: object + minReadySeconds: + format: int32 + type: integer + replicas: + format: int32 + type: integer + selector: + description: |- + A label selector is a label query over a set of resources. The result of matchLabels and + matchExpressions are ANDed. An empty label selector matches all objects. A null + label selector matches no objects. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + template: + description: MachineTemplateSpec describes the data a machine should + have when created from a template + properties: + metadata: + description: |- + Standard object's metadata. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata + type: object + x-kubernetes-preserve-unknown-fields: true + spec: + description: |- + Specification of the desired behavior of the machine. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status + properties: + class: + description: Class contains the machineclass attributes of + a machine + properties: + apiGroup: + description: API group to which it belongs + type: string + kind: + description: Kind for machine class + type: string + name: + description: Name of machine class + type: string + type: object + creationTimeout: + description: MachineCreationTimeout is the timeout after which + machinie creation is declared failed. + type: string + disableHealthTimeout: + description: |- + DisableHealthTimeout if set to true, health timeout will be ignored. Leading to machine never being declared failed. + This is intended to be used only for in-place updates. + type: boolean + drainTimeout: + description: MachineDraintimeout is the timeout after which + machine is forcefully deleted. + type: string + healthTimeout: + description: MachineHealthTimeout is the timeout after which + machine is declared unhealhty/failed. + type: string + inPlaceUpdateTimeout: + description: MachineInPlaceUpdateTimeout is the timeout after + which in-place update is declared failed. + type: string + machinePreserveTimeout: + description: MachinePreserveTimeout is the timeout after which + the machine preservation is stopped + type: string + maxEvictRetries: + description: MaxEvictRetries is the number of retries that + will be attempted while draining the node. + format: int32 + type: integer + nodeConditions: + description: NodeConditions are the set of conditions if set + to true for MachineHealthTimeOut, machine will be declared + failed. + type: string + nodeTemplate: + description: NodeTemplateSpec describes the data a node should + have when created from a template + properties: + metadata: + type: object + x-kubernetes-preserve-unknown-fields: true + spec: + description: NodeSpec describes the attributes that a + node is created with. + properties: + configSource: + description: 'Deprecated: Previously used to specify + the source of the node''s configuration for the + DynamicKubeletConfig feature. This feature is removed.' + properties: + configMap: + description: ConfigMap is a reference to a Node's + ConfigMap + properties: + kubeletConfigKey: + description: |- + KubeletConfigKey declares which key of the referenced ConfigMap corresponds to the KubeletConfiguration structure + This field is required in all cases. + type: string + name: + description: |- + Name is the metadata.name of the referenced ConfigMap. + This field is required in all cases. + type: string + namespace: + description: |- + Namespace is the metadata.namespace of the referenced ConfigMap. + This field is required in all cases. + type: string + resourceVersion: + description: |- + ResourceVersion is the metadata.ResourceVersion of the referenced ConfigMap. + This field is forbidden in Node.Spec, and required in Node.Status. + type: string + uid: + description: |- + UID is the metadata.UID of the referenced ConfigMap. + This field is forbidden in Node.Spec, and required in Node.Status. + type: string + required: + - kubeletConfigKey + - name + - namespace + type: object + type: object + externalID: + description: |- + Deprecated. Not all kubelets will set this field. Remove field after 1.13. + see: https://issues.k8s.io/61966 + type: string + podCIDR: + description: PodCIDR represents the pod IP range assigned + to the node. + type: string + podCIDRs: + description: |- + podCIDRs represents the IP ranges assigned to the node for usage by Pods on that node. If this + field is specified, the 0th entry must match the podCIDR field. It may contain at most 1 value for + each of IPv4 and IPv6. + items: + type: string + type: array + x-kubernetes-list-type: set + providerID: + description: 'ID of the node assigned by the cloud + provider in the format: ://' + type: string + taints: + description: If specified, the node's taints. + items: + description: |- + The node this Taint is attached to has the "effect" on + any pod that does not tolerate the Taint. + properties: + effect: + description: |- + Required. The effect of the taint on pods + that do not tolerate the taint. + Valid effects are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: Required. The taint key to be applied + to a node. + type: string + timeAdded: + description: |- + TimeAdded represents the time at which the taint was added. + It is only written for NoExecute taints. + format: date-time + type: string + value: + description: The taint value corresponding to + the taint key. + type: string + required: + - effect + - key + type: object + type: array + x-kubernetes-list-type: atomic + unschedulable: + description: |- + Unschedulable controls node schedulability of new pods. By default, node is schedulable. + More info: https://kubernetes.io/docs/concepts/nodes/node/#manual-node-administration + type: boolean + type: object + type: object + providerID: + description: ProviderID represents the provider's unique ID + given to a machine + type: string + type: object + type: object + type: object + status: + description: MachineSetStatus holds the most recently observed status + of MachineSet. + properties: + autoPreserveFailedMachineCount: + description: AutoPreserveFailedMachineCount has a count of the number + of failed machines in the machineset that have been auto-preserved + format: int32 + type: integer + availableReplicas: + description: The number of available replicas (ready for at least + minReadySeconds) for this replica set. + format: int32 + type: integer + failedMachines: + description: FailedMachines has summary of machines on which lastOperation + Failed + items: + description: MachineSummary store the summary of machine. + properties: + lastOperation: + description: Last operation refers to the status of the last + operation performed + properties: + description: + description: Description of the current operation + type: string + errorCode: + description: ErrorCode of the current operation if any + type: string + lastUpdateTime: + description: Last update time of current operation + format: date-time + type: string + state: + description: State of operation + type: string + type: + description: Type of operation + type: string + type: object + name: + description: Name of the machine object + type: string + ownerRef: + description: OwnerRef + type: string + providerID: + description: ProviderID represents the provider's unique ID + given to a machine + type: string + type: object + type: array + fullyLabeledReplicas: + description: The number of pods that have labels matching the labels + of the pod template of the replicaset. + format: int32 + type: integer + lastOperation: + description: LastOperation performed + properties: + description: + description: Description of the current operation + type: string + errorCode: + description: ErrorCode of the current operation if any + type: string + lastUpdateTime: + description: Last update time of current operation + format: date-time + type: string + state: + description: State of operation + type: string + type: + description: Type of operation + type: string + type: object + machineSetCondition: + description: Represents the latest available observations of a replica + set's current state. + items: + description: MachineSetCondition describes the state of a machine + set at a certain point. + properties: + lastTransitionTime: + description: The last time the condition transitioned from one + status to another. + format: date-time + type: string + message: + description: A human readable message indicating details about + the transition. + type: string + reason: + description: The reason for the condition's last transition. + type: string + status: + description: Status of the condition, one of True, False, Unknown. + type: string + type: + description: Type of machine set condition. + type: string + required: + - status + - type + type: object + type: array + observedGeneration: + description: ObservedGeneration is the most recent generation observed + by the controller. + format: int64 + type: integer + readyReplicas: + description: The number of ready replicas for this replica set. + format: int32 + type: integer + replicas: + description: Replicas is the number of actual replicas. + format: int32 + type: integer + type: object + type: object + served: true + storage: true + subresources: + scale: + specReplicasPath: .spec.replicas + statusReplicasPath: .status.replicas + status: {} diff --git a/pkg/apis/machine/v1alpha1/zz_generated.conversion.go b/pkg/apis/machine/v1alpha1/zz_generated.conversion.go new file mode 100644 index 000000000..d503e95ae --- /dev/null +++ b/pkg/apis/machine/v1alpha1/zz_generated.conversion.go @@ -0,0 +1,1179 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +// SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors +// +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by conversion-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + unsafe "unsafe" + + machine "github.com/gardener/machine-controller-manager/pkg/apis/machine" + corev1 "k8s.io/api/core/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + conversion "k8s.io/apimachinery/pkg/conversion" + runtime "k8s.io/apimachinery/pkg/runtime" + intstr "k8s.io/apimachinery/pkg/util/intstr" +) + +func init() { + localSchemeBuilder.Register(RegisterConversions) +} + +// RegisterConversions adds conversion functions to the given scheme. +// Public to allow building arbitrary schemes. +func RegisterConversions(s *runtime.Scheme) error { + if err := s.AddGeneratedConversionFunc((*ClassSpec)(nil), (*machine.ClassSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_ClassSpec_To_machine_ClassSpec(a.(*ClassSpec), b.(*machine.ClassSpec), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*machine.ClassSpec)(nil), (*ClassSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_machine_ClassSpec_To_v1alpha1_ClassSpec(a.(*machine.ClassSpec), b.(*ClassSpec), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*CurrentStatus)(nil), (*machine.CurrentStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_CurrentStatus_To_machine_CurrentStatus(a.(*CurrentStatus), b.(*machine.CurrentStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*machine.CurrentStatus)(nil), (*CurrentStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_machine_CurrentStatus_To_v1alpha1_CurrentStatus(a.(*machine.CurrentStatus), b.(*CurrentStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*InPlaceUpdateMachineDeployment)(nil), (*machine.InPlaceUpdateMachineDeployment)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_InPlaceUpdateMachineDeployment_To_machine_InPlaceUpdateMachineDeployment(a.(*InPlaceUpdateMachineDeployment), b.(*machine.InPlaceUpdateMachineDeployment), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*machine.InPlaceUpdateMachineDeployment)(nil), (*InPlaceUpdateMachineDeployment)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_machine_InPlaceUpdateMachineDeployment_To_v1alpha1_InPlaceUpdateMachineDeployment(a.(*machine.InPlaceUpdateMachineDeployment), b.(*InPlaceUpdateMachineDeployment), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*LastOperation)(nil), (*machine.LastOperation)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_LastOperation_To_machine_LastOperation(a.(*LastOperation), b.(*machine.LastOperation), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*machine.LastOperation)(nil), (*LastOperation)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_machine_LastOperation_To_v1alpha1_LastOperation(a.(*machine.LastOperation), b.(*LastOperation), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*Machine)(nil), (*machine.Machine)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_Machine_To_machine_Machine(a.(*Machine), b.(*machine.Machine), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*machine.Machine)(nil), (*Machine)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_machine_Machine_To_v1alpha1_Machine(a.(*machine.Machine), b.(*Machine), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*MachineClass)(nil), (*machine.MachineClass)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_MachineClass_To_machine_MachineClass(a.(*MachineClass), b.(*machine.MachineClass), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*machine.MachineClass)(nil), (*MachineClass)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_machine_MachineClass_To_v1alpha1_MachineClass(a.(*machine.MachineClass), b.(*MachineClass), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*MachineClassList)(nil), (*machine.MachineClassList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_MachineClassList_To_machine_MachineClassList(a.(*MachineClassList), b.(*machine.MachineClassList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*machine.MachineClassList)(nil), (*MachineClassList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_machine_MachineClassList_To_v1alpha1_MachineClassList(a.(*machine.MachineClassList), b.(*MachineClassList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*MachineConfiguration)(nil), (*machine.MachineConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_MachineConfiguration_To_machine_MachineConfiguration(a.(*MachineConfiguration), b.(*machine.MachineConfiguration), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*machine.MachineConfiguration)(nil), (*MachineConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_machine_MachineConfiguration_To_v1alpha1_MachineConfiguration(a.(*machine.MachineConfiguration), b.(*MachineConfiguration), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*MachineDeployment)(nil), (*machine.MachineDeployment)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_MachineDeployment_To_machine_MachineDeployment(a.(*MachineDeployment), b.(*machine.MachineDeployment), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*machine.MachineDeployment)(nil), (*MachineDeployment)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_machine_MachineDeployment_To_v1alpha1_MachineDeployment(a.(*machine.MachineDeployment), b.(*MachineDeployment), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*MachineDeploymentCondition)(nil), (*machine.MachineDeploymentCondition)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_MachineDeploymentCondition_To_machine_MachineDeploymentCondition(a.(*MachineDeploymentCondition), b.(*machine.MachineDeploymentCondition), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*machine.MachineDeploymentCondition)(nil), (*MachineDeploymentCondition)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_machine_MachineDeploymentCondition_To_v1alpha1_MachineDeploymentCondition(a.(*machine.MachineDeploymentCondition), b.(*MachineDeploymentCondition), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*MachineDeploymentList)(nil), (*machine.MachineDeploymentList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_MachineDeploymentList_To_machine_MachineDeploymentList(a.(*MachineDeploymentList), b.(*machine.MachineDeploymentList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*machine.MachineDeploymentList)(nil), (*MachineDeploymentList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_machine_MachineDeploymentList_To_v1alpha1_MachineDeploymentList(a.(*machine.MachineDeploymentList), b.(*MachineDeploymentList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*MachineDeploymentSpec)(nil), (*machine.MachineDeploymentSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_MachineDeploymentSpec_To_machine_MachineDeploymentSpec(a.(*MachineDeploymentSpec), b.(*machine.MachineDeploymentSpec), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*machine.MachineDeploymentSpec)(nil), (*MachineDeploymentSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_machine_MachineDeploymentSpec_To_v1alpha1_MachineDeploymentSpec(a.(*machine.MachineDeploymentSpec), b.(*MachineDeploymentSpec), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*MachineDeploymentStatus)(nil), (*machine.MachineDeploymentStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_MachineDeploymentStatus_To_machine_MachineDeploymentStatus(a.(*MachineDeploymentStatus), b.(*machine.MachineDeploymentStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*machine.MachineDeploymentStatus)(nil), (*MachineDeploymentStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_machine_MachineDeploymentStatus_To_v1alpha1_MachineDeploymentStatus(a.(*machine.MachineDeploymentStatus), b.(*MachineDeploymentStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*MachineDeploymentStrategy)(nil), (*machine.MachineDeploymentStrategy)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_MachineDeploymentStrategy_To_machine_MachineDeploymentStrategy(a.(*MachineDeploymentStrategy), b.(*machine.MachineDeploymentStrategy), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*machine.MachineDeploymentStrategy)(nil), (*MachineDeploymentStrategy)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_machine_MachineDeploymentStrategy_To_v1alpha1_MachineDeploymentStrategy(a.(*machine.MachineDeploymentStrategy), b.(*MachineDeploymentStrategy), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*MachineList)(nil), (*machine.MachineList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_MachineList_To_machine_MachineList(a.(*MachineList), b.(*machine.MachineList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*machine.MachineList)(nil), (*MachineList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_machine_MachineList_To_v1alpha1_MachineList(a.(*machine.MachineList), b.(*MachineList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*MachineSet)(nil), (*machine.MachineSet)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_MachineSet_To_machine_MachineSet(a.(*MachineSet), b.(*machine.MachineSet), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*machine.MachineSet)(nil), (*MachineSet)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_machine_MachineSet_To_v1alpha1_MachineSet(a.(*machine.MachineSet), b.(*MachineSet), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*MachineSetCondition)(nil), (*machine.MachineSetCondition)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_MachineSetCondition_To_machine_MachineSetCondition(a.(*MachineSetCondition), b.(*machine.MachineSetCondition), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*machine.MachineSetCondition)(nil), (*MachineSetCondition)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_machine_MachineSetCondition_To_v1alpha1_MachineSetCondition(a.(*machine.MachineSetCondition), b.(*MachineSetCondition), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*MachineSetList)(nil), (*machine.MachineSetList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_MachineSetList_To_machine_MachineSetList(a.(*MachineSetList), b.(*machine.MachineSetList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*machine.MachineSetList)(nil), (*MachineSetList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_machine_MachineSetList_To_v1alpha1_MachineSetList(a.(*machine.MachineSetList), b.(*MachineSetList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*MachineSetSpec)(nil), (*machine.MachineSetSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_MachineSetSpec_To_machine_MachineSetSpec(a.(*MachineSetSpec), b.(*machine.MachineSetSpec), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*machine.MachineSetSpec)(nil), (*MachineSetSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_machine_MachineSetSpec_To_v1alpha1_MachineSetSpec(a.(*machine.MachineSetSpec), b.(*MachineSetSpec), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*MachineSetStatus)(nil), (*machine.MachineSetStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_MachineSetStatus_To_machine_MachineSetStatus(a.(*MachineSetStatus), b.(*machine.MachineSetStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*machine.MachineSetStatus)(nil), (*MachineSetStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_machine_MachineSetStatus_To_v1alpha1_MachineSetStatus(a.(*machine.MachineSetStatus), b.(*MachineSetStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*MachineSpec)(nil), (*machine.MachineSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_MachineSpec_To_machine_MachineSpec(a.(*MachineSpec), b.(*machine.MachineSpec), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*machine.MachineSpec)(nil), (*MachineSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_machine_MachineSpec_To_v1alpha1_MachineSpec(a.(*machine.MachineSpec), b.(*MachineSpec), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*MachineStatus)(nil), (*machine.MachineStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_MachineStatus_To_machine_MachineStatus(a.(*MachineStatus), b.(*machine.MachineStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*machine.MachineStatus)(nil), (*MachineStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_machine_MachineStatus_To_v1alpha1_MachineStatus(a.(*machine.MachineStatus), b.(*MachineStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*MachineSummary)(nil), (*machine.MachineSummary)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_MachineSummary_To_machine_MachineSummary(a.(*MachineSummary), b.(*machine.MachineSummary), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*machine.MachineSummary)(nil), (*MachineSummary)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_machine_MachineSummary_To_v1alpha1_MachineSummary(a.(*machine.MachineSummary), b.(*MachineSummary), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*MachineTemplateSpec)(nil), (*machine.MachineTemplateSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_MachineTemplateSpec_To_machine_MachineTemplateSpec(a.(*MachineTemplateSpec), b.(*machine.MachineTemplateSpec), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*machine.MachineTemplateSpec)(nil), (*MachineTemplateSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_machine_MachineTemplateSpec_To_v1alpha1_MachineTemplateSpec(a.(*machine.MachineTemplateSpec), b.(*MachineTemplateSpec), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*NodeTemplate)(nil), (*machine.NodeTemplate)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_NodeTemplate_To_machine_NodeTemplate(a.(*NodeTemplate), b.(*machine.NodeTemplate), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*machine.NodeTemplate)(nil), (*NodeTemplate)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_machine_NodeTemplate_To_v1alpha1_NodeTemplate(a.(*machine.NodeTemplate), b.(*NodeTemplate), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*NodeTemplateSpec)(nil), (*machine.NodeTemplateSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_NodeTemplateSpec_To_machine_NodeTemplateSpec(a.(*NodeTemplateSpec), b.(*machine.NodeTemplateSpec), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*machine.NodeTemplateSpec)(nil), (*NodeTemplateSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_machine_NodeTemplateSpec_To_v1alpha1_NodeTemplateSpec(a.(*machine.NodeTemplateSpec), b.(*NodeTemplateSpec), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*RollbackConfig)(nil), (*machine.RollbackConfig)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_RollbackConfig_To_machine_RollbackConfig(a.(*RollbackConfig), b.(*machine.RollbackConfig), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*machine.RollbackConfig)(nil), (*RollbackConfig)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_machine_RollbackConfig_To_v1alpha1_RollbackConfig(a.(*machine.RollbackConfig), b.(*RollbackConfig), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*RollingUpdateMachineDeployment)(nil), (*machine.RollingUpdateMachineDeployment)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_RollingUpdateMachineDeployment_To_machine_RollingUpdateMachineDeployment(a.(*RollingUpdateMachineDeployment), b.(*machine.RollingUpdateMachineDeployment), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*machine.RollingUpdateMachineDeployment)(nil), (*RollingUpdateMachineDeployment)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_machine_RollingUpdateMachineDeployment_To_v1alpha1_RollingUpdateMachineDeployment(a.(*machine.RollingUpdateMachineDeployment), b.(*RollingUpdateMachineDeployment), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*UpdateConfiguration)(nil), (*machine.UpdateConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_UpdateConfiguration_To_machine_UpdateConfiguration(a.(*UpdateConfiguration), b.(*machine.UpdateConfiguration), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*machine.UpdateConfiguration)(nil), (*UpdateConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_machine_UpdateConfiguration_To_v1alpha1_UpdateConfiguration(a.(*machine.UpdateConfiguration), b.(*UpdateConfiguration), scope) + }); err != nil { + return err + } + return nil +} + +func autoConvert_v1alpha1_ClassSpec_To_machine_ClassSpec(in *ClassSpec, out *machine.ClassSpec, s conversion.Scope) error { + out.APIGroup = in.APIGroup + out.Kind = in.Kind + out.Name = in.Name + return nil +} + +// Convert_v1alpha1_ClassSpec_To_machine_ClassSpec is an autogenerated conversion function. +func Convert_v1alpha1_ClassSpec_To_machine_ClassSpec(in *ClassSpec, out *machine.ClassSpec, s conversion.Scope) error { + return autoConvert_v1alpha1_ClassSpec_To_machine_ClassSpec(in, out, s) +} + +func autoConvert_machine_ClassSpec_To_v1alpha1_ClassSpec(in *machine.ClassSpec, out *ClassSpec, s conversion.Scope) error { + out.APIGroup = in.APIGroup + out.Kind = in.Kind + out.Name = in.Name + return nil +} + +// Convert_machine_ClassSpec_To_v1alpha1_ClassSpec is an autogenerated conversion function. +func Convert_machine_ClassSpec_To_v1alpha1_ClassSpec(in *machine.ClassSpec, out *ClassSpec, s conversion.Scope) error { + return autoConvert_machine_ClassSpec_To_v1alpha1_ClassSpec(in, out, s) +} + +func autoConvert_v1alpha1_CurrentStatus_To_machine_CurrentStatus(in *CurrentStatus, out *machine.CurrentStatus, s conversion.Scope) error { + out.Phase = machine.MachinePhase(in.Phase) + out.TimeoutActive = in.TimeoutActive + out.LastUpdateTime = in.LastUpdateTime + out.PreserveExpiryTime = (*v1.Time)(unsafe.Pointer(in.PreserveExpiryTime)) + return nil +} + +// Convert_v1alpha1_CurrentStatus_To_machine_CurrentStatus is an autogenerated conversion function. +func Convert_v1alpha1_CurrentStatus_To_machine_CurrentStatus(in *CurrentStatus, out *machine.CurrentStatus, s conversion.Scope) error { + return autoConvert_v1alpha1_CurrentStatus_To_machine_CurrentStatus(in, out, s) +} + +func autoConvert_machine_CurrentStatus_To_v1alpha1_CurrentStatus(in *machine.CurrentStatus, out *CurrentStatus, s conversion.Scope) error { + out.Phase = MachinePhase(in.Phase) + out.TimeoutActive = in.TimeoutActive + out.LastUpdateTime = in.LastUpdateTime + out.PreserveExpiryTime = (*v1.Time)(unsafe.Pointer(in.PreserveExpiryTime)) + return nil +} + +// Convert_machine_CurrentStatus_To_v1alpha1_CurrentStatus is an autogenerated conversion function. +func Convert_machine_CurrentStatus_To_v1alpha1_CurrentStatus(in *machine.CurrentStatus, out *CurrentStatus, s conversion.Scope) error { + return autoConvert_machine_CurrentStatus_To_v1alpha1_CurrentStatus(in, out, s) +} + +func autoConvert_v1alpha1_InPlaceUpdateMachineDeployment_To_machine_InPlaceUpdateMachineDeployment(in *InPlaceUpdateMachineDeployment, out *machine.InPlaceUpdateMachineDeployment, s conversion.Scope) error { + if err := Convert_v1alpha1_UpdateConfiguration_To_machine_UpdateConfiguration(&in.UpdateConfiguration, &out.UpdateConfiguration, s); err != nil { + return err + } + out.OrchestrationType = machine.OrchestrationType(in.OrchestrationType) + return nil +} + +// Convert_v1alpha1_InPlaceUpdateMachineDeployment_To_machine_InPlaceUpdateMachineDeployment is an autogenerated conversion function. +func Convert_v1alpha1_InPlaceUpdateMachineDeployment_To_machine_InPlaceUpdateMachineDeployment(in *InPlaceUpdateMachineDeployment, out *machine.InPlaceUpdateMachineDeployment, s conversion.Scope) error { + return autoConvert_v1alpha1_InPlaceUpdateMachineDeployment_To_machine_InPlaceUpdateMachineDeployment(in, out, s) +} + +func autoConvert_machine_InPlaceUpdateMachineDeployment_To_v1alpha1_InPlaceUpdateMachineDeployment(in *machine.InPlaceUpdateMachineDeployment, out *InPlaceUpdateMachineDeployment, s conversion.Scope) error { + if err := Convert_machine_UpdateConfiguration_To_v1alpha1_UpdateConfiguration(&in.UpdateConfiguration, &out.UpdateConfiguration, s); err != nil { + return err + } + out.OrchestrationType = OrchestrationType(in.OrchestrationType) + return nil +} + +// Convert_machine_InPlaceUpdateMachineDeployment_To_v1alpha1_InPlaceUpdateMachineDeployment is an autogenerated conversion function. +func Convert_machine_InPlaceUpdateMachineDeployment_To_v1alpha1_InPlaceUpdateMachineDeployment(in *machine.InPlaceUpdateMachineDeployment, out *InPlaceUpdateMachineDeployment, s conversion.Scope) error { + return autoConvert_machine_InPlaceUpdateMachineDeployment_To_v1alpha1_InPlaceUpdateMachineDeployment(in, out, s) +} + +func autoConvert_v1alpha1_LastOperation_To_machine_LastOperation(in *LastOperation, out *machine.LastOperation, s conversion.Scope) error { + out.Description = in.Description + out.ErrorCode = in.ErrorCode + out.LastUpdateTime = in.LastUpdateTime + out.State = machine.MachineState(in.State) + out.Type = machine.MachineOperationType(in.Type) + return nil +} + +// Convert_v1alpha1_LastOperation_To_machine_LastOperation is an autogenerated conversion function. +func Convert_v1alpha1_LastOperation_To_machine_LastOperation(in *LastOperation, out *machine.LastOperation, s conversion.Scope) error { + return autoConvert_v1alpha1_LastOperation_To_machine_LastOperation(in, out, s) +} + +func autoConvert_machine_LastOperation_To_v1alpha1_LastOperation(in *machine.LastOperation, out *LastOperation, s conversion.Scope) error { + out.Description = in.Description + out.ErrorCode = in.ErrorCode + out.LastUpdateTime = in.LastUpdateTime + out.State = MachineState(in.State) + out.Type = MachineOperationType(in.Type) + return nil +} + +// Convert_machine_LastOperation_To_v1alpha1_LastOperation is an autogenerated conversion function. +func Convert_machine_LastOperation_To_v1alpha1_LastOperation(in *machine.LastOperation, out *LastOperation, s conversion.Scope) error { + return autoConvert_machine_LastOperation_To_v1alpha1_LastOperation(in, out, s) +} + +func autoConvert_v1alpha1_Machine_To_machine_Machine(in *Machine, out *machine.Machine, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_v1alpha1_MachineSpec_To_machine_MachineSpec(&in.Spec, &out.Spec, s); err != nil { + return err + } + if err := Convert_v1alpha1_MachineStatus_To_machine_MachineStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +// Convert_v1alpha1_Machine_To_machine_Machine is an autogenerated conversion function. +func Convert_v1alpha1_Machine_To_machine_Machine(in *Machine, out *machine.Machine, s conversion.Scope) error { + return autoConvert_v1alpha1_Machine_To_machine_Machine(in, out, s) +} + +func autoConvert_machine_Machine_To_v1alpha1_Machine(in *machine.Machine, out *Machine, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_machine_MachineSpec_To_v1alpha1_MachineSpec(&in.Spec, &out.Spec, s); err != nil { + return err + } + if err := Convert_machine_MachineStatus_To_v1alpha1_MachineStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +// Convert_machine_Machine_To_v1alpha1_Machine is an autogenerated conversion function. +func Convert_machine_Machine_To_v1alpha1_Machine(in *machine.Machine, out *Machine, s conversion.Scope) error { + return autoConvert_machine_Machine_To_v1alpha1_Machine(in, out, s) +} + +func autoConvert_v1alpha1_MachineClass_To_machine_MachineClass(in *MachineClass, out *machine.MachineClass, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + out.NodeTemplate = (*machine.NodeTemplate)(unsafe.Pointer(in.NodeTemplate)) + out.CredentialsSecretRef = (*corev1.SecretReference)(unsafe.Pointer(in.CredentialsSecretRef)) + out.ProviderSpec = in.ProviderSpec + out.Provider = in.Provider + out.SecretRef = (*corev1.SecretReference)(unsafe.Pointer(in.SecretRef)) + return nil +} + +// Convert_v1alpha1_MachineClass_To_machine_MachineClass is an autogenerated conversion function. +func Convert_v1alpha1_MachineClass_To_machine_MachineClass(in *MachineClass, out *machine.MachineClass, s conversion.Scope) error { + return autoConvert_v1alpha1_MachineClass_To_machine_MachineClass(in, out, s) +} + +func autoConvert_machine_MachineClass_To_v1alpha1_MachineClass(in *machine.MachineClass, out *MachineClass, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + out.NodeTemplate = (*NodeTemplate)(unsafe.Pointer(in.NodeTemplate)) + out.CredentialsSecretRef = (*corev1.SecretReference)(unsafe.Pointer(in.CredentialsSecretRef)) + out.Provider = in.Provider + out.ProviderSpec = in.ProviderSpec + out.SecretRef = (*corev1.SecretReference)(unsafe.Pointer(in.SecretRef)) + return nil +} + +// Convert_machine_MachineClass_To_v1alpha1_MachineClass is an autogenerated conversion function. +func Convert_machine_MachineClass_To_v1alpha1_MachineClass(in *machine.MachineClass, out *MachineClass, s conversion.Scope) error { + return autoConvert_machine_MachineClass_To_v1alpha1_MachineClass(in, out, s) +} + +func autoConvert_v1alpha1_MachineClassList_To_machine_MachineClassList(in *MachineClassList, out *machine.MachineClassList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]machine.MachineClass, len(*in)) + for i := range *in { + if err := Convert_v1alpha1_MachineClass_To_machine_MachineClass(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Items = nil + } + return nil +} + +// Convert_v1alpha1_MachineClassList_To_machine_MachineClassList is an autogenerated conversion function. +func Convert_v1alpha1_MachineClassList_To_machine_MachineClassList(in *MachineClassList, out *machine.MachineClassList, s conversion.Scope) error { + return autoConvert_v1alpha1_MachineClassList_To_machine_MachineClassList(in, out, s) +} + +func autoConvert_machine_MachineClassList_To_v1alpha1_MachineClassList(in *machine.MachineClassList, out *MachineClassList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]MachineClass, len(*in)) + for i := range *in { + if err := Convert_machine_MachineClass_To_v1alpha1_MachineClass(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Items = nil + } + return nil +} + +// Convert_machine_MachineClassList_To_v1alpha1_MachineClassList is an autogenerated conversion function. +func Convert_machine_MachineClassList_To_v1alpha1_MachineClassList(in *machine.MachineClassList, out *MachineClassList, s conversion.Scope) error { + return autoConvert_machine_MachineClassList_To_v1alpha1_MachineClassList(in, out, s) +} + +func autoConvert_v1alpha1_MachineConfiguration_To_machine_MachineConfiguration(in *MachineConfiguration, out *machine.MachineConfiguration, s conversion.Scope) error { + out.MachineDrainTimeout = (*v1.Duration)(unsafe.Pointer(in.MachineDrainTimeout)) + out.MachineHealthTimeout = (*v1.Duration)(unsafe.Pointer(in.MachineHealthTimeout)) + out.MachineCreationTimeout = (*v1.Duration)(unsafe.Pointer(in.MachineCreationTimeout)) + out.MachineInPlaceUpdateTimeout = (*v1.Duration)(unsafe.Pointer(in.MachineInPlaceUpdateTimeout)) + out.MachinePreserveTimeout = (*v1.Duration)(unsafe.Pointer(in.MachinePreserveTimeout)) + out.DisableHealthTimeout = (*bool)(unsafe.Pointer(in.DisableHealthTimeout)) + out.MaxEvictRetries = (*int32)(unsafe.Pointer(in.MaxEvictRetries)) + out.NodeConditions = (*string)(unsafe.Pointer(in.NodeConditions)) + return nil +} + +// Convert_v1alpha1_MachineConfiguration_To_machine_MachineConfiguration is an autogenerated conversion function. +func Convert_v1alpha1_MachineConfiguration_To_machine_MachineConfiguration(in *MachineConfiguration, out *machine.MachineConfiguration, s conversion.Scope) error { + return autoConvert_v1alpha1_MachineConfiguration_To_machine_MachineConfiguration(in, out, s) +} + +func autoConvert_machine_MachineConfiguration_To_v1alpha1_MachineConfiguration(in *machine.MachineConfiguration, out *MachineConfiguration, s conversion.Scope) error { + out.MachineDrainTimeout = (*v1.Duration)(unsafe.Pointer(in.MachineDrainTimeout)) + out.MachineHealthTimeout = (*v1.Duration)(unsafe.Pointer(in.MachineHealthTimeout)) + out.MachineCreationTimeout = (*v1.Duration)(unsafe.Pointer(in.MachineCreationTimeout)) + out.MachineInPlaceUpdateTimeout = (*v1.Duration)(unsafe.Pointer(in.MachineInPlaceUpdateTimeout)) + out.MachinePreserveTimeout = (*v1.Duration)(unsafe.Pointer(in.MachinePreserveTimeout)) + out.DisableHealthTimeout = (*bool)(unsafe.Pointer(in.DisableHealthTimeout)) + out.MaxEvictRetries = (*int32)(unsafe.Pointer(in.MaxEvictRetries)) + out.NodeConditions = (*string)(unsafe.Pointer(in.NodeConditions)) + return nil +} + +// Convert_machine_MachineConfiguration_To_v1alpha1_MachineConfiguration is an autogenerated conversion function. +func Convert_machine_MachineConfiguration_To_v1alpha1_MachineConfiguration(in *machine.MachineConfiguration, out *MachineConfiguration, s conversion.Scope) error { + return autoConvert_machine_MachineConfiguration_To_v1alpha1_MachineConfiguration(in, out, s) +} + +func autoConvert_v1alpha1_MachineDeployment_To_machine_MachineDeployment(in *MachineDeployment, out *machine.MachineDeployment, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_v1alpha1_MachineDeploymentSpec_To_machine_MachineDeploymentSpec(&in.Spec, &out.Spec, s); err != nil { + return err + } + if err := Convert_v1alpha1_MachineDeploymentStatus_To_machine_MachineDeploymentStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +// Convert_v1alpha1_MachineDeployment_To_machine_MachineDeployment is an autogenerated conversion function. +func Convert_v1alpha1_MachineDeployment_To_machine_MachineDeployment(in *MachineDeployment, out *machine.MachineDeployment, s conversion.Scope) error { + return autoConvert_v1alpha1_MachineDeployment_To_machine_MachineDeployment(in, out, s) +} + +func autoConvert_machine_MachineDeployment_To_v1alpha1_MachineDeployment(in *machine.MachineDeployment, out *MachineDeployment, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_machine_MachineDeploymentSpec_To_v1alpha1_MachineDeploymentSpec(&in.Spec, &out.Spec, s); err != nil { + return err + } + if err := Convert_machine_MachineDeploymentStatus_To_v1alpha1_MachineDeploymentStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +// Convert_machine_MachineDeployment_To_v1alpha1_MachineDeployment is an autogenerated conversion function. +func Convert_machine_MachineDeployment_To_v1alpha1_MachineDeployment(in *machine.MachineDeployment, out *MachineDeployment, s conversion.Scope) error { + return autoConvert_machine_MachineDeployment_To_v1alpha1_MachineDeployment(in, out, s) +} + +func autoConvert_v1alpha1_MachineDeploymentCondition_To_machine_MachineDeploymentCondition(in *MachineDeploymentCondition, out *machine.MachineDeploymentCondition, s conversion.Scope) error { + out.Type = machine.MachineDeploymentConditionType(in.Type) + out.Status = machine.ConditionStatus(in.Status) + out.LastUpdateTime = in.LastUpdateTime + out.LastTransitionTime = in.LastTransitionTime + out.Reason = in.Reason + out.Message = in.Message + return nil +} + +// Convert_v1alpha1_MachineDeploymentCondition_To_machine_MachineDeploymentCondition is an autogenerated conversion function. +func Convert_v1alpha1_MachineDeploymentCondition_To_machine_MachineDeploymentCondition(in *MachineDeploymentCondition, out *machine.MachineDeploymentCondition, s conversion.Scope) error { + return autoConvert_v1alpha1_MachineDeploymentCondition_To_machine_MachineDeploymentCondition(in, out, s) +} + +func autoConvert_machine_MachineDeploymentCondition_To_v1alpha1_MachineDeploymentCondition(in *machine.MachineDeploymentCondition, out *MachineDeploymentCondition, s conversion.Scope) error { + out.Type = MachineDeploymentConditionType(in.Type) + out.Status = ConditionStatus(in.Status) + out.LastUpdateTime = in.LastUpdateTime + out.LastTransitionTime = in.LastTransitionTime + out.Reason = in.Reason + out.Message = in.Message + return nil +} + +// Convert_machine_MachineDeploymentCondition_To_v1alpha1_MachineDeploymentCondition is an autogenerated conversion function. +func Convert_machine_MachineDeploymentCondition_To_v1alpha1_MachineDeploymentCondition(in *machine.MachineDeploymentCondition, out *MachineDeploymentCondition, s conversion.Scope) error { + return autoConvert_machine_MachineDeploymentCondition_To_v1alpha1_MachineDeploymentCondition(in, out, s) +} + +func autoConvert_v1alpha1_MachineDeploymentList_To_machine_MachineDeploymentList(in *MachineDeploymentList, out *machine.MachineDeploymentList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + out.Items = *(*[]machine.MachineDeployment)(unsafe.Pointer(&in.Items)) + return nil +} + +// Convert_v1alpha1_MachineDeploymentList_To_machine_MachineDeploymentList is an autogenerated conversion function. +func Convert_v1alpha1_MachineDeploymentList_To_machine_MachineDeploymentList(in *MachineDeploymentList, out *machine.MachineDeploymentList, s conversion.Scope) error { + return autoConvert_v1alpha1_MachineDeploymentList_To_machine_MachineDeploymentList(in, out, s) +} + +func autoConvert_machine_MachineDeploymentList_To_v1alpha1_MachineDeploymentList(in *machine.MachineDeploymentList, out *MachineDeploymentList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + out.Items = *(*[]MachineDeployment)(unsafe.Pointer(&in.Items)) + return nil +} + +// Convert_machine_MachineDeploymentList_To_v1alpha1_MachineDeploymentList is an autogenerated conversion function. +func Convert_machine_MachineDeploymentList_To_v1alpha1_MachineDeploymentList(in *machine.MachineDeploymentList, out *MachineDeploymentList, s conversion.Scope) error { + return autoConvert_machine_MachineDeploymentList_To_v1alpha1_MachineDeploymentList(in, out, s) +} + +func autoConvert_v1alpha1_MachineDeploymentSpec_To_machine_MachineDeploymentSpec(in *MachineDeploymentSpec, out *machine.MachineDeploymentSpec, s conversion.Scope) error { + out.Replicas = in.Replicas + out.Selector = (*v1.LabelSelector)(unsafe.Pointer(in.Selector)) + if err := Convert_v1alpha1_MachineTemplateSpec_To_machine_MachineTemplateSpec(&in.Template, &out.Template, s); err != nil { + return err + } + if err := Convert_v1alpha1_MachineDeploymentStrategy_To_machine_MachineDeploymentStrategy(&in.Strategy, &out.Strategy, s); err != nil { + return err + } + out.MinReadySeconds = in.MinReadySeconds + out.RevisionHistoryLimit = (*int32)(unsafe.Pointer(in.RevisionHistoryLimit)) + out.Paused = in.Paused + out.RollbackTo = (*machine.RollbackConfig)(unsafe.Pointer(in.RollbackTo)) + out.ProgressDeadlineSeconds = (*int32)(unsafe.Pointer(in.ProgressDeadlineSeconds)) + out.AutoPreserveFailedMachineMax = (*int32)(unsafe.Pointer(in.AutoPreserveFailedMachineMax)) + return nil +} + +// Convert_v1alpha1_MachineDeploymentSpec_To_machine_MachineDeploymentSpec is an autogenerated conversion function. +func Convert_v1alpha1_MachineDeploymentSpec_To_machine_MachineDeploymentSpec(in *MachineDeploymentSpec, out *machine.MachineDeploymentSpec, s conversion.Scope) error { + return autoConvert_v1alpha1_MachineDeploymentSpec_To_machine_MachineDeploymentSpec(in, out, s) +} + +func autoConvert_machine_MachineDeploymentSpec_To_v1alpha1_MachineDeploymentSpec(in *machine.MachineDeploymentSpec, out *MachineDeploymentSpec, s conversion.Scope) error { + out.Replicas = in.Replicas + out.Selector = (*v1.LabelSelector)(unsafe.Pointer(in.Selector)) + if err := Convert_machine_MachineTemplateSpec_To_v1alpha1_MachineTemplateSpec(&in.Template, &out.Template, s); err != nil { + return err + } + if err := Convert_machine_MachineDeploymentStrategy_To_v1alpha1_MachineDeploymentStrategy(&in.Strategy, &out.Strategy, s); err != nil { + return err + } + out.MinReadySeconds = in.MinReadySeconds + out.RevisionHistoryLimit = (*int32)(unsafe.Pointer(in.RevisionHistoryLimit)) + out.Paused = in.Paused + out.RollbackTo = (*RollbackConfig)(unsafe.Pointer(in.RollbackTo)) + out.ProgressDeadlineSeconds = (*int32)(unsafe.Pointer(in.ProgressDeadlineSeconds)) + out.AutoPreserveFailedMachineMax = (*int32)(unsafe.Pointer(in.AutoPreserveFailedMachineMax)) + return nil +} + +// Convert_machine_MachineDeploymentSpec_To_v1alpha1_MachineDeploymentSpec is an autogenerated conversion function. +func Convert_machine_MachineDeploymentSpec_To_v1alpha1_MachineDeploymentSpec(in *machine.MachineDeploymentSpec, out *MachineDeploymentSpec, s conversion.Scope) error { + return autoConvert_machine_MachineDeploymentSpec_To_v1alpha1_MachineDeploymentSpec(in, out, s) +} + +func autoConvert_v1alpha1_MachineDeploymentStatus_To_machine_MachineDeploymentStatus(in *MachineDeploymentStatus, out *machine.MachineDeploymentStatus, s conversion.Scope) error { + out.ObservedGeneration = in.ObservedGeneration + out.Replicas = in.Replicas + out.UpdatedReplicas = in.UpdatedReplicas + out.ReadyReplicas = in.ReadyReplicas + out.AvailableReplicas = in.AvailableReplicas + out.UnavailableReplicas = in.UnavailableReplicas + out.Conditions = *(*[]machine.MachineDeploymentCondition)(unsafe.Pointer(&in.Conditions)) + out.CollisionCount = (*int32)(unsafe.Pointer(in.CollisionCount)) + out.FailedMachines = *(*[]*machine.MachineSummary)(unsafe.Pointer(&in.FailedMachines)) + return nil +} + +// Convert_v1alpha1_MachineDeploymentStatus_To_machine_MachineDeploymentStatus is an autogenerated conversion function. +func Convert_v1alpha1_MachineDeploymentStatus_To_machine_MachineDeploymentStatus(in *MachineDeploymentStatus, out *machine.MachineDeploymentStatus, s conversion.Scope) error { + return autoConvert_v1alpha1_MachineDeploymentStatus_To_machine_MachineDeploymentStatus(in, out, s) +} + +func autoConvert_machine_MachineDeploymentStatus_To_v1alpha1_MachineDeploymentStatus(in *machine.MachineDeploymentStatus, out *MachineDeploymentStatus, s conversion.Scope) error { + out.ObservedGeneration = in.ObservedGeneration + out.Replicas = in.Replicas + out.UpdatedReplicas = in.UpdatedReplicas + out.ReadyReplicas = in.ReadyReplicas + out.AvailableReplicas = in.AvailableReplicas + out.UnavailableReplicas = in.UnavailableReplicas + out.Conditions = *(*[]MachineDeploymentCondition)(unsafe.Pointer(&in.Conditions)) + out.CollisionCount = (*int32)(unsafe.Pointer(in.CollisionCount)) + out.FailedMachines = *(*[]*MachineSummary)(unsafe.Pointer(&in.FailedMachines)) + return nil +} + +// Convert_machine_MachineDeploymentStatus_To_v1alpha1_MachineDeploymentStatus is an autogenerated conversion function. +func Convert_machine_MachineDeploymentStatus_To_v1alpha1_MachineDeploymentStatus(in *machine.MachineDeploymentStatus, out *MachineDeploymentStatus, s conversion.Scope) error { + return autoConvert_machine_MachineDeploymentStatus_To_v1alpha1_MachineDeploymentStatus(in, out, s) +} + +func autoConvert_v1alpha1_MachineDeploymentStrategy_To_machine_MachineDeploymentStrategy(in *MachineDeploymentStrategy, out *machine.MachineDeploymentStrategy, s conversion.Scope) error { + out.Type = machine.MachineDeploymentStrategyType(in.Type) + out.RollingUpdate = (*machine.RollingUpdateMachineDeployment)(unsafe.Pointer(in.RollingUpdate)) + out.InPlaceUpdate = (*machine.InPlaceUpdateMachineDeployment)(unsafe.Pointer(in.InPlaceUpdate)) + return nil +} + +// Convert_v1alpha1_MachineDeploymentStrategy_To_machine_MachineDeploymentStrategy is an autogenerated conversion function. +func Convert_v1alpha1_MachineDeploymentStrategy_To_machine_MachineDeploymentStrategy(in *MachineDeploymentStrategy, out *machine.MachineDeploymentStrategy, s conversion.Scope) error { + return autoConvert_v1alpha1_MachineDeploymentStrategy_To_machine_MachineDeploymentStrategy(in, out, s) +} + +func autoConvert_machine_MachineDeploymentStrategy_To_v1alpha1_MachineDeploymentStrategy(in *machine.MachineDeploymentStrategy, out *MachineDeploymentStrategy, s conversion.Scope) error { + out.Type = MachineDeploymentStrategyType(in.Type) + out.RollingUpdate = (*RollingUpdateMachineDeployment)(unsafe.Pointer(in.RollingUpdate)) + out.InPlaceUpdate = (*InPlaceUpdateMachineDeployment)(unsafe.Pointer(in.InPlaceUpdate)) + return nil +} + +// Convert_machine_MachineDeploymentStrategy_To_v1alpha1_MachineDeploymentStrategy is an autogenerated conversion function. +func Convert_machine_MachineDeploymentStrategy_To_v1alpha1_MachineDeploymentStrategy(in *machine.MachineDeploymentStrategy, out *MachineDeploymentStrategy, s conversion.Scope) error { + return autoConvert_machine_MachineDeploymentStrategy_To_v1alpha1_MachineDeploymentStrategy(in, out, s) +} + +func autoConvert_v1alpha1_MachineList_To_machine_MachineList(in *MachineList, out *machine.MachineList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + out.Items = *(*[]machine.Machine)(unsafe.Pointer(&in.Items)) + return nil +} + +// Convert_v1alpha1_MachineList_To_machine_MachineList is an autogenerated conversion function. +func Convert_v1alpha1_MachineList_To_machine_MachineList(in *MachineList, out *machine.MachineList, s conversion.Scope) error { + return autoConvert_v1alpha1_MachineList_To_machine_MachineList(in, out, s) +} + +func autoConvert_machine_MachineList_To_v1alpha1_MachineList(in *machine.MachineList, out *MachineList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + out.Items = *(*[]Machine)(unsafe.Pointer(&in.Items)) + return nil +} + +// Convert_machine_MachineList_To_v1alpha1_MachineList is an autogenerated conversion function. +func Convert_machine_MachineList_To_v1alpha1_MachineList(in *machine.MachineList, out *MachineList, s conversion.Scope) error { + return autoConvert_machine_MachineList_To_v1alpha1_MachineList(in, out, s) +} + +func autoConvert_v1alpha1_MachineSet_To_machine_MachineSet(in *MachineSet, out *machine.MachineSet, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_v1alpha1_MachineSetSpec_To_machine_MachineSetSpec(&in.Spec, &out.Spec, s); err != nil { + return err + } + if err := Convert_v1alpha1_MachineSetStatus_To_machine_MachineSetStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +// Convert_v1alpha1_MachineSet_To_machine_MachineSet is an autogenerated conversion function. +func Convert_v1alpha1_MachineSet_To_machine_MachineSet(in *MachineSet, out *machine.MachineSet, s conversion.Scope) error { + return autoConvert_v1alpha1_MachineSet_To_machine_MachineSet(in, out, s) +} + +func autoConvert_machine_MachineSet_To_v1alpha1_MachineSet(in *machine.MachineSet, out *MachineSet, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_machine_MachineSetSpec_To_v1alpha1_MachineSetSpec(&in.Spec, &out.Spec, s); err != nil { + return err + } + if err := Convert_machine_MachineSetStatus_To_v1alpha1_MachineSetStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +// Convert_machine_MachineSet_To_v1alpha1_MachineSet is an autogenerated conversion function. +func Convert_machine_MachineSet_To_v1alpha1_MachineSet(in *machine.MachineSet, out *MachineSet, s conversion.Scope) error { + return autoConvert_machine_MachineSet_To_v1alpha1_MachineSet(in, out, s) +} + +func autoConvert_v1alpha1_MachineSetCondition_To_machine_MachineSetCondition(in *MachineSetCondition, out *machine.MachineSetCondition, s conversion.Scope) error { + out.Type = machine.MachineSetConditionType(in.Type) + out.Status = machine.ConditionStatus(in.Status) + out.LastTransitionTime = in.LastTransitionTime + out.Reason = in.Reason + out.Message = in.Message + return nil +} + +// Convert_v1alpha1_MachineSetCondition_To_machine_MachineSetCondition is an autogenerated conversion function. +func Convert_v1alpha1_MachineSetCondition_To_machine_MachineSetCondition(in *MachineSetCondition, out *machine.MachineSetCondition, s conversion.Scope) error { + return autoConvert_v1alpha1_MachineSetCondition_To_machine_MachineSetCondition(in, out, s) +} + +func autoConvert_machine_MachineSetCondition_To_v1alpha1_MachineSetCondition(in *machine.MachineSetCondition, out *MachineSetCondition, s conversion.Scope) error { + out.Type = MachineSetConditionType(in.Type) + out.Status = ConditionStatus(in.Status) + out.LastTransitionTime = in.LastTransitionTime + out.Reason = in.Reason + out.Message = in.Message + return nil +} + +// Convert_machine_MachineSetCondition_To_v1alpha1_MachineSetCondition is an autogenerated conversion function. +func Convert_machine_MachineSetCondition_To_v1alpha1_MachineSetCondition(in *machine.MachineSetCondition, out *MachineSetCondition, s conversion.Scope) error { + return autoConvert_machine_MachineSetCondition_To_v1alpha1_MachineSetCondition(in, out, s) +} + +func autoConvert_v1alpha1_MachineSetList_To_machine_MachineSetList(in *MachineSetList, out *machine.MachineSetList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + out.Items = *(*[]machine.MachineSet)(unsafe.Pointer(&in.Items)) + return nil +} + +// Convert_v1alpha1_MachineSetList_To_machine_MachineSetList is an autogenerated conversion function. +func Convert_v1alpha1_MachineSetList_To_machine_MachineSetList(in *MachineSetList, out *machine.MachineSetList, s conversion.Scope) error { + return autoConvert_v1alpha1_MachineSetList_To_machine_MachineSetList(in, out, s) +} + +func autoConvert_machine_MachineSetList_To_v1alpha1_MachineSetList(in *machine.MachineSetList, out *MachineSetList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + out.Items = *(*[]MachineSet)(unsafe.Pointer(&in.Items)) + return nil +} + +// Convert_machine_MachineSetList_To_v1alpha1_MachineSetList is an autogenerated conversion function. +func Convert_machine_MachineSetList_To_v1alpha1_MachineSetList(in *machine.MachineSetList, out *MachineSetList, s conversion.Scope) error { + return autoConvert_machine_MachineSetList_To_v1alpha1_MachineSetList(in, out, s) +} + +func autoConvert_v1alpha1_MachineSetSpec_To_machine_MachineSetSpec(in *MachineSetSpec, out *machine.MachineSetSpec, s conversion.Scope) error { + out.Replicas = in.Replicas + out.Selector = (*v1.LabelSelector)(unsafe.Pointer(in.Selector)) + if err := Convert_v1alpha1_ClassSpec_To_machine_ClassSpec(&in.MachineClass, &out.MachineClass, s); err != nil { + return err + } + if err := Convert_v1alpha1_MachineTemplateSpec_To_machine_MachineTemplateSpec(&in.Template, &out.Template, s); err != nil { + return err + } + out.MinReadySeconds = in.MinReadySeconds + out.AutoPreserveFailedMachineMax = (*int32)(unsafe.Pointer(in.AutoPreserveFailedMachineMax)) + return nil +} + +// Convert_v1alpha1_MachineSetSpec_To_machine_MachineSetSpec is an autogenerated conversion function. +func Convert_v1alpha1_MachineSetSpec_To_machine_MachineSetSpec(in *MachineSetSpec, out *machine.MachineSetSpec, s conversion.Scope) error { + return autoConvert_v1alpha1_MachineSetSpec_To_machine_MachineSetSpec(in, out, s) +} + +func autoConvert_machine_MachineSetSpec_To_v1alpha1_MachineSetSpec(in *machine.MachineSetSpec, out *MachineSetSpec, s conversion.Scope) error { + out.Replicas = in.Replicas + out.Selector = (*v1.LabelSelector)(unsafe.Pointer(in.Selector)) + if err := Convert_machine_ClassSpec_To_v1alpha1_ClassSpec(&in.MachineClass, &out.MachineClass, s); err != nil { + return err + } + if err := Convert_machine_MachineTemplateSpec_To_v1alpha1_MachineTemplateSpec(&in.Template, &out.Template, s); err != nil { + return err + } + out.MinReadySeconds = in.MinReadySeconds + out.AutoPreserveFailedMachineMax = (*int32)(unsafe.Pointer(in.AutoPreserveFailedMachineMax)) + return nil +} + +// Convert_machine_MachineSetSpec_To_v1alpha1_MachineSetSpec is an autogenerated conversion function. +func Convert_machine_MachineSetSpec_To_v1alpha1_MachineSetSpec(in *machine.MachineSetSpec, out *MachineSetSpec, s conversion.Scope) error { + return autoConvert_machine_MachineSetSpec_To_v1alpha1_MachineSetSpec(in, out, s) +} + +func autoConvert_v1alpha1_MachineSetStatus_To_machine_MachineSetStatus(in *MachineSetStatus, out *machine.MachineSetStatus, s conversion.Scope) error { + out.Replicas = in.Replicas + out.FullyLabeledReplicas = in.FullyLabeledReplicas + out.ReadyReplicas = in.ReadyReplicas + out.AvailableReplicas = in.AvailableReplicas + out.ObservedGeneration = in.ObservedGeneration + out.Conditions = *(*[]machine.MachineSetCondition)(unsafe.Pointer(&in.Conditions)) + if err := Convert_v1alpha1_LastOperation_To_machine_LastOperation(&in.LastOperation, &out.LastOperation, s); err != nil { + return err + } + out.FailedMachines = (*[]machine.MachineSummary)(unsafe.Pointer(in.FailedMachines)) + out.AutoPreserveFailedMachineCount = (*int32)(unsafe.Pointer(in.AutoPreserveFailedMachineCount)) + return nil +} + +// Convert_v1alpha1_MachineSetStatus_To_machine_MachineSetStatus is an autogenerated conversion function. +func Convert_v1alpha1_MachineSetStatus_To_machine_MachineSetStatus(in *MachineSetStatus, out *machine.MachineSetStatus, s conversion.Scope) error { + return autoConvert_v1alpha1_MachineSetStatus_To_machine_MachineSetStatus(in, out, s) +} + +func autoConvert_machine_MachineSetStatus_To_v1alpha1_MachineSetStatus(in *machine.MachineSetStatus, out *MachineSetStatus, s conversion.Scope) error { + out.Replicas = in.Replicas + out.FullyLabeledReplicas = in.FullyLabeledReplicas + out.ReadyReplicas = in.ReadyReplicas + out.AvailableReplicas = in.AvailableReplicas + out.ObservedGeneration = in.ObservedGeneration + out.Conditions = *(*[]MachineSetCondition)(unsafe.Pointer(&in.Conditions)) + if err := Convert_machine_LastOperation_To_v1alpha1_LastOperation(&in.LastOperation, &out.LastOperation, s); err != nil { + return err + } + out.FailedMachines = (*[]MachineSummary)(unsafe.Pointer(in.FailedMachines)) + out.AutoPreserveFailedMachineCount = (*int32)(unsafe.Pointer(in.AutoPreserveFailedMachineCount)) + return nil +} + +// Convert_machine_MachineSetStatus_To_v1alpha1_MachineSetStatus is an autogenerated conversion function. +func Convert_machine_MachineSetStatus_To_v1alpha1_MachineSetStatus(in *machine.MachineSetStatus, out *MachineSetStatus, s conversion.Scope) error { + return autoConvert_machine_MachineSetStatus_To_v1alpha1_MachineSetStatus(in, out, s) +} + +func autoConvert_v1alpha1_MachineSpec_To_machine_MachineSpec(in *MachineSpec, out *machine.MachineSpec, s conversion.Scope) error { + if err := Convert_v1alpha1_ClassSpec_To_machine_ClassSpec(&in.Class, &out.Class, s); err != nil { + return err + } + out.ProviderID = in.ProviderID + if err := Convert_v1alpha1_NodeTemplateSpec_To_machine_NodeTemplateSpec(&in.NodeTemplateSpec, &out.NodeTemplateSpec, s); err != nil { + return err + } + out.MachineConfiguration = (*machine.MachineConfiguration)(unsafe.Pointer(in.MachineConfiguration)) + return nil +} + +// Convert_v1alpha1_MachineSpec_To_machine_MachineSpec is an autogenerated conversion function. +func Convert_v1alpha1_MachineSpec_To_machine_MachineSpec(in *MachineSpec, out *machine.MachineSpec, s conversion.Scope) error { + return autoConvert_v1alpha1_MachineSpec_To_machine_MachineSpec(in, out, s) +} + +func autoConvert_machine_MachineSpec_To_v1alpha1_MachineSpec(in *machine.MachineSpec, out *MachineSpec, s conversion.Scope) error { + if err := Convert_machine_ClassSpec_To_v1alpha1_ClassSpec(&in.Class, &out.Class, s); err != nil { + return err + } + out.ProviderID = in.ProviderID + if err := Convert_machine_NodeTemplateSpec_To_v1alpha1_NodeTemplateSpec(&in.NodeTemplateSpec, &out.NodeTemplateSpec, s); err != nil { + return err + } + out.MachineConfiguration = (*MachineConfiguration)(unsafe.Pointer(in.MachineConfiguration)) + return nil +} + +// Convert_machine_MachineSpec_To_v1alpha1_MachineSpec is an autogenerated conversion function. +func Convert_machine_MachineSpec_To_v1alpha1_MachineSpec(in *machine.MachineSpec, out *MachineSpec, s conversion.Scope) error { + return autoConvert_machine_MachineSpec_To_v1alpha1_MachineSpec(in, out, s) +} + +func autoConvert_v1alpha1_MachineStatus_To_machine_MachineStatus(in *MachineStatus, out *machine.MachineStatus, s conversion.Scope) error { + out.Addresses = *(*[]corev1.NodeAddress)(unsafe.Pointer(&in.Addresses)) + out.Conditions = *(*[]corev1.NodeCondition)(unsafe.Pointer(&in.Conditions)) + if err := Convert_v1alpha1_LastOperation_To_machine_LastOperation(&in.LastOperation, &out.LastOperation, s); err != nil { + return err + } + if err := Convert_v1alpha1_CurrentStatus_To_machine_CurrentStatus(&in.CurrentStatus, &out.CurrentStatus, s); err != nil { + return err + } + out.LastKnownState = in.LastKnownState + return nil +} + +// Convert_v1alpha1_MachineStatus_To_machine_MachineStatus is an autogenerated conversion function. +func Convert_v1alpha1_MachineStatus_To_machine_MachineStatus(in *MachineStatus, out *machine.MachineStatus, s conversion.Scope) error { + return autoConvert_v1alpha1_MachineStatus_To_machine_MachineStatus(in, out, s) +} + +func autoConvert_machine_MachineStatus_To_v1alpha1_MachineStatus(in *machine.MachineStatus, out *MachineStatus, s conversion.Scope) error { + out.Addresses = *(*[]corev1.NodeAddress)(unsafe.Pointer(&in.Addresses)) + out.Conditions = *(*[]corev1.NodeCondition)(unsafe.Pointer(&in.Conditions)) + if err := Convert_machine_LastOperation_To_v1alpha1_LastOperation(&in.LastOperation, &out.LastOperation, s); err != nil { + return err + } + if err := Convert_machine_CurrentStatus_To_v1alpha1_CurrentStatus(&in.CurrentStatus, &out.CurrentStatus, s); err != nil { + return err + } + out.LastKnownState = in.LastKnownState + return nil +} + +// Convert_machine_MachineStatus_To_v1alpha1_MachineStatus is an autogenerated conversion function. +func Convert_machine_MachineStatus_To_v1alpha1_MachineStatus(in *machine.MachineStatus, out *MachineStatus, s conversion.Scope) error { + return autoConvert_machine_MachineStatus_To_v1alpha1_MachineStatus(in, out, s) +} + +func autoConvert_v1alpha1_MachineSummary_To_machine_MachineSummary(in *MachineSummary, out *machine.MachineSummary, s conversion.Scope) error { + out.Name = in.Name + out.ProviderID = in.ProviderID + if err := Convert_v1alpha1_LastOperation_To_machine_LastOperation(&in.LastOperation, &out.LastOperation, s); err != nil { + return err + } + out.OwnerRef = in.OwnerRef + return nil +} + +// Convert_v1alpha1_MachineSummary_To_machine_MachineSummary is an autogenerated conversion function. +func Convert_v1alpha1_MachineSummary_To_machine_MachineSummary(in *MachineSummary, out *machine.MachineSummary, s conversion.Scope) error { + return autoConvert_v1alpha1_MachineSummary_To_machine_MachineSummary(in, out, s) +} + +func autoConvert_machine_MachineSummary_To_v1alpha1_MachineSummary(in *machine.MachineSummary, out *MachineSummary, s conversion.Scope) error { + out.Name = in.Name + out.ProviderID = in.ProviderID + if err := Convert_machine_LastOperation_To_v1alpha1_LastOperation(&in.LastOperation, &out.LastOperation, s); err != nil { + return err + } + out.OwnerRef = in.OwnerRef + return nil +} + +// Convert_machine_MachineSummary_To_v1alpha1_MachineSummary is an autogenerated conversion function. +func Convert_machine_MachineSummary_To_v1alpha1_MachineSummary(in *machine.MachineSummary, out *MachineSummary, s conversion.Scope) error { + return autoConvert_machine_MachineSummary_To_v1alpha1_MachineSummary(in, out, s) +} + +func autoConvert_v1alpha1_MachineTemplateSpec_To_machine_MachineTemplateSpec(in *MachineTemplateSpec, out *machine.MachineTemplateSpec, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_v1alpha1_MachineSpec_To_machine_MachineSpec(&in.Spec, &out.Spec, s); err != nil { + return err + } + return nil +} + +// Convert_v1alpha1_MachineTemplateSpec_To_machine_MachineTemplateSpec is an autogenerated conversion function. +func Convert_v1alpha1_MachineTemplateSpec_To_machine_MachineTemplateSpec(in *MachineTemplateSpec, out *machine.MachineTemplateSpec, s conversion.Scope) error { + return autoConvert_v1alpha1_MachineTemplateSpec_To_machine_MachineTemplateSpec(in, out, s) +} + +func autoConvert_machine_MachineTemplateSpec_To_v1alpha1_MachineTemplateSpec(in *machine.MachineTemplateSpec, out *MachineTemplateSpec, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_machine_MachineSpec_To_v1alpha1_MachineSpec(&in.Spec, &out.Spec, s); err != nil { + return err + } + return nil +} + +// Convert_machine_MachineTemplateSpec_To_v1alpha1_MachineTemplateSpec is an autogenerated conversion function. +func Convert_machine_MachineTemplateSpec_To_v1alpha1_MachineTemplateSpec(in *machine.MachineTemplateSpec, out *MachineTemplateSpec, s conversion.Scope) error { + return autoConvert_machine_MachineTemplateSpec_To_v1alpha1_MachineTemplateSpec(in, out, s) +} + +func autoConvert_v1alpha1_NodeTemplate_To_machine_NodeTemplate(in *NodeTemplate, out *machine.NodeTemplate, s conversion.Scope) error { + out.Capacity = *(*corev1.ResourceList)(unsafe.Pointer(&in.Capacity)) + out.VirtualCapacity = *(*corev1.ResourceList)(unsafe.Pointer(&in.VirtualCapacity)) + out.InstanceType = in.InstanceType + out.Region = in.Region + out.Zone = in.Zone + out.Architecture = (*string)(unsafe.Pointer(in.Architecture)) + return nil +} + +// Convert_v1alpha1_NodeTemplate_To_machine_NodeTemplate is an autogenerated conversion function. +func Convert_v1alpha1_NodeTemplate_To_machine_NodeTemplate(in *NodeTemplate, out *machine.NodeTemplate, s conversion.Scope) error { + return autoConvert_v1alpha1_NodeTemplate_To_machine_NodeTemplate(in, out, s) +} + +func autoConvert_machine_NodeTemplate_To_v1alpha1_NodeTemplate(in *machine.NodeTemplate, out *NodeTemplate, s conversion.Scope) error { + out.Capacity = *(*corev1.ResourceList)(unsafe.Pointer(&in.Capacity)) + out.VirtualCapacity = *(*corev1.ResourceList)(unsafe.Pointer(&in.VirtualCapacity)) + out.InstanceType = in.InstanceType + out.Region = in.Region + out.Zone = in.Zone + out.Architecture = (*string)(unsafe.Pointer(in.Architecture)) + return nil +} + +// Convert_machine_NodeTemplate_To_v1alpha1_NodeTemplate is an autogenerated conversion function. +func Convert_machine_NodeTemplate_To_v1alpha1_NodeTemplate(in *machine.NodeTemplate, out *NodeTemplate, s conversion.Scope) error { + return autoConvert_machine_NodeTemplate_To_v1alpha1_NodeTemplate(in, out, s) +} + +func autoConvert_v1alpha1_NodeTemplateSpec_To_machine_NodeTemplateSpec(in *NodeTemplateSpec, out *machine.NodeTemplateSpec, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + out.Spec = in.Spec + return nil +} + +// Convert_v1alpha1_NodeTemplateSpec_To_machine_NodeTemplateSpec is an autogenerated conversion function. +func Convert_v1alpha1_NodeTemplateSpec_To_machine_NodeTemplateSpec(in *NodeTemplateSpec, out *machine.NodeTemplateSpec, s conversion.Scope) error { + return autoConvert_v1alpha1_NodeTemplateSpec_To_machine_NodeTemplateSpec(in, out, s) +} + +func autoConvert_machine_NodeTemplateSpec_To_v1alpha1_NodeTemplateSpec(in *machine.NodeTemplateSpec, out *NodeTemplateSpec, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + out.Spec = in.Spec + return nil +} + +// Convert_machine_NodeTemplateSpec_To_v1alpha1_NodeTemplateSpec is an autogenerated conversion function. +func Convert_machine_NodeTemplateSpec_To_v1alpha1_NodeTemplateSpec(in *machine.NodeTemplateSpec, out *NodeTemplateSpec, s conversion.Scope) error { + return autoConvert_machine_NodeTemplateSpec_To_v1alpha1_NodeTemplateSpec(in, out, s) +} + +func autoConvert_v1alpha1_RollbackConfig_To_machine_RollbackConfig(in *RollbackConfig, out *machine.RollbackConfig, s conversion.Scope) error { + out.Revision = in.Revision + return nil +} + +// Convert_v1alpha1_RollbackConfig_To_machine_RollbackConfig is an autogenerated conversion function. +func Convert_v1alpha1_RollbackConfig_To_machine_RollbackConfig(in *RollbackConfig, out *machine.RollbackConfig, s conversion.Scope) error { + return autoConvert_v1alpha1_RollbackConfig_To_machine_RollbackConfig(in, out, s) +} + +func autoConvert_machine_RollbackConfig_To_v1alpha1_RollbackConfig(in *machine.RollbackConfig, out *RollbackConfig, s conversion.Scope) error { + out.Revision = in.Revision + return nil +} + +// Convert_machine_RollbackConfig_To_v1alpha1_RollbackConfig is an autogenerated conversion function. +func Convert_machine_RollbackConfig_To_v1alpha1_RollbackConfig(in *machine.RollbackConfig, out *RollbackConfig, s conversion.Scope) error { + return autoConvert_machine_RollbackConfig_To_v1alpha1_RollbackConfig(in, out, s) +} + +func autoConvert_v1alpha1_RollingUpdateMachineDeployment_To_machine_RollingUpdateMachineDeployment(in *RollingUpdateMachineDeployment, out *machine.RollingUpdateMachineDeployment, s conversion.Scope) error { + if err := Convert_v1alpha1_UpdateConfiguration_To_machine_UpdateConfiguration(&in.UpdateConfiguration, &out.UpdateConfiguration, s); err != nil { + return err + } + return nil +} + +// Convert_v1alpha1_RollingUpdateMachineDeployment_To_machine_RollingUpdateMachineDeployment is an autogenerated conversion function. +func Convert_v1alpha1_RollingUpdateMachineDeployment_To_machine_RollingUpdateMachineDeployment(in *RollingUpdateMachineDeployment, out *machine.RollingUpdateMachineDeployment, s conversion.Scope) error { + return autoConvert_v1alpha1_RollingUpdateMachineDeployment_To_machine_RollingUpdateMachineDeployment(in, out, s) +} + +func autoConvert_machine_RollingUpdateMachineDeployment_To_v1alpha1_RollingUpdateMachineDeployment(in *machine.RollingUpdateMachineDeployment, out *RollingUpdateMachineDeployment, s conversion.Scope) error { + if err := Convert_machine_UpdateConfiguration_To_v1alpha1_UpdateConfiguration(&in.UpdateConfiguration, &out.UpdateConfiguration, s); err != nil { + return err + } + return nil +} + +// Convert_machine_RollingUpdateMachineDeployment_To_v1alpha1_RollingUpdateMachineDeployment is an autogenerated conversion function. +func Convert_machine_RollingUpdateMachineDeployment_To_v1alpha1_RollingUpdateMachineDeployment(in *machine.RollingUpdateMachineDeployment, out *RollingUpdateMachineDeployment, s conversion.Scope) error { + return autoConvert_machine_RollingUpdateMachineDeployment_To_v1alpha1_RollingUpdateMachineDeployment(in, out, s) +} + +func autoConvert_v1alpha1_UpdateConfiguration_To_machine_UpdateConfiguration(in *UpdateConfiguration, out *machine.UpdateConfiguration, s conversion.Scope) error { + out.MaxUnavailable = (*intstr.IntOrString)(unsafe.Pointer(in.MaxUnavailable)) + out.MaxSurge = (*intstr.IntOrString)(unsafe.Pointer(in.MaxSurge)) + return nil +} + +// Convert_v1alpha1_UpdateConfiguration_To_machine_UpdateConfiguration is an autogenerated conversion function. +func Convert_v1alpha1_UpdateConfiguration_To_machine_UpdateConfiguration(in *UpdateConfiguration, out *machine.UpdateConfiguration, s conversion.Scope) error { + return autoConvert_v1alpha1_UpdateConfiguration_To_machine_UpdateConfiguration(in, out, s) +} + +func autoConvert_machine_UpdateConfiguration_To_v1alpha1_UpdateConfiguration(in *machine.UpdateConfiguration, out *UpdateConfiguration, s conversion.Scope) error { + out.MaxUnavailable = (*intstr.IntOrString)(unsafe.Pointer(in.MaxUnavailable)) + out.MaxSurge = (*intstr.IntOrString)(unsafe.Pointer(in.MaxSurge)) + return nil +} + +// Convert_machine_UpdateConfiguration_To_v1alpha1_UpdateConfiguration is an autogenerated conversion function. +func Convert_machine_UpdateConfiguration_To_v1alpha1_UpdateConfiguration(in *machine.UpdateConfiguration, out *UpdateConfiguration, s conversion.Scope) error { + return autoConvert_machine_UpdateConfiguration_To_v1alpha1_UpdateConfiguration(in, out, s) +} diff --git a/pkg/apis/machine/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/machine/v1alpha1/zz_generated.deepcopy.go new file mode 100644 index 000000000..f169b3811 --- /dev/null +++ b/pkg/apis/machine/v1alpha1/zz_generated.deepcopy.go @@ -0,0 +1,813 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +// SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors +// +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + intstr "k8s.io/apimachinery/pkg/util/intstr" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClassSpec) DeepCopyInto(out *ClassSpec) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClassSpec. +func (in *ClassSpec) DeepCopy() *ClassSpec { + if in == nil { + return nil + } + out := new(ClassSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CurrentStatus) DeepCopyInto(out *CurrentStatus) { + *out = *in + in.LastUpdateTime.DeepCopyInto(&out.LastUpdateTime) + if in.PreserveExpiryTime != nil { + in, out := &in.PreserveExpiryTime, &out.PreserveExpiryTime + *out = (*in).DeepCopy() + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CurrentStatus. +func (in *CurrentStatus) DeepCopy() *CurrentStatus { + if in == nil { + return nil + } + out := new(CurrentStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *InPlaceUpdateMachineDeployment) DeepCopyInto(out *InPlaceUpdateMachineDeployment) { + *out = *in + in.UpdateConfiguration.DeepCopyInto(&out.UpdateConfiguration) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InPlaceUpdateMachineDeployment. +func (in *InPlaceUpdateMachineDeployment) DeepCopy() *InPlaceUpdateMachineDeployment { + if in == nil { + return nil + } + out := new(InPlaceUpdateMachineDeployment) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LastOperation) DeepCopyInto(out *LastOperation) { + *out = *in + in.LastUpdateTime.DeepCopyInto(&out.LastUpdateTime) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LastOperation. +func (in *LastOperation) DeepCopy() *LastOperation { + if in == nil { + return nil + } + out := new(LastOperation) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Machine) DeepCopyInto(out *Machine) { + *out = *in + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.TypeMeta = in.TypeMeta + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Machine. +func (in *Machine) DeepCopy() *Machine { + if in == nil { + return nil + } + out := new(Machine) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Machine) 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 *MachineClass) DeepCopyInto(out *MachineClass) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + if in.NodeTemplate != nil { + in, out := &in.NodeTemplate, &out.NodeTemplate + *out = new(NodeTemplate) + (*in).DeepCopyInto(*out) + } + if in.CredentialsSecretRef != nil { + in, out := &in.CredentialsSecretRef, &out.CredentialsSecretRef + *out = new(v1.SecretReference) + **out = **in + } + in.ProviderSpec.DeepCopyInto(&out.ProviderSpec) + if in.SecretRef != nil { + in, out := &in.SecretRef, &out.SecretRef + *out = new(v1.SecretReference) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineClass. +func (in *MachineClass) DeepCopy() *MachineClass { + if in == nil { + return nil + } + out := new(MachineClass) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *MachineClass) 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 *MachineClassList) DeepCopyInto(out *MachineClassList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]MachineClass, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineClassList. +func (in *MachineClassList) DeepCopy() *MachineClassList { + if in == nil { + return nil + } + out := new(MachineClassList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *MachineClassList) 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 *MachineConfiguration) DeepCopyInto(out *MachineConfiguration) { + *out = *in + if in.MachineDrainTimeout != nil { + in, out := &in.MachineDrainTimeout, &out.MachineDrainTimeout + *out = new(metav1.Duration) + **out = **in + } + if in.MachineHealthTimeout != nil { + in, out := &in.MachineHealthTimeout, &out.MachineHealthTimeout + *out = new(metav1.Duration) + **out = **in + } + if in.MachineCreationTimeout != nil { + in, out := &in.MachineCreationTimeout, &out.MachineCreationTimeout + *out = new(metav1.Duration) + **out = **in + } + if in.MachineInPlaceUpdateTimeout != nil { + in, out := &in.MachineInPlaceUpdateTimeout, &out.MachineInPlaceUpdateTimeout + *out = new(metav1.Duration) + **out = **in + } + if in.MachinePreserveTimeout != nil { + in, out := &in.MachinePreserveTimeout, &out.MachinePreserveTimeout + *out = new(metav1.Duration) + **out = **in + } + if in.DisableHealthTimeout != nil { + in, out := &in.DisableHealthTimeout, &out.DisableHealthTimeout + *out = new(bool) + **out = **in + } + if in.MaxEvictRetries != nil { + in, out := &in.MaxEvictRetries, &out.MaxEvictRetries + *out = new(int32) + **out = **in + } + if in.NodeConditions != nil { + in, out := &in.NodeConditions, &out.NodeConditions + *out = new(string) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineConfiguration. +func (in *MachineConfiguration) DeepCopy() *MachineConfiguration { + if in == nil { + return nil + } + out := new(MachineConfiguration) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MachineDeployment) DeepCopyInto(out *MachineDeployment) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineDeployment. +func (in *MachineDeployment) DeepCopy() *MachineDeployment { + if in == nil { + return nil + } + out := new(MachineDeployment) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *MachineDeployment) 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 *MachineDeploymentCondition) DeepCopyInto(out *MachineDeploymentCondition) { + *out = *in + in.LastUpdateTime.DeepCopyInto(&out.LastUpdateTime) + in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineDeploymentCondition. +func (in *MachineDeploymentCondition) DeepCopy() *MachineDeploymentCondition { + if in == nil { + return nil + } + out := new(MachineDeploymentCondition) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MachineDeploymentList) DeepCopyInto(out *MachineDeploymentList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]MachineDeployment, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineDeploymentList. +func (in *MachineDeploymentList) DeepCopy() *MachineDeploymentList { + if in == nil { + return nil + } + out := new(MachineDeploymentList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *MachineDeploymentList) 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 *MachineDeploymentSpec) DeepCopyInto(out *MachineDeploymentSpec) { + *out = *in + if in.Selector != nil { + in, out := &in.Selector, &out.Selector + *out = new(metav1.LabelSelector) + (*in).DeepCopyInto(*out) + } + in.Template.DeepCopyInto(&out.Template) + in.Strategy.DeepCopyInto(&out.Strategy) + if in.RevisionHistoryLimit != nil { + in, out := &in.RevisionHistoryLimit, &out.RevisionHistoryLimit + *out = new(int32) + **out = **in + } + if in.RollbackTo != nil { + in, out := &in.RollbackTo, &out.RollbackTo + *out = new(RollbackConfig) + **out = **in + } + if in.ProgressDeadlineSeconds != nil { + in, out := &in.ProgressDeadlineSeconds, &out.ProgressDeadlineSeconds + *out = new(int32) + **out = **in + } + if in.AutoPreserveFailedMachineMax != nil { + in, out := &in.AutoPreserveFailedMachineMax, &out.AutoPreserveFailedMachineMax + *out = new(int32) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineDeploymentSpec. +func (in *MachineDeploymentSpec) DeepCopy() *MachineDeploymentSpec { + if in == nil { + return nil + } + out := new(MachineDeploymentSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MachineDeploymentStatus) DeepCopyInto(out *MachineDeploymentStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]MachineDeploymentCondition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.CollisionCount != nil { + in, out := &in.CollisionCount, &out.CollisionCount + *out = new(int32) + **out = **in + } + if in.FailedMachines != nil { + in, out := &in.FailedMachines, &out.FailedMachines + *out = make([]*MachineSummary, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(MachineSummary) + (*in).DeepCopyInto(*out) + } + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineDeploymentStatus. +func (in *MachineDeploymentStatus) DeepCopy() *MachineDeploymentStatus { + if in == nil { + return nil + } + out := new(MachineDeploymentStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MachineDeploymentStrategy) DeepCopyInto(out *MachineDeploymentStrategy) { + *out = *in + if in.RollingUpdate != nil { + in, out := &in.RollingUpdate, &out.RollingUpdate + *out = new(RollingUpdateMachineDeployment) + (*in).DeepCopyInto(*out) + } + if in.InPlaceUpdate != nil { + in, out := &in.InPlaceUpdate, &out.InPlaceUpdate + *out = new(InPlaceUpdateMachineDeployment) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineDeploymentStrategy. +func (in *MachineDeploymentStrategy) DeepCopy() *MachineDeploymentStrategy { + if in == nil { + return nil + } + out := new(MachineDeploymentStrategy) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MachineList) DeepCopyInto(out *MachineList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Machine, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineList. +func (in *MachineList) DeepCopy() *MachineList { + if in == nil { + return nil + } + out := new(MachineList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *MachineList) 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 *MachineSet) DeepCopyInto(out *MachineSet) { + *out = *in + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.TypeMeta = in.TypeMeta + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineSet. +func (in *MachineSet) DeepCopy() *MachineSet { + if in == nil { + return nil + } + out := new(MachineSet) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *MachineSet) 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 *MachineSetCondition) DeepCopyInto(out *MachineSetCondition) { + *out = *in + in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineSetCondition. +func (in *MachineSetCondition) DeepCopy() *MachineSetCondition { + if in == nil { + return nil + } + out := new(MachineSetCondition) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MachineSetList) DeepCopyInto(out *MachineSetList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]MachineSet, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineSetList. +func (in *MachineSetList) DeepCopy() *MachineSetList { + if in == nil { + return nil + } + out := new(MachineSetList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *MachineSetList) 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 *MachineSetSpec) DeepCopyInto(out *MachineSetSpec) { + *out = *in + if in.Selector != nil { + in, out := &in.Selector, &out.Selector + *out = new(metav1.LabelSelector) + (*in).DeepCopyInto(*out) + } + out.MachineClass = in.MachineClass + in.Template.DeepCopyInto(&out.Template) + if in.AutoPreserveFailedMachineMax != nil { + in, out := &in.AutoPreserveFailedMachineMax, &out.AutoPreserveFailedMachineMax + *out = new(int32) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineSetSpec. +func (in *MachineSetSpec) DeepCopy() *MachineSetSpec { + if in == nil { + return nil + } + out := new(MachineSetSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MachineSetStatus) DeepCopyInto(out *MachineSetStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]MachineSetCondition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + in.LastOperation.DeepCopyInto(&out.LastOperation) + if in.FailedMachines != nil { + in, out := &in.FailedMachines, &out.FailedMachines + *out = new([]MachineSummary) + if **in != nil { + in, out := *in, *out + *out = make([]MachineSummary, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + } + if in.AutoPreserveFailedMachineCount != nil { + in, out := &in.AutoPreserveFailedMachineCount, &out.AutoPreserveFailedMachineCount + *out = new(int32) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineSetStatus. +func (in *MachineSetStatus) DeepCopy() *MachineSetStatus { + if in == nil { + return nil + } + out := new(MachineSetStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MachineSpec) DeepCopyInto(out *MachineSpec) { + *out = *in + out.Class = in.Class + in.NodeTemplateSpec.DeepCopyInto(&out.NodeTemplateSpec) + if in.MachineConfiguration != nil { + in, out := &in.MachineConfiguration, &out.MachineConfiguration + *out = new(MachineConfiguration) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineSpec. +func (in *MachineSpec) DeepCopy() *MachineSpec { + if in == nil { + return nil + } + out := new(MachineSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MachineStatus) DeepCopyInto(out *MachineStatus) { + *out = *in + if in.Addresses != nil { + in, out := &in.Addresses, &out.Addresses + *out = make([]v1.NodeAddress, len(*in)) + copy(*out, *in) + } + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.NodeCondition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + in.LastOperation.DeepCopyInto(&out.LastOperation) + in.CurrentStatus.DeepCopyInto(&out.CurrentStatus) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineStatus. +func (in *MachineStatus) DeepCopy() *MachineStatus { + if in == nil { + return nil + } + out := new(MachineStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MachineSummary) DeepCopyInto(out *MachineSummary) { + *out = *in + in.LastOperation.DeepCopyInto(&out.LastOperation) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineSummary. +func (in *MachineSummary) DeepCopy() *MachineSummary { + if in == nil { + return nil + } + out := new(MachineSummary) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MachineTemplateSpec) DeepCopyInto(out *MachineTemplateSpec) { + *out = *in + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineTemplateSpec. +func (in *MachineTemplateSpec) DeepCopy() *MachineTemplateSpec { + if in == nil { + return nil + } + out := new(MachineTemplateSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NodeTemplate) DeepCopyInto(out *NodeTemplate) { + *out = *in + if in.Capacity != nil { + in, out := &in.Capacity, &out.Capacity + *out = make(v1.ResourceList, len(*in)) + for key, val := range *in { + (*out)[key] = val.DeepCopy() + } + } + if in.VirtualCapacity != nil { + in, out := &in.VirtualCapacity, &out.VirtualCapacity + *out = make(v1.ResourceList, len(*in)) + for key, val := range *in { + (*out)[key] = val.DeepCopy() + } + } + if in.Architecture != nil { + in, out := &in.Architecture, &out.Architecture + *out = new(string) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeTemplate. +func (in *NodeTemplate) DeepCopy() *NodeTemplate { + if in == nil { + return nil + } + out := new(NodeTemplate) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NodeTemplateSpec) DeepCopyInto(out *NodeTemplateSpec) { + *out = *in + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeTemplateSpec. +func (in *NodeTemplateSpec) DeepCopy() *NodeTemplateSpec { + if in == nil { + return nil + } + out := new(NodeTemplateSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RollbackConfig) DeepCopyInto(out *RollbackConfig) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RollbackConfig. +func (in *RollbackConfig) DeepCopy() *RollbackConfig { + if in == nil { + return nil + } + out := new(RollbackConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RollingUpdateMachineDeployment) DeepCopyInto(out *RollingUpdateMachineDeployment) { + *out = *in + in.UpdateConfiguration.DeepCopyInto(&out.UpdateConfiguration) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RollingUpdateMachineDeployment. +func (in *RollingUpdateMachineDeployment) DeepCopy() *RollingUpdateMachineDeployment { + if in == nil { + return nil + } + out := new(RollingUpdateMachineDeployment) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *UpdateConfiguration) DeepCopyInto(out *UpdateConfiguration) { + *out = *in + if in.MaxUnavailable != nil { + in, out := &in.MaxUnavailable, &out.MaxUnavailable + *out = new(intstr.IntOrString) + **out = **in + } + if in.MaxSurge != nil { + in, out := &in.MaxSurge, &out.MaxSurge + *out = new(intstr.IntOrString) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UpdateConfiguration. +func (in *UpdateConfiguration) DeepCopy() *UpdateConfiguration { + if in == nil { + return nil + } + out := new(UpdateConfiguration) + in.DeepCopyInto(out) + return out +} diff --git a/pkg/apis/machine/v1alpha1/zz_generated.defaults.go b/pkg/apis/machine/v1alpha1/zz_generated.defaults.go new file mode 100644 index 000000000..dce68e638 --- /dev/null +++ b/pkg/apis/machine/v1alpha1/zz_generated.defaults.go @@ -0,0 +1,21 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +// SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors +// +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by defaulter-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// RegisterDefaults adds defaulters functions to the given scheme. +// Public to allow building arbitrary schemes. +// All generated defaulters are covering - they call all nested defaulters. +func RegisterDefaults(scheme *runtime.Scheme) error { + return nil +} diff --git a/pkg/apis/machine/zz_generated.deepcopy.go b/pkg/apis/machine/zz_generated.deepcopy.go new file mode 100644 index 000000000..2f1d11e2f --- /dev/null +++ b/pkg/apis/machine/zz_generated.deepcopy.go @@ -0,0 +1,906 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +// SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors +// +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package machine + +import ( + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + intstr "k8s.io/apimachinery/pkg/util/intstr" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClassSpec) DeepCopyInto(out *ClassSpec) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClassSpec. +func (in *ClassSpec) DeepCopy() *ClassSpec { + if in == nil { + return nil + } + out := new(ClassSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CurrentStatus) DeepCopyInto(out *CurrentStatus) { + *out = *in + in.LastUpdateTime.DeepCopyInto(&out.LastUpdateTime) + if in.PreserveExpiryTime != nil { + in, out := &in.PreserveExpiryTime, &out.PreserveExpiryTime + *out = (*in).DeepCopy() + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CurrentStatus. +func (in *CurrentStatus) DeepCopy() *CurrentStatus { + if in == nil { + return nil + } + out := new(CurrentStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *InPlaceUpdateMachineDeployment) DeepCopyInto(out *InPlaceUpdateMachineDeployment) { + *out = *in + in.UpdateConfiguration.DeepCopyInto(&out.UpdateConfiguration) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InPlaceUpdateMachineDeployment. +func (in *InPlaceUpdateMachineDeployment) DeepCopy() *InPlaceUpdateMachineDeployment { + if in == nil { + return nil + } + out := new(InPlaceUpdateMachineDeployment) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LastOperation) DeepCopyInto(out *LastOperation) { + *out = *in + in.LastUpdateTime.DeepCopyInto(&out.LastUpdateTime) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LastOperation. +func (in *LastOperation) DeepCopy() *LastOperation { + if in == nil { + return nil + } + out := new(LastOperation) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Machine) DeepCopyInto(out *Machine) { + *out = *in + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.TypeMeta = in.TypeMeta + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Machine. +func (in *Machine) DeepCopy() *Machine { + if in == nil { + return nil + } + out := new(Machine) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Machine) 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 *MachineClass) DeepCopyInto(out *MachineClass) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + if in.NodeTemplate != nil { + in, out := &in.NodeTemplate, &out.NodeTemplate + *out = new(NodeTemplate) + (*in).DeepCopyInto(*out) + } + if in.CredentialsSecretRef != nil { + in, out := &in.CredentialsSecretRef, &out.CredentialsSecretRef + *out = new(v1.SecretReference) + **out = **in + } + in.ProviderSpec.DeepCopyInto(&out.ProviderSpec) + if in.SecretRef != nil { + in, out := &in.SecretRef, &out.SecretRef + *out = new(v1.SecretReference) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineClass. +func (in *MachineClass) DeepCopy() *MachineClass { + if in == nil { + return nil + } + out := new(MachineClass) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *MachineClass) 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 *MachineClassList) DeepCopyInto(out *MachineClassList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]MachineClass, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineClassList. +func (in *MachineClassList) DeepCopy() *MachineClassList { + if in == nil { + return nil + } + out := new(MachineClassList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *MachineClassList) 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 *MachineConfiguration) DeepCopyInto(out *MachineConfiguration) { + *out = *in + if in.MachineDrainTimeout != nil { + in, out := &in.MachineDrainTimeout, &out.MachineDrainTimeout + *out = new(metav1.Duration) + **out = **in + } + if in.MachineHealthTimeout != nil { + in, out := &in.MachineHealthTimeout, &out.MachineHealthTimeout + *out = new(metav1.Duration) + **out = **in + } + if in.MachineCreationTimeout != nil { + in, out := &in.MachineCreationTimeout, &out.MachineCreationTimeout + *out = new(metav1.Duration) + **out = **in + } + if in.MachineInPlaceUpdateTimeout != nil { + in, out := &in.MachineInPlaceUpdateTimeout, &out.MachineInPlaceUpdateTimeout + *out = new(metav1.Duration) + **out = **in + } + if in.MachinePreserveTimeout != nil { + in, out := &in.MachinePreserveTimeout, &out.MachinePreserveTimeout + *out = new(metav1.Duration) + **out = **in + } + if in.DisableHealthTimeout != nil { + in, out := &in.DisableHealthTimeout, &out.DisableHealthTimeout + *out = new(bool) + **out = **in + } + if in.MaxEvictRetries != nil { + in, out := &in.MaxEvictRetries, &out.MaxEvictRetries + *out = new(int32) + **out = **in + } + if in.NodeConditions != nil { + in, out := &in.NodeConditions, &out.NodeConditions + *out = new(string) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineConfiguration. +func (in *MachineConfiguration) DeepCopy() *MachineConfiguration { + if in == nil { + return nil + } + out := new(MachineConfiguration) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MachineDeployment) DeepCopyInto(out *MachineDeployment) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineDeployment. +func (in *MachineDeployment) DeepCopy() *MachineDeployment { + if in == nil { + return nil + } + out := new(MachineDeployment) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *MachineDeployment) 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 *MachineDeploymentCondition) DeepCopyInto(out *MachineDeploymentCondition) { + *out = *in + in.LastUpdateTime.DeepCopyInto(&out.LastUpdateTime) + in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineDeploymentCondition. +func (in *MachineDeploymentCondition) DeepCopy() *MachineDeploymentCondition { + if in == nil { + return nil + } + out := new(MachineDeploymentCondition) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MachineDeploymentList) DeepCopyInto(out *MachineDeploymentList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]MachineDeployment, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineDeploymentList. +func (in *MachineDeploymentList) DeepCopy() *MachineDeploymentList { + if in == nil { + return nil + } + out := new(MachineDeploymentList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *MachineDeploymentList) 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 *MachineDeploymentRollback) DeepCopyInto(out *MachineDeploymentRollback) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.UpdatedAnnotations != nil { + in, out := &in.UpdatedAnnotations, &out.UpdatedAnnotations + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + out.RollbackTo = in.RollbackTo + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineDeploymentRollback. +func (in *MachineDeploymentRollback) DeepCopy() *MachineDeploymentRollback { + if in == nil { + return nil + } + out := new(MachineDeploymentRollback) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *MachineDeploymentRollback) 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 *MachineDeploymentSpec) DeepCopyInto(out *MachineDeploymentSpec) { + *out = *in + if in.Selector != nil { + in, out := &in.Selector, &out.Selector + *out = new(metav1.LabelSelector) + (*in).DeepCopyInto(*out) + } + in.Template.DeepCopyInto(&out.Template) + in.Strategy.DeepCopyInto(&out.Strategy) + if in.RevisionHistoryLimit != nil { + in, out := &in.RevisionHistoryLimit, &out.RevisionHistoryLimit + *out = new(int32) + **out = **in + } + if in.RollbackTo != nil { + in, out := &in.RollbackTo, &out.RollbackTo + *out = new(RollbackConfig) + **out = **in + } + if in.ProgressDeadlineSeconds != nil { + in, out := &in.ProgressDeadlineSeconds, &out.ProgressDeadlineSeconds + *out = new(int32) + **out = **in + } + if in.AutoPreserveFailedMachineMax != nil { + in, out := &in.AutoPreserveFailedMachineMax, &out.AutoPreserveFailedMachineMax + *out = new(int32) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineDeploymentSpec. +func (in *MachineDeploymentSpec) DeepCopy() *MachineDeploymentSpec { + if in == nil { + return nil + } + out := new(MachineDeploymentSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MachineDeploymentStatus) DeepCopyInto(out *MachineDeploymentStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]MachineDeploymentCondition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.CollisionCount != nil { + in, out := &in.CollisionCount, &out.CollisionCount + *out = new(int32) + **out = **in + } + if in.FailedMachines != nil { + in, out := &in.FailedMachines, &out.FailedMachines + *out = make([]*MachineSummary, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(MachineSummary) + (*in).DeepCopyInto(*out) + } + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineDeploymentStatus. +func (in *MachineDeploymentStatus) DeepCopy() *MachineDeploymentStatus { + if in == nil { + return nil + } + out := new(MachineDeploymentStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MachineDeploymentStrategy) DeepCopyInto(out *MachineDeploymentStrategy) { + *out = *in + if in.RollingUpdate != nil { + in, out := &in.RollingUpdate, &out.RollingUpdate + *out = new(RollingUpdateMachineDeployment) + (*in).DeepCopyInto(*out) + } + if in.InPlaceUpdate != nil { + in, out := &in.InPlaceUpdate, &out.InPlaceUpdate + *out = new(InPlaceUpdateMachineDeployment) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineDeploymentStrategy. +func (in *MachineDeploymentStrategy) DeepCopy() *MachineDeploymentStrategy { + if in == nil { + return nil + } + out := new(MachineDeploymentStrategy) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MachineList) DeepCopyInto(out *MachineList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Machine, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineList. +func (in *MachineList) DeepCopy() *MachineList { + if in == nil { + return nil + } + out := new(MachineList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *MachineList) 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 *MachineSet) DeepCopyInto(out *MachineSet) { + *out = *in + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.TypeMeta = in.TypeMeta + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineSet. +func (in *MachineSet) DeepCopy() *MachineSet { + if in == nil { + return nil + } + out := new(MachineSet) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *MachineSet) 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 *MachineSetCondition) DeepCopyInto(out *MachineSetCondition) { + *out = *in + in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineSetCondition. +func (in *MachineSetCondition) DeepCopy() *MachineSetCondition { + if in == nil { + return nil + } + out := new(MachineSetCondition) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MachineSetList) DeepCopyInto(out *MachineSetList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]MachineSet, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineSetList. +func (in *MachineSetList) DeepCopy() *MachineSetList { + if in == nil { + return nil + } + out := new(MachineSetList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *MachineSetList) 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 *MachineSetSpec) DeepCopyInto(out *MachineSetSpec) { + *out = *in + if in.Selector != nil { + in, out := &in.Selector, &out.Selector + *out = new(metav1.LabelSelector) + (*in).DeepCopyInto(*out) + } + out.MachineClass = in.MachineClass + in.Template.DeepCopyInto(&out.Template) + if in.AutoPreserveFailedMachineMax != nil { + in, out := &in.AutoPreserveFailedMachineMax, &out.AutoPreserveFailedMachineMax + *out = new(int32) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineSetSpec. +func (in *MachineSetSpec) DeepCopy() *MachineSetSpec { + if in == nil { + return nil + } + out := new(MachineSetSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MachineSetStatus) DeepCopyInto(out *MachineSetStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]MachineSetCondition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + in.LastOperation.DeepCopyInto(&out.LastOperation) + if in.FailedMachines != nil { + in, out := &in.FailedMachines, &out.FailedMachines + *out = new([]MachineSummary) + if **in != nil { + in, out := *in, *out + *out = make([]MachineSummary, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + } + if in.AutoPreserveFailedMachineCount != nil { + in, out := &in.AutoPreserveFailedMachineCount, &out.AutoPreserveFailedMachineCount + *out = new(int32) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineSetStatus. +func (in *MachineSetStatus) DeepCopy() *MachineSetStatus { + if in == nil { + return nil + } + out := new(MachineSetStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MachineSpec) DeepCopyInto(out *MachineSpec) { + *out = *in + out.Class = in.Class + in.NodeTemplateSpec.DeepCopyInto(&out.NodeTemplateSpec) + if in.MachineConfiguration != nil { + in, out := &in.MachineConfiguration, &out.MachineConfiguration + *out = new(MachineConfiguration) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineSpec. +func (in *MachineSpec) DeepCopy() *MachineSpec { + if in == nil { + return nil + } + out := new(MachineSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MachineStatus) DeepCopyInto(out *MachineStatus) { + *out = *in + if in.Addresses != nil { + in, out := &in.Addresses, &out.Addresses + *out = make([]v1.NodeAddress, len(*in)) + copy(*out, *in) + } + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.NodeCondition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + in.LastOperation.DeepCopyInto(&out.LastOperation) + in.CurrentStatus.DeepCopyInto(&out.CurrentStatus) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineStatus. +func (in *MachineStatus) DeepCopy() *MachineStatus { + if in == nil { + return nil + } + out := new(MachineStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MachineSummary) DeepCopyInto(out *MachineSummary) { + *out = *in + in.LastOperation.DeepCopyInto(&out.LastOperation) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineSummary. +func (in *MachineSummary) DeepCopy() *MachineSummary { + if in == nil { + return nil + } + out := new(MachineSummary) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MachineTemplate) DeepCopyInto(out *MachineTemplate) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Template.DeepCopyInto(&out.Template) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineTemplate. +func (in *MachineTemplate) DeepCopy() *MachineTemplate { + if in == nil { + return nil + } + out := new(MachineTemplate) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *MachineTemplate) 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 *MachineTemplateList) DeepCopyInto(out *MachineTemplateList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]MachineTemplate, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineTemplateList. +func (in *MachineTemplateList) DeepCopy() *MachineTemplateList { + if in == nil { + return nil + } + out := new(MachineTemplateList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *MachineTemplateList) 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 *MachineTemplateSpec) DeepCopyInto(out *MachineTemplateSpec) { + *out = *in + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineTemplateSpec. +func (in *MachineTemplateSpec) DeepCopy() *MachineTemplateSpec { + if in == nil { + return nil + } + out := new(MachineTemplateSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NodeTemplate) DeepCopyInto(out *NodeTemplate) { + *out = *in + if in.Capacity != nil { + in, out := &in.Capacity, &out.Capacity + *out = make(v1.ResourceList, len(*in)) + for key, val := range *in { + (*out)[key] = val.DeepCopy() + } + } + if in.VirtualCapacity != nil { + in, out := &in.VirtualCapacity, &out.VirtualCapacity + *out = make(v1.ResourceList, len(*in)) + for key, val := range *in { + (*out)[key] = val.DeepCopy() + } + } + if in.Architecture != nil { + in, out := &in.Architecture, &out.Architecture + *out = new(string) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeTemplate. +func (in *NodeTemplate) DeepCopy() *NodeTemplate { + if in == nil { + return nil + } + out := new(NodeTemplate) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NodeTemplateSpec) DeepCopyInto(out *NodeTemplateSpec) { + *out = *in + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeTemplateSpec. +func (in *NodeTemplateSpec) DeepCopy() *NodeTemplateSpec { + if in == nil { + return nil + } + out := new(NodeTemplateSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RollbackConfig) DeepCopyInto(out *RollbackConfig) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RollbackConfig. +func (in *RollbackConfig) DeepCopy() *RollbackConfig { + if in == nil { + return nil + } + out := new(RollbackConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RollingUpdateMachineDeployment) DeepCopyInto(out *RollingUpdateMachineDeployment) { + *out = *in + in.UpdateConfiguration.DeepCopyInto(&out.UpdateConfiguration) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RollingUpdateMachineDeployment. +func (in *RollingUpdateMachineDeployment) DeepCopy() *RollingUpdateMachineDeployment { + if in == nil { + return nil + } + out := new(RollingUpdateMachineDeployment) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *UpdateConfiguration) DeepCopyInto(out *UpdateConfiguration) { + *out = *in + if in.MaxUnavailable != nil { + in, out := &in.MaxUnavailable, &out.MaxUnavailable + *out = new(intstr.IntOrString) + **out = **in + } + if in.MaxSurge != nil { + in, out := &in.MaxSurge, &out.MaxSurge + *out = new(intstr.IntOrString) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UpdateConfiguration. +func (in *UpdateConfiguration) DeepCopy() *UpdateConfiguration { + if in == nil { + return nil + } + out := new(UpdateConfiguration) + in.DeepCopyInto(out) + return out +} From 0761fba9e3693fa0a520ff652db0cfb6965a2ae1 Mon Sep 17 00:00:00 2001 From: thiyyakat Date: Thu, 8 Jan 2026 14:19:11 +0530 Subject: [PATCH 43/43] Fix nil pointer dereferencing bug. --- pkg/controller/machineset.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/controller/machineset.go b/pkg/controller/machineset.go index 120d39b06..dca3ab1f1 100644 --- a/pkg/controller/machineset.go +++ b/pkg/controller/machineset.go @@ -508,7 +508,7 @@ func (c *controller) isMachineCandidateForPreservation(ctx context.Context, mach return false, nil } } - if *machineSet.Status.AutoPreserveFailedMachineCount < *machineSet.Spec.AutoPreserveFailedMachineMax { + if machineSet.Status.AutoPreserveFailedMachineCount != nil && machineSet.Spec.AutoPreserveFailedMachineMax != nil && *machineSet.Status.AutoPreserveFailedMachineCount < *machineSet.Spec.AutoPreserveFailedMachineMax { err := c.annotateMachineForAutoPreservation(ctx, machine) if err != nil { return true, err