Skip to content

Commit 9be7337

Browse files
Remove generated names from error messages to reduce reconciliation
Signed-off-by: killianmuldoon <[email protected]>
1 parent c3e0ec6 commit 9be7337

File tree

2 files changed

+92
-16
lines changed

2 files changed

+92
-16
lines changed

internal/controllers/topology/cluster/reconcile_state.go

+43-16
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package cluster
1919
import (
2020
"context"
2121
"fmt"
22+
"strings"
2223

2324
"github.com/pkg/errors"
2425
corev1 "k8s.io/api/core/v1"
@@ -184,7 +185,7 @@ func (r *Reconciler) reconcileControlPlane(ctx context.Context, s *scope.Scope)
184185

185186
cpInfraRef, err := contract.ControlPlane().MachineTemplate().InfrastructureRef().Get(s.Desired.ControlPlane.Object)
186187
if err != nil {
187-
return errors.Wrapf(err, "failed to update %s", tlog.KObj{Obj: s.Desired.ControlPlane.InfrastructureMachineTemplate})
188+
return errors.Wrapf(err, "failed to reconcile %s", tlog.KObj{Obj: s.Desired.ControlPlane.InfrastructureMachineTemplate})
188189
}
189190

190191
// Create or update the MachineInfrastructureTemplate of the control plane.
@@ -198,13 +199,13 @@ func (r *Reconciler) reconcileControlPlane(ctx context.Context, s *scope.Scope)
198199
},
199200
)
200201
if err != nil {
201-
return errors.Wrapf(err, "failed to update %s", tlog.KObj{Obj: s.Desired.ControlPlane.InfrastructureMachineTemplate})
202+
return err
202203
}
203204

204205
// The controlPlaneObject.Spec.machineTemplate.infrastructureRef has to be updated in the desired object
205206
err = contract.ControlPlane().MachineTemplate().InfrastructureRef().Set(s.Desired.ControlPlane.Object, refToUnstructured(cpInfraRef))
206207
if err != nil {
207-
return errors.Wrapf(err, "failed to update %s", tlog.KObj{Obj: s.Desired.ControlPlane.Object})
208+
return errors.Wrapf(err, "failed to reconcile %s", tlog.KObj{Obj: s.Desired.ControlPlane.Object})
208209
}
209210
}
210211

@@ -227,7 +228,7 @@ func (r *Reconciler) reconcileControlPlane(ctx context.Context, s *scope.Scope)
227228
},
228229
},
229230
}); err != nil {
230-
return errors.Wrapf(err, "failed to update %s", tlog.KObj{Obj: s.Desired.ControlPlane.Object})
231+
return err
231232
}
232233

233234
// If the ControlPlane has defined a current or desired MachineHealthCheck attempt to reconcile it.
@@ -242,7 +243,7 @@ func (r *Reconciler) reconcileControlPlane(ctx context.Context, s *scope.Scope)
242243

243244
// Reconcile the current and desired state of the MachineHealthCheck.
244245
if err := r.reconcileMachineHealthCheck(ctx, s.Current.ControlPlane.MachineHealthCheck, s.Desired.ControlPlane.MachineHealthCheck); err != nil {
245-
return errors.Wrapf(err, "failed to update %s", tlog.KObj{Obj: s.Desired.ControlPlane.MachineHealthCheck})
246+
return err
246247
}
247248
}
248249
return nil
@@ -403,21 +404,21 @@ func (r *Reconciler) createMachineDeployment(ctx context.Context, cluster *clust
403404
cluster: cluster,
404405
desired: md.InfrastructureMachineTemplate,
405406
}); err != nil {
406-
return errors.Wrapf(err, "failed to create %s", tlog.KObj{Obj: md.Object})
407+
return errors.Wrapf(err, "failed to create %s", md.Object.Kind)
407408
}
408409

409410
bootstrapCtx, _ := log.WithObject(md.BootstrapTemplate).Into(ctx)
410411
if err := r.reconcileReferencedTemplate(bootstrapCtx, reconcileReferencedTemplateInput{
411412
cluster: cluster,
412413
desired: md.BootstrapTemplate,
413414
}); err != nil {
414-
return errors.Wrapf(err, "failed to create %s", tlog.KObj{Obj: md.Object})
415+
return errors.Wrapf(err, "failed to create %s", md.Object.Kind)
415416
}
416417

417418
log = log.WithObject(md.Object)
418419
log.Infof(fmt.Sprintf("Creating %s", tlog.KObj{Obj: md.Object}))
419420
if err := r.Client.Create(ctx, md.Object.DeepCopy()); err != nil {
420-
return errors.Wrapf(err, "failed to create %s", tlog.KObj{Obj: md.Object})
421+
return createErrorWithoutObjectName(err, md.Object)
421422
}
422423
r.recorder.Eventf(cluster, corev1.EventTypeNormal, createEventReason, "Created %q", tlog.KObj{Obj: md.Object})
423424

