Skip to content

Commit efeb3da

Browse files
committed
feat: return auth error
If controller encounter a auth error (token invalid), error stay silent to user
1 parent 4961b50 commit efeb3da

6 files changed

Lines changed: 43 additions & 18 deletions

File tree

internal/controller/linodecluster_controller.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ func (r *LinodeClusterReconciler) reconcile(
207207

208208
if err := addMachineToLB(ctx, clusterScope); err != nil {
209209
logger.Error(err, "Failed to add Linode machine to loadbalancer option")
210-
return retryIfTransient(err, logger)
210+
return retryIfTransient(err)
211211
}
212212

213213
return res, nil

internal/controller/linodemachine_controller.go

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -178,8 +178,13 @@ func (r *LinodeMachineReconciler) reconcile(ctx context.Context, logger logr.Log
178178
//nolint:dupl // Code duplication is simplicity in this case.
179179
defer func() {
180180
if err != nil {
181-
// Only set failure reason if the error is not retryable.
182-
if linodego.ErrHasStatus(err, http.StatusBadRequest) {
181+
// Set specific failure reason for authentication errors
182+
if util.IsAuthenticationError(err) {
183+
failureReason = util.CredentialError
184+
}
185+
186+
// Set failure status for terminal errors (400, 401, 403, 404)
187+
if util.IsTerminalError(err) {
183188
machineScope.LinodeMachine.Status.FailureReason = util.Pointer(failureReason)
184189
machineScope.LinodeMachine.Status.FailureMessage = util.Pointer(err.Error())
185190
machineScope.LinodeMachine.SetCondition(metav1.Condition{
@@ -535,7 +540,7 @@ func (r *LinodeMachineReconciler) reconcilePreflightMetadataSupportConfigure(ctx
535540
_, err := machineScope.LinodeClient.GetRegion(ctx, machineScope.LinodeMachine.Spec.Region)
536541
if err != nil {
537542
logger.Error(err, fmt.Sprintf("Failed to fetch region %s", machineScope.LinodeMachine.Spec.Region))
538-
return retryIfTransient(err, logger)
543+
return retryIfTransient(err)
539544
}
540545
imageName := reconciler.DefaultMachineControllerLinodeImage
541546
if machineScope.LinodeMachine.Spec.Image != "" {
@@ -544,7 +549,7 @@ func (r *LinodeMachineReconciler) reconcilePreflightMetadataSupportConfigure(ctx
544549
_, err = machineScope.LinodeClient.GetImage(ctx, imageName)
545550
if err != nil {
546551
logger.Error(err, fmt.Sprintf("Failed to fetch image %s", imageName))
547-
return retryIfTransient(err, logger)
552+
return retryIfTransient(err)
548553
}
549554
machineScope.LinodeMachine.SetCondition(metav1.Condition{
550555
Type: ConditionPreflightMetadataSupportConfigured,
@@ -559,7 +564,7 @@ func (r *LinodeMachineReconciler) reconcilePreflightCreate(ctx context.Context,
559564
createOpts, err := newCreateConfig(ctx, machineScope, r.GzipCompressionEnabled, logger)
560565
if err != nil {
561566
logger.Error(err, "Failed to create Linode machine InstanceCreateOptions")
562-
return retryIfTransient(err, logger)
567+
return retryIfTransient(err)
563568
}
564569

565570
linodeInstance, retryAfter, err := createInstance(ctx, logger, machineScope, createOpts)
@@ -585,7 +590,7 @@ func (r *LinodeMachineReconciler) reconcilePreflightCreate(ctx context.Context,
585590
Reason: util.CreateError,
586591
Message: err.Error(),
587592
})
588-
return retryIfTransient(err, logger)
593+
return retryIfTransient(err)
589594
}
590595

591596
machineScope.LinodeMachine.SetCondition(metav1.Condition{
@@ -643,11 +648,11 @@ func (r *LinodeMachineReconciler) reconcilePreflightConfigure(ctx context.Contex
643648
instanceConfig, err := getDefaultInstanceConfig(ctx, machineScope, instanceID)
644649
if err != nil {
645650
logger.Error(err, "Failed to get default instance configuration")
646-
return retryIfTransient(err, logger)
651+
return retryIfTransient(err)
647652
}
648653
if _, err := machineScope.LinodeClient.UpdateInstanceConfig(ctx, instanceID, instanceConfig.ID, configData); err != nil {
649654
logger.Error(err, "Failed to update default instance configuration", "configuration", configData)
650-
return retryIfTransient(err, logger)
655+
return retryIfTransient(err)
651656
}
652657
}
653658

@@ -729,7 +734,7 @@ func (r *LinodeMachineReconciler) reconcileUpdate(ctx context.Context, logger lo
729734

730735
var linodeInstance *linodego.Instance
731736
if linodeInstance, err = machineScope.LinodeClient.GetInstance(ctx, instanceID); err != nil {
732-
return retryIfTransient(err, logger)
737+
return retryIfTransient(err)
733738
}
734739
// update the status
735740
machineScope.LinodeMachine.Status.InstanceState = &linodeInstance.Status

internal/controller/linodemachine_controller_helpers.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,15 +68,16 @@ var (
6868
errNoPublicIPv6SLAACAddrs = errors.New("no public SLAAC address set")
6969
)
7070

71-
func retryIfTransient(err error, logger logr.Logger) (ctrl.Result, error) {
71+
func retryIfTransient(err error) (ctrl.Result, error) {
7272
if util.IsRetryableError(err) {
7373
if linodego.ErrHasStatus(err, http.StatusTooManyRequests) {
7474
return ctrl.Result{RequeueAfter: reconciler.DefaultLinodeTooManyRequestsErrorRetryDelay}, nil
7575
}
7676
return ctrl.Result{RequeueAfter: reconciler.DefaultMachineControllerRetryDelay}, nil
7777
}
78-
logger.Error(err, "unknown Linode API error")
79-
return ctrl.Result{RequeueAfter: reconciler.DefaultMachineControllerRetryDelay}, nil
78+
// Return the error for terminal errors (400, 401, 403, 404) so that
79+
// the reconciler can set appropriate conditions and events
80+
return ctrl.Result{}, err
8081
}
8182

8283
func fillCreateConfig(createConfig *linodego.InstanceCreateOptions, machineScope *scope.MachineScope) {

internal/controller/linodeobjectstoragebucket_controller.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ func (r *LinodeObjectStorageBucketReconciler) reconcile(ctx context.Context, bSc
140140
// Handle deleted buckets
141141
if !bScope.Bucket.DeletionTimestamp.IsZero() {
142142
if err := r.reconcileDelete(ctx, bScope); err != nil {
143-
return retryIfTransient(err, bScope.Logger)
143+
return retryIfTransient(err)
144144
}
145145
return res, nil
146146
}

util/errors.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,9 @@ var (
2929

3030
// List of failure reasons to use in the status fields of our resources
3131
var (
32-
CreateError = "CreateError"
33-
DeleteError = "DeleteError"
34-
UpdateError = "UpdateError"
35-
UnknownError = "UnknownError"
32+
CreateError = "CreateError"
33+
DeleteError = "DeleteError"
34+
UpdateError = "UpdateError"
35+
UnknownError = "UnknownError"
36+
CredentialError = "CredentialError"
3637
)

util/helpers.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,24 @@ func IsRetryableError(err error) bool {
6161
linodego.ErrorFromError) || errors.Is(err, http.ErrHandlerTimeout) || errors.Is(err, os.ErrDeadlineExceeded) || errors.Is(err, io.ErrUnexpectedEOF)
6262
}
6363

64+
// IsAuthenticationError determines if the error is an authentication or authorization error (401/403)
65+
// These errors are terminal and should not be retried without user intervention
66+
func IsAuthenticationError(err error) bool {
67+
return linodego.ErrHasStatus(err, http.StatusUnauthorized, http.StatusForbidden)
68+
}
69+
70+
// IsTerminalError determines if the error is terminal and should not be retried.
71+
// Terminal errors include bad requests (400), authentication errors (401/403), and not found (404)
72+
func IsTerminalError(err error) bool {
73+
return linodego.ErrHasStatus(
74+
err,
75+
http.StatusBadRequest,
76+
http.StatusUnauthorized,
77+
http.StatusForbidden,
78+
http.StatusNotFound,
79+
)
80+
}
81+
6482
// GetInstanceID determines the instance ID from the ProviderID
6583
func GetInstanceID(providerID *string) (int, error) {
6684
if providerID == nil {

0 commit comments

Comments
 (0)