Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 50 additions & 9 deletions pkg/controllers/machinesync/machine_sync_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,16 @@ var (

// errUnsupportedCPMSOwnedMachineConversion is returned when attempting to convert ControlPlaneMachineSet owned machines.
errUnsupportedCPMSOwnedMachineConversion = errors.New("conversion of control plane machines owned by control plane machine set is currently not supported")

// errInvalidInfraClusterReference is returned when the cluster name is empty in CAPI machine spec.
errInvalidInfraClusterReference = errors.New("cluster name is empty in Cluster API machine spec")

// errInvalidInfraMachineReference is returned when the infrastructure machine reference is invalid or incomplete.
errInvalidInfraMachineReference = errors.New("infrastructure machine reference is invalid or incomplete")
)

const (
terminalConfigurationErrorLog string = "Detected terminal configuration error - cluster name or infrastructure machine reference is empty, not requeuing"
)

// MachineSyncReconciler reconciles CAPI and MAPI machines.
Expand All @@ -136,7 +146,7 @@ type MachineSyncReconciler struct {
MAPINamespace string
}

// SetupWithManager sets the CoreClusterReconciler controller up with the given manager.
// SetupWithManager sets the MachineSyncReconciler controller up with the given manager.
func (r *MachineSyncReconciler) SetupWithManager(mgr ctrl.Manager) error {
infraMachine, _, err := controllers.InitInfraMachineAndInfraClusterFromProvider(r.Platform)
if err != nil {
Expand All @@ -163,7 +173,7 @@ func (r *MachineSyncReconciler) SetupWithManager(mgr ctrl.Manager) error {
).
Watches(
infraMachine,
handler.EnqueueRequestsFromMapFunc(util.RewriteNamespace(r.MAPINamespace)),
handler.EnqueueRequestsFromMapFunc(util.ResolveCAPIMachineFromInfraMachine(r.MAPINamespace)),
builder.WithPredicates(util.FilterNamespace(r.CAPINamespace)),
).
Complete(r); err != nil {
Expand Down Expand Up @@ -282,11 +292,20 @@ func (r *MachineSyncReconciler) reconcileCAPIMachinetoMAPIMachine(ctx context.Co
}

infraCluster, infraMachine, err := r.fetchCAPIInfraResources(ctx, sourceCAPIMachine)
if err != nil {
if err != nil { //nolint:nestif
fetchErr := fmt.Errorf("failed to fetch Cluster API infra resources: %w", err)

if existingMAPIMachine == nil {
// Don't requeue for terminal configuration errors
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to do the same for MachineSets?

if errors.Is(err, errInvalidInfraClusterReference) || errors.Is(err, errInvalidInfraMachineReference) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are repeating this check quite a lot, how about having a small function for this, so the configuration errors set can also be extended in a single point in the future.

e.g. something along the lines of
isTerminalConfigurationError()

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still see these repeated, would it make sense to add this util func?

logger.Error(err, terminalConfigurationErrorLog)
r.Recorder.Event(sourceCAPIMachine, corev1.EventTypeWarning, "SynchronizationError", fetchErr.Error())

return ctrl.Result{}, nil
}

r.Recorder.Event(sourceCAPIMachine, corev1.EventTypeWarning, "SynchronizationWarning", fetchErr.Error())

return ctrl.Result{}, fetchErr
}

Expand All @@ -295,6 +314,12 @@ func (r *MachineSyncReconciler) reconcileCAPIMachinetoMAPIMachine(ctx context.Co
return ctrl.Result{}, utilerrors.NewAggregate([]error{fetchErr, condErr})
}

// Don't requeue for terminal configuration errors
if errors.Is(err, errInvalidInfraClusterReference) || errors.Is(err, errInvalidInfraMachineReference) {
logger.Error(err, terminalConfigurationErrorLog)
return ctrl.Result{}, nil
}

return ctrl.Result{}, fetchErr
}

Expand Down Expand Up @@ -410,6 +435,12 @@ func (r *MachineSyncReconciler) reconcileMAPIMachinetoCAPIMachine(ctx context.Co
return ctrl.Result{}, utilerrors.NewAggregate([]error{fetchErr, condErr})
}

// Don't requeue for terminal configuration errors
if errors.Is(err, errInvalidInfraClusterReference) || errors.Is(err, errInvalidInfraMachineReference) {
logger.Error(err, terminalConfigurationErrorLog)
return ctrl.Result{}, nil
}

return ctrl.Result{}, fetchErr
}

Expand Down Expand Up @@ -949,6 +980,18 @@ func (r *MachineSyncReconciler) fetchCAPIInfraResources(ctx context.Context, cap
Name: infraMachineRef.Name,
}

// Validate that required references are not empty to avoid nil pointer issues later.
// These are terminal configuration errors that require user intervention.
if capiMachine.Spec.ClusterName == "" {
return nil, nil, fmt.Errorf("machine %s/%s: %w",
capiMachine.Namespace, capiMachine.Name, errInvalidInfraClusterReference)
}

if infraMachineRef.Name == "" || infraMachineRef.Namespace == "" {
return nil, nil, fmt.Errorf("machine %s/%s: %w",
capiMachine.Namespace, capiMachine.Name, errInvalidInfraMachineReference)
}

infraMachine, infraCluster, err := controllers.InitInfraMachineAndInfraClusterFromProvider(r.Platform)
if err != nil {
return nil, nil, fmt.Errorf("unable to devise Cluster API infra resources: %w", err)
Expand All @@ -968,7 +1011,9 @@ func (r *MachineSyncReconciler) fetchCAPIInfraResources(ctx context.Context, cap
}

//nolint:funlen,gocognit,cyclop
func (r *MachineSyncReconciler) reconcileMAPItoCAPIMachineDeletion(ctx context.Context, mapiMachine *mapiv1beta1.Machine, capiMachine *clusterv1.Machine, infraMachine client.Object) (bool, error) {
func (r *MachineSyncReconciler) reconcileMAPItoCAPIMachineDeletion(ctx context.Context, mapiMachine *mapiv1beta1.Machine, capiMachine *clusterv1.Machine, infraMachine client.Object) (shouldRequeue bool, err error) {
logger := logf.FromContext(ctx)

if mapiMachine.DeletionTimestamp.IsZero() {
if capiMachine == nil || capiMachine.DeletionTimestamp.IsZero() {
// Neither MAPI authoritative machine nor its CAPI non-authoritative machine mirror
Expand All @@ -986,8 +1031,6 @@ func (r *MachineSyncReconciler) reconcileMAPItoCAPIMachineDeletion(ctx context.C
return true, nil
}

logger := logf.FromContext(ctx)

if capiMachine == nil && util.IsNilObject(infraMachine) {
logger.Info("Cluster API machine and infra machine do not exist, removing corresponding Machine API machine sync finalizer")
// We don't have a capi machine or infra resouorces to clean up we can
Expand Down Expand Up @@ -1185,9 +1228,7 @@ func (r *MachineSyncReconciler) reconcileCAPItoMAPIMachineDeletion(ctx context.C

// ensureSyncFinalizer ensures the sync finalizer is present across the mapi
// machine, capi machine and capi infra machine.
func (r *MachineSyncReconciler) ensureSyncFinalizer(ctx context.Context, mapiMachine *mapiv1beta1.Machine, capiMachine *clusterv1.Machine, infraMachine client.Object) (bool, error) {
var shouldRequeue bool

func (r *MachineSyncReconciler) ensureSyncFinalizer(ctx context.Context, mapiMachine *mapiv1beta1.Machine, capiMachine *clusterv1.Machine, infraMachine client.Object) (shouldRequeue bool, err error) {
var errors []error

if mapiMachine != nil {
Expand Down
Loading