@@ -429,7 +430,7 @@ func (r *Reconciler) createMachineDeployment(ctx context.Context, cluster *clust
429430
*ownerReferenceTo(md.Object),
430431
})
431432
if err := r.reconcileMachineHealthCheck(ctx, nil, md.MachineHealthCheck); err != nil {
432-
return errors.Wrapf(err, "failed to create %s", tlog.KObj{Obj: md.MachineHealthCheck})
433+
return err
433434
}
434435
}
435436
return nil
@@ -448,7 +449,7 @@ func (r *Reconciler) updateMachineDeployment(ctx context.Context, cluster *clust
448449
templateNamePrefix: infrastructureMachineTemplateNamePrefix(cluster.Name, mdTopologyName),
449450
compatibilityChecker: check.ObjectsAreCompatible,
450451
}); err != nil {
451-
return errors.Wrapf(err, "failed to update %s", tlog.KObj{Obj: currentMD.Object})
452+
return errors.Wrapf(err, "failed to reconcile %s", tlog.KObj{Obj: currentMD.Object})
452453
}
453454

454455
bootstrapCtx, _ := log.WithObject(desiredMD.BootstrapTemplate).Into(ctx)
@@ -460,13 +461,13 @@ func (r *Reconciler) updateMachineDeployment(ctx context.Context, cluster *clust
460461
templateNamePrefix: bootstrapTemplateNamePrefix(cluster.Name, mdTopologyName),
461462
compatibilityChecker: check.ObjectsAreInTheSameNamespace,
462463
}); err != nil {
463-
return errors.Wrapf(err, "failed to update %s", tlog.KObj{Obj: currentMD.Object})
464+
return errors.Wrapf(err, "failed to reconcile %s", tlog.KObj{Obj: currentMD.Object})
464465
}
465466

466467
// Patch MachineHealthCheck for the MachineDeployment.
467468
if desiredMD.MachineHealthCheck != nil || currentMD.MachineHealthCheck != nil {
468469
if err := r.reconcileMachineHealthCheck(ctx, currentMD.MachineHealthCheck, desiredMD.MachineHealthCheck); err != nil {
469-
return errors.Wrapf(err, "failed to update %s", tlog.KObj{Obj: desiredMD.MachineHealthCheck})
470+
return err
470471
}
471472
}
472473

