Reputation: 1120
I'm trying to create a generic function that creates k8s resources (custom and built-in) using Operator SDK.
package common
import (
"context"
"reflect"
"time"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/log"
)
type Reconciler interface {
client.Reader
client.Writer
GetScheme() *runtime.Scheme
}
func EnsureResource[T client.Object, P client.Object](r Reconciler, ctx context.Context, res T, parent P) (ctrl.Result, error) {
log := log.FromContext(ctx)
existing := res
if err := r.Get(ctx, types.NamespacedName{Name: res.GetName(), Namespace: res.GetNamespace()}, existing); err != nil && errors.IsNotFound(err) {
ctrl.SetControllerReference(parent, res, r.GetScheme())
if err = r.Create(ctx, res); err != nil {
log.Error(err, "failed to create resource", "Name", res.GetName(), "Namespace", res.GetNamespace())
return ctrl.Result{}, err
}
return ctrl.Result{RequeueAfter: 1 * time.Second}, nil // created successfully, requeue
} else if err == nil && !reflect.DeepEqual(res.Spec, existing.Spec) {
// exists already but modified
r.Update(ctx, res)
} else {
log.Error(err, "couldn't fetch existing resource", "Name", res.GetName(), "Namespace", res.GetNamespace())
return ctrl.Result{}, err
}
// already exists, finish reconcile
return ctrl.Result{}, nil
}
The creation part works perfectly and can create any k8s resource. Now I am working on the part that detects updates to an existing resource. In the middle if
block, I need to check if the Spec
fields of res
and existing
are DeepEqual
, but I can't imagine a way of accessing them with generics.
client.Object
is of course in k8s package. Also, some resource definitions that will be used as T
and P
will be from k8s api, and some were Custom Resources created by me, so not sure if I can use an interface here.
Is there a reasonable way to achieve this?
Alternatively, is it even necessary to check for updates to an existing k8s resource and only propagate if necessary? For example, if I get a reconciliation event, but there is no difference between existing and new Specs, then will calling r.Update
trigger reconciliation on all child resources?
Upvotes: 1
Views: 216