Skip to content

Commit

Permalink
internal: added helper for status update
Browse files Browse the repository at this point in the history
  • Loading branch information
giautm committed Jan 6, 2025
1 parent 85a2be2 commit 99a9286
Show file tree
Hide file tree
Showing 2 changed files with 138 additions and 0 deletions.
80 changes: 80 additions & 0 deletions internal/result/result.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// Copyright 2025 The Atlas Operator Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package result

import (
"errors"
"time"

ctrl "sigs.k8s.io/controller-runtime"
)

// Transient checks if the error is transient and returns a result
// that indicates whether the request should be retried.
func Transient(err error) (r ctrl.Result, _ error) {
if t := (*transientError)(nil); errors.As(err, &t) {
return Retry(t.after)
}
// Permanent errors are not returned as errors because they cause
// the controller to requeue indefinitely. Instead, they should be
// reported as a status condition.
return OK()
}

// OK returns a successful result
func OK() (ctrl.Result, error) {
return ctrl.Result{}, nil
}

// Failed returns a failed result
func Failed() (ctrl.Result, error) {
return Retry(0)
}

// Retry requeues the request after the specified number of seconds
func Retry(after int) (ctrl.Result, error) {
return ctrl.Result{
Requeue: true,
RequeueAfter: time.Second * time.Duration(after),
}, nil
}

// transientError is an error that should be retried.
type transientError struct {
err error
after int
}

func (t *transientError) Error() string { return t.err.Error() }
func (t *transientError) Unwrap() error { return t.err }

// TransientError wraps an error to indicate that it should be retried.
func TransientError(err error) error {
return TransientErrorAfter(err, 5)
}

// TransientErrorAfter wraps an error to indicate that it should be retried after
// the given duration.
func TransientErrorAfter(err error, after int) error {
if err == nil {
return nil
}
return &transientError{err: err, after: after}
}

func isTransient(err error) bool {
var t *transientError
return errors.As(err, &t)
}
58 changes: 58 additions & 0 deletions internal/status/status.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Copyright 2025 The Atlas Operator Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package status

import (
"context"

ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
)

type (
// OptionBuilder is an interface that can be implemented
// by any type that can provide a list of options
OptionBuilder[T any] interface {
GetOptions() []Option[T]
}
// Option is an interface that can be implemented by any type
// that can apply an option to a resource and return a result
Option[T any] interface {
ApplyOption(o T)
GetResult() (ctrl.Result, error)
}
)

// Update takes the options provided by the given option builder, applies them all and then updates the resource
func Update[T client.Object](ctx context.Context, sw client.StatusWriter, obj T, b OptionBuilder[T]) (r ctrl.Result, err error) {
opts := b.GetOptions()
for _, o := range opts {
o.ApplyOption(obj)
}
if err := sw.Update(ctx, obj); err != nil {
return ctrl.Result{}, err
}
for _, o := range opts {
if r, err = o.GetResult(); err != nil {
return r, err
}
}
for _, o := range opts {
if r, _ := o.GetResult(); r.Requeue || r.RequeueAfter > 0 {
return r, nil
}
}
return ctrl.Result{}, nil
}

0 comments on commit 99a9286

Please sign in to comment.