@@ -525,7 +526,7 @@ func (r *Reconciler) deleteMachineDeployment(ctx context.Context, cluster *clust
525526
// delete MachineHealthCheck for the MachineDeployment.
526527
if md.MachineHealthCheck != nil {
527528
if err := r.reconcileMachineHealthCheck(ctx, md.MachineHealthCheck, nil); err != nil {
528-
return errors.Wrapf(err, "failed to delete %s", tlog.KObj{Obj: md.MachineHealthCheck})
529+
return err
529530
}
530531
}
531532
log.Infof("Deleting %s", tlog.KObj{Obj: md.Object})
@@ -587,7 +588,7 @@ func (r *Reconciler) reconcileReferencedObject(ctx context.Context, in reconcile
587588
return errors.Wrapf(err, "failed to create a copy of %s with the managed field annotation", tlog.KObj{Obj: in.desired})
588589
}
589590
if err := r.Client.Create(ctx, desiredWithManagedFieldAnnotation); err != nil {
590-
return errors.Wrapf(err, "failed to create %s", tlog.KObj{Obj: desiredWithManagedFieldAnnotation})
591+
return createErrorWithoutObjectName(err, desiredWithManagedFieldAnnotation)
591592
}
592593
r.recorder.Eventf(in.cluster, corev1.EventTypeNormal, createEventReason, "Created %q", tlog.KObj{Obj: in.desired})
593594
return nil
@@ -664,7 +665,7 @@ func (r *Reconciler) reconcileReferencedTemplate(ctx context.Context, in reconci
664665
return errors.Wrapf(err, "failed to create a copy of %s with the managed field annotation", tlog.KObj{Obj: in.desired})
665666
}
666667
if err := r.Client.Create(ctx, desiredWithManagedFieldAnnotation); err != nil {
667-
return errors.Wrapf(err, "failed to create %s", tlog.KObj{Obj: desiredWithManagedFieldAnnotation})
668+
return createErrorWithoutObjectName(err, desiredWithManagedFieldAnnotation)
668669
}
669670
r.recorder.Eventf(in.cluster, corev1.EventTypeNormal, createEventReason, "Created %q", tlog.KObj{Obj: in.desired})
670671
return nil
@@ -716,7 +717,7 @@ func (r *Reconciler) reconcileReferencedTemplate(ctx context.Context, in reconci
716717
return errors.Wrapf(err, "failed to create a copy of %s with the managed field annotation", tlog.KObj{Obj: in.desired})
717718
}
718719
if err := r.Client.Create(ctx, desiredWithManagedFieldAnnotation); err != nil {
719-
return errors.Wrapf(err, "failed to create %s", tlog.KObj{Obj: desiredWithManagedFieldAnnotation})
720+
return createErrorWithoutObjectName(err, desiredWithManagedFieldAnnotation)
720721
}
721722
r.recorder.Eventf(in.cluster, corev1.EventTypeNormal, createEventReason, "Created %q as a replacement for %q (template rotation)", tlog.KObj{Obj: in.desired}, in.ref.Name)
722723

@@ -727,3 +728,29 @@ func (r *Reconciler) reconcileReferencedTemplate(ctx context.Context, in reconci
727728

728729
return nil
729730
}
731+
732+
// createErrorWithoutObjectName removes the name of the object from the error message. As each new Create call involves an
733+
// object with a unique generated name each error appears to be a different error. As the errors are being surfaced in a condition
734+
// on the Cluster, the name is removed here to prevent each creation error from triggering a new reconciliation.
735+
func createErrorWithoutObjectName(err error, obj client.Object) error {
736+
var statusError *apierrors.StatusError
737+
if errors.As(err, &statusError) {
738+
if statusError.Status().Details != nil {
739+
var causes []string
740+
for _, cause := range statusError.Status().Details.Causes {
741+
causes = append(causes, fmt.Sprintf("%s: %s: %s", cause.Type, cause.Field, cause.Message))
742+
}
743+
var msg string
744+
if len(causes) > 0 {
745+
msg = fmt.Sprintf("failed to create %s.%s: %s", statusError.Status().Details.Kind, statusError.Status().Details.Group, strings.Join(causes, " "))
746+
} else {
747+
msg = fmt.Sprintf("failed to create %s.%s", statusError.Status().Details.Kind, statusError.Status().Details.Group)
748+
}
749+
// Replace the statusError message with the constructed message.
750+
statusError.ErrStatus.Message = msg
751+
return statusError
752+
}
753+
}
754+
// If this isn't a StatusError return a more generic error with the object details.
755+
return errors.Wrapf(err, "failed to create %s", tlog.KObj{Obj: obj})
756+
}

internal/controllers/topology/cluster/reconcile_state_test.go

+49
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package cluster
1919
import (
2020
"context"
2121
"fmt"
22+
"net/http"
2223
"regexp"
2324
"testing"
2425
"time"
@@ -2081,3 +2082,51 @@ func TestReconciler_reconcileMachineHealthCheck(t *testing.T) {
20812082
})
20822083
}
20832084
}
2085+
2086+
func Test_createErrorWithoutObjectName(t *testing.T) {
2087+
originalError := &apierrors.StatusError{
2088+
ErrStatus: metav1.Status{
2089+
Status: metav1.StatusFailure,
2090+
Code: http.StatusUnprocessableEntity,
2091+
Reason: metav1.StatusReasonInvalid,
2092+
Message: "DockerMachineTemplate.infrastructure.cluster.x-k8s.io \"docker-template-one\" is invalid: spec.template.spec.preLoadImages: Invalid value: \"array\": spec.template.spec.preLoadImages in body must be of type string: \"array\"",
2093+
Details: &metav1.StatusDetails{
2094+
Group: "infrastructure.cluster.x-k8s.io",
2095+
Kind: "DockerMachineTemplate",
2096+
Name: "docker-template-one",
2097+
Causes: []metav1.StatusCause{
2098+
{
2099+
Type: "FieldValueInvalid",
2100+
Message: "Invalid value: \"array\": spec.template.spec.preLoadImages in body must be of type string: \"array\"",
2101+
Field: "spec.template.spec.preLoadImages",
2102+
},
2103+
},
2104+
},
2105+
}}
2106+
wantError := &apierrors.StatusError{
2107+
ErrStatus: metav1.Status{
2108+
Status: metav1.StatusFailure,
2109+
Code: http.StatusUnprocessableEntity,
2110+
Reason: metav1.StatusReasonInvalid,
2111+
// The only difference between the two objects should be in the Message section.
2112+
Message: "failed to create DockerMachineTemplate.infrastructure.cluster.x-k8s.io: FieldValueInvalid: spec.template.spec.preLoadImages: Invalid value: \"array\": spec.template.spec.preLoadImages in body must be of type string: \"array\"",
2113+
Details: &metav1.StatusDetails{
2114+
Group: "infrastructure.cluster.x-k8s.io",
2115+
Kind: "DockerMachineTemplate",
2116+
Name: "docker-template-one",
2117+
Causes: []metav1.StatusCause{
2118+
{
2119+
Type: "FieldValueInvalid",
2120+
Message: "Invalid value: \"array\": spec.template.spec.preLoadImages in body must be of type string: \"array\"",
2121+
Field: "spec.template.spec.preLoadImages",
2122+
},
2123+
},
2124+
},
2125+
},
2126+
}
2127+
t.Run("Transform a create error correctly", func(t *testing.T) {
2128+
g := NewWithT(t)
2129+
err := createErrorWithoutObjectName(originalError, nil)
2130+
g.Expect(err).To(Equal(wantError), cmp.Diff(err, wantError))
2131+
})
2132+
}

0 commit comments

Comments
 (0)