Skip to content

🌱 [0.3] Backport 3740, 3759, and 3723 #3772

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
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
30 changes: 12 additions & 18 deletions controllers/machine_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,8 +235,6 @@ func patchMachine(ctx context.Context, patchHelper *patch.Helper, machine *clust
}

func (r *MachineReconciler) reconcile(ctx context.Context, cluster *clusterv1.Cluster, m *clusterv1.Machine) (ctrl.Result, error) {
logger := r.Log.WithValues("machine", m.Name, "namespace", m.Namespace)
logger = logger.WithValues("cluster", cluster.Name)

// If the Machine belongs to a cluster, add an owner reference.
if r.shouldAdopt(m) {
Expand All @@ -248,28 +246,24 @@ func (r *MachineReconciler) reconcile(ctx context.Context, cluster *clusterv1.Cl
})
}

// Call the inner reconciliation methods.
reconciliationErrors := []error{
r.reconcileBootstrap(ctx, cluster, m),
r.reconcileInfrastructure(ctx, cluster, m),
r.reconcileNodeRef(ctx, cluster, m),
phases := []func(context.Context, *clusterv1.Cluster, *clusterv1.Machine) (ctrl.Result, error){
r.reconcileBootstrap,
r.reconcileInfrastructure,
r.reconcileNodeRef,
}

// Parse the errors, making sure we record if there is a RequeueAfterError.
res := ctrl.Result{}
errs := []error{}
for _, err := range reconciliationErrors {
if requeueErr, ok := errors.Cause(err).(capierrors.HasRequeueAfterError); ok {
// Only record and log the first RequeueAfterError.
if !res.Requeue {
res.Requeue = true
res.RequeueAfter = requeueErr.GetRequeueAfter()
logger.Error(err, "Reconciliation for Machine asked to requeue")
}
for _, phase := range phases {
// Call the inner reconciliation methods.
phaseResult, err := phase(ctx, cluster, m)
if err != nil {
errs = append(errs, err)
}
if len(errs) > 0 {
continue
}

errs = append(errs, err)
res = util.LowestNonZeroResult(res, phaseResult)
}
return res, kerrors.NewAggregate(errs)
}
Expand Down
23 changes: 12 additions & 11 deletions controllers/machine_controller_noderef.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,68 +18,69 @@ package controllers

import (
"context"
"fmt"
"time"

"github.com/pkg/errors"
apicorev1 "k8s.io/api/core/v1"
clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha3"
"sigs.k8s.io/cluster-api/controllers/noderefutil"
capierrors "sigs.k8s.io/cluster-api/errors"
"sigs.k8s.io/cluster-api/util"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
)

var (
ErrNodeNotFound = errors.New("cannot find node with matching ProviderID")
)

func (r *MachineReconciler) reconcileNodeRef(ctx context.Context, cluster *clusterv1.Cluster, machine *clusterv1.Machine) error {
func (r *MachineReconciler) reconcileNodeRef(ctx context.Context, cluster *clusterv1.Cluster, machine *clusterv1.Machine) (ctrl.Result, error) {
logger := r.Log.WithValues("machine", machine.Name, "namespace", machine.Namespace)
// Check that the Machine hasn't been deleted or in the process.
if !machine.DeletionTimestamp.IsZero() {
return nil
return ctrl.Result{}, nil
}

// Check that the Machine doesn't already have a NodeRef.
if machine.Status.NodeRef != nil {
return nil
return ctrl.Result{}, nil
}

logger = logger.WithValues("cluster", cluster.Name)

// Check that the Machine has a valid ProviderID.
if machine.Spec.ProviderID == nil || *machine.Spec.ProviderID == "" {
logger.Info("Machine doesn't have a valid ProviderID yet")
return nil
return ctrl.Result{}, nil
}

providerID, err := noderefutil.NewProviderID(*machine.Spec.ProviderID)
if err != nil {
return err
return ctrl.Result{}, err
}

remoteClient, err := r.Tracker.GetClient(ctx, util.ObjectKey(cluster))
if err != nil {
return err
return ctrl.Result{}, err
}

// Get the Node reference.
nodeRef, err := r.getNodeReference(remoteClient, providerID)
if err != nil {
if err == ErrNodeNotFound {
return errors.Wrapf(&capierrors.RequeueAfterError{RequeueAfter: 20 * time.Second},
"cannot assign NodeRef to Machine %q in namespace %q, no matching Node", machine.Name, machine.Namespace)
logger.Info(fmt.Sprintf("Cannot assign NodeRef to Machine: %s, requeuing", ErrNodeNotFound.Error()))
return ctrl.Result{RequeueAfter: 20 * time.Second}, nil
}
logger.Error(err, "Failed to assign NodeRef")
r.recorder.Event(machine, apicorev1.EventTypeWarning, "FailedSetNodeRef", err.Error())
return err
return ctrl.Result{}, err
}

// Set the Machine NodeRef.
machine.Status.NodeRef = nodeRef
logger.Info("Set Machine's NodeRef", "noderef", machine.Status.NodeRef.Name)
r.recorder.Event(machine, apicorev1.EventTypeNormal, "SuccessfulSetNodeRef", machine.Status.NodeRef.Name)
return nil
return ctrl.Result{}, nil
}

func (r *MachineReconciler) getNodeReference(c client.Reader, providerID *noderefutil.ProviderID) (*apicorev1.ObjectReference, error) {
Expand Down
65 changes: 34 additions & 31 deletions controllers/machine_controller_phases.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,17 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/utils/pointer"
"sigs.k8s.io/cluster-api/util/annotations"
"sigs.k8s.io/cluster-api/util/conditions"
utilconversion "sigs.k8s.io/cluster-api/util/conversion"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
"sigs.k8s.io/controller-runtime/pkg/handler"

clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha3"
"sigs.k8s.io/cluster-api/controllers/external"
capierrors "sigs.k8s.io/cluster-api/errors"
"sigs.k8s.io/cluster-api/util"
"sigs.k8s.io/cluster-api/util/annotations"
"sigs.k8s.io/cluster-api/util/conditions"
utilconversion "sigs.k8s.io/cluster-api/util/conversion"
"sigs.k8s.io/cluster-api/util/patch"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
"sigs.k8s.io/controller-runtime/pkg/handler"
)

var (
Expand Down Expand Up @@ -172,38 +172,40 @@ func (r *MachineReconciler) reconcileExternal(ctx context.Context, cluster *clus
}

// reconcileBootstrap reconciles the Spec.Bootstrap.ConfigRef object on a Machine.
func (r *MachineReconciler) reconcileBootstrap(ctx context.Context, cluster *clusterv1.Cluster, m *clusterv1.Machine) error {
func (r *MachineReconciler) reconcileBootstrap(ctx context.Context, cluster *clusterv1.Cluster, m *clusterv1.Machine) (ctrl.Result, error) {
logger := r.Log.WithValues("machine", m.Name, "namespace", m.Namespace)

// If the bootstrap data is populated, set ready and return.
if m.Spec.Bootstrap.DataSecretName != nil {
m.Status.BootstrapReady = true
conditions.MarkTrue(m, clusterv1.BootstrapReadyCondition)
return nil
return ctrl.Result{}, nil
}

// If the Boostrap ref is nil (and so the machine should use user generated data secret), return.
if m.Spec.Bootstrap.ConfigRef == nil {
return nil
return ctrl.Result{}, nil
}

// Call generic external reconciler if we have an external reference.
externalResult, err := r.reconcileExternal(ctx, cluster, m, m.Spec.Bootstrap.ConfigRef)
if err != nil {
return err
return ctrl.Result{}, err
}
if externalResult.Paused {
return nil
return ctrl.Result{}, nil
}
bootstrapConfig := externalResult.Result

// If the bootstrap config is being deleted, return early.
if !bootstrapConfig.GetDeletionTimestamp().IsZero() {
return nil
return ctrl.Result{}, nil
}

// Determine if the bootstrap provider is ready.
ready, err := external.IsReady(bootstrapConfig)
if err != nil {
return err
return ctrl.Result{}, err
}

// Report a summary of current status of the bootstrap object defined for this machine.
Expand All @@ -214,26 +216,28 @@ func (r *MachineReconciler) reconcileBootstrap(ctx context.Context, cluster *clu

// If the bootstrap provider is not ready, requeue.
if !ready {
return errors.Wrapf(&capierrors.RequeueAfterError{RequeueAfter: externalReadyWait},
"Bootstrap provider for Machine %q in namespace %q is not ready, requeuing", m.Name, m.Namespace)
logger.Info("Bootstrap provider is not ready, requeuing")
return ctrl.Result{RequeueAfter: externalReadyWait}, nil
}

// Get and set the name of the secret containing the bootstrap data.
secretName, _, err := unstructured.NestedString(bootstrapConfig.Object, "status", "dataSecretName")
if err != nil {
return errors.Wrapf(err, "failed to retrieve dataSecretName from bootstrap provider for Machine %q in namespace %q", m.Name, m.Namespace)
return ctrl.Result{}, errors.Wrapf(err, "failed to retrieve dataSecretName from bootstrap provider for Machine %q in namespace %q", m.Name, m.Namespace)
} else if secretName == "" {
return errors.Errorf("retrieved empty dataSecretName from bootstrap provider for Machine %q in namespace %q", m.Name, m.Namespace)
return ctrl.Result{}, errors.Errorf("retrieved empty dataSecretName from bootstrap provider for Machine %q in namespace %q", m.Name, m.Namespace)
}

m.Spec.Bootstrap.Data = nil
m.Spec.Bootstrap.DataSecretName = pointer.StringPtr(secretName)
m.Status.BootstrapReady = true
return nil
return ctrl.Result{}, nil
}

// reconcileInfrastructure reconciles the Spec.InfrastructureRef object on a Machine.
func (r *MachineReconciler) reconcileInfrastructure(ctx context.Context, cluster *clusterv1.Cluster, m *clusterv1.Machine) error {
func (r *MachineReconciler) reconcileInfrastructure(ctx context.Context, cluster *clusterv1.Cluster, m *clusterv1.Machine) (ctrl.Result, error) {
logger := r.Log.WithValues("machine", m.Name, "namespace", m.Namespace)

// Call generic external reconciler.
infraReconcileResult, err := r.reconcileExternal(ctx, cluster, m, &m.Spec.InfrastructureRef)
if err != nil {
Expand All @@ -244,22 +248,22 @@ func (r *MachineReconciler) reconcileInfrastructure(ctx context.Context, cluster
m.Status.FailureMessage = pointer.StringPtr(fmt.Sprintf("Machine infrastructure resource %v with name %q has been deleted after being ready",
m.Spec.InfrastructureRef.GroupVersionKind(), m.Spec.InfrastructureRef.Name))
}
return err
return ctrl.Result{}, err
}
// if the external object is paused, return without any further processing
if infraReconcileResult.Paused {
return nil
return ctrl.Result{}, nil
}
infraConfig := infraReconcileResult.Result

if !infraConfig.GetDeletionTimestamp().IsZero() {
return nil
return ctrl.Result{}, nil
}

// Determine if the infrastructure provider is ready.
ready, err := external.IsReady(infraConfig)
if err != nil {
return err
return ctrl.Result{}, err
}
m.Status.InfrastructureReady = ready

Expand All @@ -271,23 +275,22 @@ func (r *MachineReconciler) reconcileInfrastructure(ctx context.Context, cluster

// If the infrastructure provider is not ready, return early.
if !ready {
return errors.Wrapf(&capierrors.RequeueAfterError{RequeueAfter: externalReadyWait},
"Infrastructure provider for Machine %q in namespace %q is not ready, requeuing", m.Name, m.Namespace,
)
logger.Info("Infrastructure provider is not ready, requeuing")
return ctrl.Result{RequeueAfter: externalReadyWait}, nil
}

// Get Spec.ProviderID from the infrastructure provider.
var providerID string
if err := util.UnstructuredUnmarshalField(infraConfig, &providerID, "spec", "providerID"); err != nil {
return errors.Wrapf(err, "failed to retrieve Spec.ProviderID from infrastructure provider for Machine %q in namespace %q", m.Name, m.Namespace)
return ctrl.Result{}, errors.Wrapf(err, "failed to retrieve Spec.ProviderID from infrastructure provider for Machine %q in namespace %q", m.Name, m.Namespace)
} else if providerID == "" {
return errors.Errorf("retrieved empty Spec.ProviderID from infrastructure provider for Machine %q in namespace %q", m.Name, m.Namespace)
return ctrl.Result{}, errors.Errorf("retrieved empty Spec.ProviderID from infrastructure provider for Machine %q in namespace %q", m.Name, m.Namespace)
}

// Get and set Status.Addresses from the infrastructure provider.
err = util.UnstructuredUnmarshalField(infraConfig, &m.Status.Addresses, "status", "addresses")
if err != nil && err != util.ErrUnstructuredFieldNotFound {
return errors.Wrapf(err, "failed to retrieve addresses from infrastructure provider for Machine %q in namespace %q", m.Name, m.Namespace)
return ctrl.Result{}, errors.Wrapf(err, "failed to retrieve addresses from infrastructure provider for Machine %q in namespace %q", m.Name, m.Namespace)
}

// Get and set the failure domain from the infrastructure provider.
Expand All @@ -296,11 +299,11 @@ func (r *MachineReconciler) reconcileInfrastructure(ctx context.Context, cluster
switch {
case err == util.ErrUnstructuredFieldNotFound: // no-op
case err != nil:
return errors.Wrapf(err, "failed to failure domain from infrastructure provider for Machine %q in namespace %q", m.Name, m.Namespace)
return ctrl.Result{}, errors.Wrapf(err, "failed to failure domain from infrastructure provider for Machine %q in namespace %q", m.Name, m.Namespace)
default:
m.Spec.FailureDomain = pointer.StringPtr(failureDomain)
}

m.Spec.ProviderID = pointer.StringPtr(providerID)
return nil
return ctrl.Result{}, nil
}
Loading