Add internal/apistatus package with typed terminal errors#325
Add internal/apistatus package with typed terminal errors#325felix-kaestner wants to merge 4 commits into
internal/apistatus package with typed terminal errors#325Conversation
internal/apistatus package with typed terminal errors
9d34c07 to
f7c97e3
Compare
f7c97e3 to
74b89da
Compare
| // if err != nil { | ||
| // return apistatus.WrapTerminalError(err) | ||
| // } | ||
| func WrapTerminalError(err error) error { |
There was a problem hiding this comment.
Don't we wrap grpc errors to TerminalError already? Does it make sense to combine this in one function?
There was a problem hiding this comment.
Yes, we do, but it doesn't make sense to combine this. grpc errors would be returned when we actually make a gNMI call. These apistatus errors are used for input validation, even before making any gNMI call. Hence they are also checked at different code paths.
| @@ -29,7 +29,10 @@ const ( | |||
| CodeUnsupportedField | |||
|
|
|||
| // CodeFailedPrecondition signals that a precondition on the device or | |||
There was a problem hiding this comment.
the idea just popped into my head, unsure if that make sense, but would it be helpful to make retry configurable? For most of the cases probably not, just wanted tho share my thoughts here.
There was a problem hiding this comment.
Nice idea. I think I would leave this up to future follow-ups in case we really need it. Currently, as this Error is used for the NX-OS implementation, we agreed that we are fine to keep the backup/retry behavior (making it non-terminal) so that it has the chance to eventually resolve itself.
74b89da to
6472af5
Compare
Introduces internal/apistatus, a leaf package that gives provider implementations a structured way to return non-retryable errors to controllers without coupling directly to reconcile.TerminalError. The package defines a Code enum (CodeInvalidArgument, CodeUnsupportedField, CodeFailedPrecondition) with String() and Valid() methods, a StatusError struct carrying a Code, an optional Message, and optional FieldViolations, and constructor functions for each code. StatusError implements Is() so that errors.Is can be used for type detection across error chains. WrapTerminalError wraps any error containing a *StatusError as a reconcile.TerminalError, leaving all other errors unchanged. conditions.FromError is extended to detect *StatusError before the existing gRPC status path, mapping the code to the condition Reason and the formatted message to the condition Message field. The stub internal/controllerutil package, which this supersedes, has been removed as no code imported it. Signed-off-by: Felix Kästner <felix.kaestner@sap.com>
Each controller's Reconcile method now passes provider errors through apistatus.WrapTerminalError before returning them to controller-runtime. This ensures that any *StatusError returned by a provider implementation — signalling an unsupported field, an invalid argument, or an unmet precondition — suppresses retry backoff and is treated as a terminal error by the reconciler. Transient errors and Kubernetes-level precondition failures are returned unchanged, preserving existing retry behaviour for those cases. Signed-off-by: Felix Kästner <felix.kaestner@sap.com>
Replace plain fmt.Errorf/errors.New calls in the NX-OS provider and name.go with typed apistatus errors so non-retryable failures surface as structured Kubernetes status conditions with a stable Reason field. Signed-off-by: Felix Kästner <felix.kaestner@sap.com>
WrapTerminalError now only promotes CodeInvalidArgument and CodeUnsupportedField to reconcile.TerminalError. CodeFailedPrecondition errors pass through unchanged so controller-runtime exponential backoff can requeue them — the precondition (e.g. a BGP process) may become true on a future attempt. Update docs and tests to reflect the new behaviour. Signed-off-by: Felix Kästner <felix.kaestner@sap.com>
6472af5 to
f87cad7
Compare
Merging this branch changes the coverage (1 decrease, 2 increase)
Coverage by fileChanged files (no unit tests)
Please note that the "Total", "Covered", and "Missed" counts above refer to code statements instead of lines of code. The value in brackets refers to the test coverage of that file in the old version of the code. Changed unit test files
|
Introduces internal/apistatus, a package that gives provider implementations a structured way to return non-retryable errors to controllers without coupling directly to reconcile.TerminalError.
The package defines a Code enum (CodeInvalidArgument, CodeUnsupportedField, CodeFailedPrecondition) with String() and Valid() methods, a StatusError struct carrying a Code, an optional Message, and optional FieldViolations, and constructor functions for each code. StatusError implements Is() so that errors.Is can be used for type detection across error chains. WrapTerminalError wraps any error containing a *StatusError as a reconcile.TerminalError, leaving all other errors unchanged.
conditions.FromError is extended to detect *StatusError before the existing gRPC status path, mapping the code to the condition Reason and the formatted message to the condition Message field.
The stub internal/controllerutil package, which this supersedes, has been removed as no code imported it.