refactor: provide a base reconciler to provide common functionnalities
- singleton - finalizer Signed-off-by: Luca Burgazzoli <lburgazzoli@gmail.com>
This commit is contained in:
parent
4fad550e78
commit
025596d9d3
|
@ -19,6 +19,8 @@ import (
|
|||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
var ErrUnmarshalOnNil = errors.New("UnmarshalJSON on nil pointer")
|
||||
|
@ -94,3 +96,9 @@ type ChartMeta struct {
|
|||
Name string `json:"name,omitempty"`
|
||||
Version string `json:"version,omitempty"`
|
||||
}
|
||||
|
||||
type Status struct {
|
||||
Phase string `json:"phase"`
|
||||
Conditions []metav1.Condition `json:"conditions,omitempty"`
|
||||
ObservedGeneration int64 `json:"observedGeneration,omitempty"`
|
||||
}
|
||||
|
|
|
@ -27,10 +27,8 @@ type DaprControlPlaneSpec struct {
|
|||
}
|
||||
|
||||
type DaprControlPlaneStatus struct {
|
||||
Phase string `json:"phase"`
|
||||
Conditions []metav1.Condition `json:"conditions,omitempty"`
|
||||
ObservedGeneration int64 `json:"observedGeneration,omitempty"`
|
||||
Chart *ChartMeta `json:"chart,omitempty"`
|
||||
Status `json:",inline"`
|
||||
Chart *ChartMeta `json:"chart,omitempty"`
|
||||
}
|
||||
|
||||
// +genclient
|
||||
|
@ -53,6 +51,10 @@ type DaprControlPlane struct {
|
|||
Status DaprControlPlaneStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
func (in *DaprControlPlane) GetStatus() *Status {
|
||||
return &in.Status.Status
|
||||
}
|
||||
|
||||
func (in *DaprControlPlane) GetConditions() conditions.Conditions {
|
||||
return in.Status.Conditions
|
||||
}
|
||||
|
|
|
@ -27,10 +27,8 @@ type DaprCruiseControlSpec struct {
|
|||
|
||||
// DaprCruiseControlStatus defines the observed state of DaprCruiseControl.
|
||||
type DaprCruiseControlStatus struct {
|
||||
Phase string `json:"phase"`
|
||||
Conditions []metav1.Condition `json:"conditions,omitempty"`
|
||||
ObservedGeneration int64 `json:"observedGeneration,omitempty"`
|
||||
Chart *ChartMeta `json:"chart,omitempty"`
|
||||
Status `json:",inline"`
|
||||
Chart *ChartMeta `json:"chart,omitempty"`
|
||||
}
|
||||
|
||||
// +genclient
|
||||
|
@ -53,6 +51,10 @@ type DaprCruiseControl struct {
|
|||
Status DaprCruiseControlStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
func (in *DaprCruiseControl) GetStatus() *Status {
|
||||
return &in.Status.Status
|
||||
}
|
||||
|
||||
func (in *DaprCruiseControl) GetConditions() conditions.Conditions {
|
||||
return in.Status.Conditions
|
||||
}
|
||||
|
|
|
@ -32,10 +32,8 @@ type DaprInstanceSpec struct {
|
|||
|
||||
// DaprInstanceStatus defines the observed state of DaprInstance.
|
||||
type DaprInstanceStatus struct {
|
||||
Phase string `json:"phase"`
|
||||
Conditions []metav1.Condition `json:"conditions,omitempty"`
|
||||
ObservedGeneration int64 `json:"observedGeneration,omitempty"`
|
||||
Chart *ChartMeta `json:"chart,omitempty"`
|
||||
Status `json:",inline"`
|
||||
Chart *ChartMeta `json:"chart,omitempty"`
|
||||
}
|
||||
|
||||
// +genclient
|
||||
|
@ -58,6 +56,10 @@ type DaprInstance struct {
|
|||
Status DaprInstanceStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
func (in *DaprInstance) GetStatus() *Status {
|
||||
return &in.Status.Status
|
||||
}
|
||||
|
||||
func (in *DaprInstance) GetConditions() conditions.Conditions {
|
||||
return in.Status.Conditions
|
||||
}
|
||||
|
|
|
@ -137,13 +137,7 @@ func (in *DaprControlPlaneSpec) DeepCopy() *DaprControlPlaneSpec {
|
|||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *DaprControlPlaneStatus) DeepCopyInto(out *DaprControlPlaneStatus) {
|
||||
*out = *in
|
||||
if in.Conditions != nil {
|
||||
in, out := &in.Conditions, &out.Conditions
|
||||
*out = make([]v1.Condition, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
in.Status.DeepCopyInto(&out.Status)
|
||||
if in.Chart != nil {
|
||||
in, out := &in.Chart, &out.Chart
|
||||
*out = new(ChartMeta)
|
||||
|
@ -238,13 +232,7 @@ func (in *DaprCruiseControlSpec) DeepCopy() *DaprCruiseControlSpec {
|
|||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *DaprCruiseControlStatus) DeepCopyInto(out *DaprCruiseControlStatus) {
|
||||
*out = *in
|
||||
if in.Conditions != nil {
|
||||
in, out := &in.Conditions, &out.Conditions
|
||||
*out = make([]v1.Condition, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
in.Status.DeepCopyInto(&out.Status)
|
||||
if in.Chart != nil {
|
||||
in, out := &in.Chart, &out.Chart
|
||||
*out = new(ChartMeta)
|
||||
|
@ -349,13 +337,7 @@ func (in *DaprInstanceSpec) DeepCopy() *DaprInstanceSpec {
|
|||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *DaprInstanceStatus) DeepCopyInto(out *DaprInstanceStatus) {
|
||||
*out = *in
|
||||
if in.Conditions != nil {
|
||||
in, out := &in.Conditions, &out.Conditions
|
||||
*out = make([]v1.Condition, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
in.Status.DeepCopyInto(&out.Status)
|
||||
if in.Chart != nil {
|
||||
in, out := &in.Chart, &out.Chart
|
||||
*out = new(ChartMeta)
|
||||
|
@ -411,3 +393,25 @@ func (in RawMessage) DeepCopy() RawMessage {
|
|||
in.DeepCopyInto(out)
|
||||
return *out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Status) DeepCopyInto(out *Status) {
|
||||
*out = *in
|
||||
if in.Conditions != nil {
|
||||
in, out := &in.Conditions, &out.Conditions
|
||||
*out = make([]v1.Condition, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Status.
|
||||
func (in *Status) DeepCopy() *Status {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Status)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
|
|
@ -8,5 +8,5 @@ apiVersion: kustomize.config.k8s.io/v1beta1
|
|||
kind: Kustomization
|
||||
images:
|
||||
- name: controller
|
||||
newName: ghcr.io/dapr-sandbox/dapr-kubernetes-operator
|
||||
newName: ghcr.io/dapr/kubernetes-operator
|
||||
newTag: 0.0.8
|
||||
|
|
|
@ -5,7 +5,7 @@ metadata:
|
|||
namespace: olm
|
||||
spec:
|
||||
sourceType: grpc
|
||||
image: ghcr.io/dapr-sandbox/dapr-kubernetes-operator-catalog:latest
|
||||
image: ghcr.io/dapr/kubernetes-operator-catalog:latest
|
||||
displayName: dapr.io catalog
|
||||
grpcPodConfig:
|
||||
securityContextConfig: restricted
|
||||
|
|
|
@ -20,23 +20,24 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
|
||||
"github.com/dapr/kubernetes-operator/pkg/openshift"
|
||||
|
||||
"github.com/dapr/kubernetes-operator/pkg/helm"
|
||||
|
||||
"k8s.io/client-go/tools/record"
|
||||
|
||||
"helm.sh/helm/v3/pkg/chart"
|
||||
"helm.sh/helm/v3/pkg/chart/loader"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
||||
"sigs.k8s.io/controller-runtime/pkg/builder"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
"sigs.k8s.io/controller-runtime/pkg/predicate"
|
||||
|
||||
daprApi "github.com/dapr/kubernetes-operator/api/operator/v1alpha1"
|
||||
|
||||
"github.com/dapr/kubernetes-operator/pkg/controller"
|
||||
"github.com/dapr/kubernetes-operator/pkg/controller/client"
|
||||
"github.com/dapr/kubernetes-operator/pkg/controller/reconciler"
|
||||
"github.com/dapr/kubernetes-operator/pkg/helm"
|
||||
"github.com/dapr/kubernetes-operator/pkg/openshift"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
|
||||
ctrlRt "sigs.k8s.io/controller-runtime"
|
||||
|
@ -129,9 +130,19 @@ func (r *Reconciler) init(ctx context.Context) error {
|
|||
c = b
|
||||
}
|
||||
|
||||
objRec := reconcile.AsReconciler[*daprApi.DaprControlPlane](r.manager.GetClient(), r)
|
||||
// by default, the controller expect the DaprControlPlane resource to be created
|
||||
// in the same namespace where it runs, if not fallback to the default namespace
|
||||
rec := reconciler.BaseReconciler[*daprApi.DaprControlPlane]{
|
||||
Delegate: r,
|
||||
Client: r.client,
|
||||
Log: log.FromContext(ctx),
|
||||
Name: DaprControlPlaneResourceName,
|
||||
Namespace: controller.OperatorNamespace(),
|
||||
FinalizerName: DaprControlPlaneFinalizerName,
|
||||
FinalizerAction: r.Cleanup,
|
||||
}
|
||||
|
||||
ct, err := c.Build(objRec)
|
||||
ct, err := c.Build(&rec)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failure building the application controller for DaprControlPlane resource: %w", err)
|
||||
}
|
||||
|
|
|
@ -20,13 +20,8 @@ import (
|
|||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
|
||||
"github.com/dapr/kubernetes-operator/pkg/controller/reconciler"
|
||||
|
||||
"github.com/dapr/kubernetes-operator/pkg/controller"
|
||||
|
||||
"github.com/dapr/kubernetes-operator/pkg/conditions"
|
||||
|
||||
k8serrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
|
@ -39,10 +34,8 @@ import (
|
|||
daprApi "github.com/dapr/kubernetes-operator/api/operator/v1alpha1"
|
||||
)
|
||||
|
||||
func (r *Reconciler) Reconcile(ctx context.Context, res *daprApi.DaprControlPlane) (ctrl.Result, error) {
|
||||
l := log.FromContext(ctx)
|
||||
|
||||
rr := ReconciliationRequest{
|
||||
func (r *Reconciler) reconciliationRequest(res *daprApi.DaprControlPlane) ReconciliationRequest {
|
||||
return ReconciliationRequest{
|
||||
Client: r.Client(),
|
||||
NamespacedName: types.NamespacedName{
|
||||
Name: res.Name,
|
||||
|
@ -52,62 +45,14 @@ func (r *Reconciler) Reconcile(ctx context.Context, res *daprApi.DaprControlPlan
|
|||
Reconciler: r,
|
||||
Resource: res,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Reconciler) Reconcile(ctx context.Context, res *daprApi.DaprControlPlane) (ctrl.Result, error) {
|
||||
rr := r.reconciliationRequest(res)
|
||||
|
||||
l := log.FromContext(ctx)
|
||||
l.Info("Reconciling", "resource", rr.NamespacedName.String())
|
||||
|
||||
// by default, the controller expect the DaprControlPlane resource to be created
|
||||
// in the same namespace where it runs, if not fallback to the default namespace
|
||||
// dapr-system
|
||||
ns := os.Getenv(controller.NamespaceEnv)
|
||||
if ns == "" {
|
||||
ns = controller.NamespaceDefault
|
||||
}
|
||||
|
||||
if res.Name != DaprControlPlaneResourceName || res.Namespace != ns {
|
||||
rr.Resource.Status.Phase = conditions.TypeError
|
||||
|
||||
meta.SetStatusCondition(&rr.Resource.Status.Conditions, metav1.Condition{
|
||||
Type: conditions.TypeReconciled,
|
||||
Status: metav1.ConditionFalse,
|
||||
Reason: conditions.ReasonUnsupportedConfiguration,
|
||||
Message: fmt.Sprintf(
|
||||
"Unsupported resource, the operator handles a single DaprControlPlane resource named %s in namespace %s",
|
||||
DaprControlPlaneResourceName,
|
||||
ns),
|
||||
})
|
||||
|
||||
err := r.Client().Status().Update(ctx, rr.Resource)
|
||||
|
||||
if err != nil && k8serrors.IsConflict(err) {
|
||||
l.Info(err.Error())
|
||||
return ctrl.Result{Requeue: true}, nil
|
||||
}
|
||||
|
||||
return ctrl.Result{}, fmt.Errorf("error updating DaprControlPlane resource: %w", err)
|
||||
}
|
||||
|
||||
//nolint:wrapcheck
|
||||
if rr.Resource.ObjectMeta.DeletionTimestamp.IsZero() {
|
||||
err := reconciler.AddFinalizer(ctx, r.Client(), rr.Resource, DaprControlPlaneFinalizerName)
|
||||
if err != nil {
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
} else {
|
||||
// Cleanup leftovers if needed
|
||||
for i := len(r.actions) - 1; i >= 0; i-- {
|
||||
if err := r.actions[i].Cleanup(ctx, &rr); err != nil {
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
}
|
||||
|
||||
err := reconciler.RemoveFinalizer(ctx, r.Client(), rr.Resource, DaprControlPlaneFinalizerName)
|
||||
if err != nil {
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
//
|
||||
// Reconcile
|
||||
//
|
||||
|
@ -159,3 +104,19 @@ func (r *Reconciler) Reconcile(ctx context.Context, res *daprApi.DaprControlPlan
|
|||
|
||||
return ctrl.Result{}, errors.Join(errs...)
|
||||
}
|
||||
|
||||
func (r *Reconciler) Cleanup(ctx context.Context, res *daprApi.DaprControlPlane) error {
|
||||
rr := r.reconciliationRequest(res)
|
||||
|
||||
l := log.FromContext(ctx)
|
||||
l.Info("Cleanup", "resource", rr.NamespacedName.String())
|
||||
|
||||
// Cleanup leftovers if needed
|
||||
for i := len(r.actions) - 1; i >= 0; i-- {
|
||||
if err := r.actions[i].Cleanup(ctx, &rr); err != nil {
|
||||
return fmt.Errorf("failure running cleanup action: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -20,15 +20,11 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/dapr/kubernetes-operator/pkg/openshift"
|
||||
|
||||
"github.com/dapr/kubernetes-operator/pkg/helm"
|
||||
|
||||
"k8s.io/client-go/tools/record"
|
||||
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
|
||||
"sigs.k8s.io/controller-runtime/pkg/handler"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
"sigs.k8s.io/controller-runtime/pkg/source"
|
||||
|
||||
"helm.sh/helm/v3/pkg/chart"
|
||||
|
@ -38,8 +34,12 @@ import (
|
|||
"sigs.k8s.io/controller-runtime/pkg/predicate"
|
||||
|
||||
daprApi "github.com/dapr/kubernetes-operator/api/operator/v1alpha1"
|
||||
|
||||
"github.com/dapr/kubernetes-operator/pkg/controller"
|
||||
"github.com/dapr/kubernetes-operator/pkg/controller/client"
|
||||
"github.com/dapr/kubernetes-operator/pkg/controller/reconciler"
|
||||
"github.com/dapr/kubernetes-operator/pkg/helm"
|
||||
"github.com/dapr/kubernetes-operator/pkg/openshift"
|
||||
"github.com/go-logr/logr"
|
||||
|
||||
ctrlRt "sigs.k8s.io/controller-runtime"
|
||||
|
@ -159,9 +159,19 @@ func (r *Reconciler) init(ctx context.Context) error {
|
|||
c = b
|
||||
}
|
||||
|
||||
objRec := reconcile.AsReconciler[*daprApi.DaprInstance](r.manager.GetClient(), r)
|
||||
// by default, the controller expect the DaprControlPlane resource to be created
|
||||
// in the same namespace where it runs, if not fallback to the default namespace
|
||||
rec := reconciler.BaseReconciler[*daprApi.DaprInstance]{
|
||||
Delegate: r,
|
||||
Client: r.client,
|
||||
Log: log.FromContext(ctx),
|
||||
Name: DaprInstanceResourceName,
|
||||
Namespace: controller.OperatorNamespace(),
|
||||
FinalizerName: DaprInstanceFinalizerName,
|
||||
FinalizerAction: r.Cleanup,
|
||||
}
|
||||
|
||||
ct, err := c.Build(objRec)
|
||||
ct, err := c.Build(&rec)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failure building the application controller for DaprInstance resource: %w", err)
|
||||
}
|
||||
|
|
|
@ -20,13 +20,8 @@ import (
|
|||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
|
||||
"github.com/dapr/kubernetes-operator/pkg/controller/reconciler"
|
||||
|
||||
"github.com/dapr/kubernetes-operator/pkg/controller"
|
||||
|
||||
"github.com/dapr/kubernetes-operator/pkg/conditions"
|
||||
|
||||
k8serrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
|
@ -39,10 +34,8 @@ import (
|
|||
daprApi "github.com/dapr/kubernetes-operator/api/operator/v1alpha1"
|
||||
)
|
||||
|
||||
func (r *Reconciler) Reconcile(ctx context.Context, res *daprApi.DaprInstance) (ctrl.Result, error) {
|
||||
l := log.FromContext(ctx)
|
||||
|
||||
rr := ReconciliationRequest{
|
||||
func (r *Reconciler) reconciliationRequest(res *daprApi.DaprInstance) ReconciliationRequest {
|
||||
return ReconciliationRequest{
|
||||
Client: r.Client(),
|
||||
NamespacedName: types.NamespacedName{
|
||||
Name: res.Name,
|
||||
|
@ -59,62 +52,14 @@ func (r *Reconciler) Reconcile(ctx context.Context, res *daprApi.DaprInstance) (
|
|||
"dapr_dashboard": map[string]interface{}{"runAsNonRoot": "true"},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Reconciler) Reconcile(ctx context.Context, res *daprApi.DaprInstance) (ctrl.Result, error) {
|
||||
rr := r.reconciliationRequest(res)
|
||||
|
||||
l := log.FromContext(ctx)
|
||||
l.Info("Reconciling", "resource", rr.NamespacedName.String())
|
||||
|
||||
// by default, the controller expect the DaprInstance resource to be created
|
||||
// in the same namespace where it runs, if not fallback to the default namespace
|
||||
// dapr-system
|
||||
ns := os.Getenv(controller.NamespaceEnv)
|
||||
if ns == "" {
|
||||
ns = controller.NamespaceDefault
|
||||
}
|
||||
|
||||
if res.Name != DaprInstanceResourceName || res.Namespace != ns {
|
||||
rr.Resource.Status.Phase = conditions.TypeError
|
||||
|
||||
meta.SetStatusCondition(&rr.Resource.Status.Conditions, metav1.Condition{
|
||||
Type: conditions.TypeReconciled,
|
||||
Status: metav1.ConditionFalse,
|
||||
Reason: conditions.ReasonUnsupportedConfiguration,
|
||||
Message: fmt.Sprintf(
|
||||
"Unsupported resource, the operator handles a single DaprInstance resource named %s in namespace %s",
|
||||
DaprInstanceResourceName,
|
||||
ns),
|
||||
})
|
||||
|
||||
err := r.Client().Status().Update(ctx, rr.Resource)
|
||||
|
||||
if err != nil && k8serrors.IsConflict(err) {
|
||||
l.Info(err.Error())
|
||||
return ctrl.Result{Requeue: true}, nil
|
||||
}
|
||||
|
||||
return ctrl.Result{}, fmt.Errorf("error updating DaprInstance resource: %w", err)
|
||||
}
|
||||
|
||||
//nolint:wrapcheck
|
||||
if rr.Resource.ObjectMeta.DeletionTimestamp.IsZero() {
|
||||
err := reconciler.AddFinalizer(ctx, r.Client(), rr.Resource, DaprInstanceFinalizerName)
|
||||
if err != nil {
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
} else {
|
||||
// Cleanup leftovers if needed
|
||||
for i := len(r.actions) - 1; i >= 0; i-- {
|
||||
if err := r.actions[i].Cleanup(ctx, &rr); err != nil {
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
}
|
||||
|
||||
err := reconciler.RemoveFinalizer(ctx, r.Client(), rr.Resource, DaprInstanceFinalizerName)
|
||||
if err != nil {
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
//
|
||||
// Reconcile
|
||||
//
|
||||
|
@ -167,3 +112,19 @@ func (r *Reconciler) Reconcile(ctx context.Context, res *daprApi.DaprInstance) (
|
|||
|
||||
return ctrl.Result{}, errors.Join(errs...)
|
||||
}
|
||||
|
||||
func (r *Reconciler) Cleanup(ctx context.Context, res *daprApi.DaprInstance) error {
|
||||
rr := r.reconciliationRequest(res)
|
||||
|
||||
l := log.FromContext(ctx)
|
||||
l.Info("Cleanup", "resource", rr.NamespacedName.String())
|
||||
|
||||
// Cleanup leftovers if needed
|
||||
for i := len(r.actions) - 1; i >= 0; i-- {
|
||||
if err := r.actions[i].Cleanup(ctx, &rr); err != nil {
|
||||
return fmt.Errorf("failure running cleanup action: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -24,10 +24,8 @@ import (
|
|||
// DaprControlPlaneStatusApplyConfiguration represents an declarative configuration of the DaprControlPlaneStatus type for use
|
||||
// with apply.
|
||||
type DaprControlPlaneStatusApplyConfiguration struct {
|
||||
Phase *string `json:"phase,omitempty"`
|
||||
Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"`
|
||||
ObservedGeneration *int64 `json:"observedGeneration,omitempty"`
|
||||
Chart *ChartMetaApplyConfiguration `json:"chart,omitempty"`
|
||||
StatusApplyConfiguration `json:",inline"`
|
||||
Chart *ChartMetaApplyConfiguration `json:"chart,omitempty"`
|
||||
}
|
||||
|
||||
// DaprControlPlaneStatusApplyConfiguration constructs an declarative configuration of the DaprControlPlaneStatus type for use with
|
||||
|
|
|
@ -24,10 +24,8 @@ import (
|
|||
// DaprCruiseControlStatusApplyConfiguration represents an declarative configuration of the DaprCruiseControlStatus type for use
|
||||
// with apply.
|
||||
type DaprCruiseControlStatusApplyConfiguration struct {
|
||||
Phase *string `json:"phase,omitempty"`
|
||||
Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"`
|
||||
ObservedGeneration *int64 `json:"observedGeneration,omitempty"`
|
||||
Chart *ChartMetaApplyConfiguration `json:"chart,omitempty"`
|
||||
StatusApplyConfiguration `json:",inline"`
|
||||
Chart *ChartMetaApplyConfiguration `json:"chart,omitempty"`
|
||||
}
|
||||
|
||||
// DaprCruiseControlStatusApplyConfiguration constructs an declarative configuration of the DaprCruiseControlStatus type for use with
|
||||
|
|
|
@ -24,10 +24,8 @@ import (
|
|||
// DaprInstanceStatusApplyConfiguration represents an declarative configuration of the DaprInstanceStatus type for use
|
||||
// with apply.
|
||||
type DaprInstanceStatusApplyConfiguration struct {
|
||||
Phase *string `json:"phase,omitempty"`
|
||||
Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"`
|
||||
ObservedGeneration *int64 `json:"observedGeneration,omitempty"`
|
||||
Chart *ChartMetaApplyConfiguration `json:"chart,omitempty"`
|
||||
StatusApplyConfiguration `json:",inline"`
|
||||
Chart *ChartMetaApplyConfiguration `json:"chart,omitempty"`
|
||||
}
|
||||
|
||||
// DaprInstanceStatusApplyConfiguration constructs an declarative configuration of the DaprInstanceStatus type for use with
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
Copyright 2023.
|
||||
|
||||
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.
|
||||
*/
|
||||
// Code generated by applyconfiguration-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
v1 "k8s.io/client-go/applyconfigurations/meta/v1"
|
||||
)
|
||||
|
||||
// StatusApplyConfiguration represents an declarative configuration of the Status type for use
|
||||
// with apply.
|
||||
type StatusApplyConfiguration struct {
|
||||
Phase *string `json:"phase,omitempty"`
|
||||
Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"`
|
||||
ObservedGeneration *int64 `json:"observedGeneration,omitempty"`
|
||||
}
|
||||
|
||||
// StatusApplyConfiguration constructs an declarative configuration of the Status type for use with
|
||||
// apply.
|
||||
func Status() *StatusApplyConfiguration {
|
||||
return &StatusApplyConfiguration{}
|
||||
}
|
||||
|
||||
// WithPhase sets the Phase field in the declarative configuration to the given value
|
||||
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
|
||||
// If called multiple times, the Phase field is set to the value of the last call.
|
||||
func (b *StatusApplyConfiguration) WithPhase(value string) *StatusApplyConfiguration {
|
||||
b.Phase = &value
|
||||
return b
|
||||
}
|
||||
|
||||
// WithConditions adds the given value to the Conditions field in the declarative configuration
|
||||
// and returns the receiver, so that objects can be build by chaining "With" function invocations.
|
||||
// If called multiple times, values provided by each call will be appended to the Conditions field.
|
||||
func (b *StatusApplyConfiguration) WithConditions(values ...*v1.ConditionApplyConfiguration) *StatusApplyConfiguration {
|
||||
for i := range values {
|
||||
if values[i] == nil {
|
||||
panic("nil value passed to WithConditions")
|
||||
}
|
||||
b.Conditions = append(b.Conditions, *values[i])
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// WithObservedGeneration sets the ObservedGeneration field in the declarative configuration to the given value
|
||||
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
|
||||
// If called multiple times, the ObservedGeneration field is set to the value of the last call.
|
||||
func (b *StatusApplyConfiguration) WithObservedGeneration(value int64) *StatusApplyConfiguration {
|
||||
b.ObservedGeneration = &value
|
||||
return b
|
||||
}
|
|
@ -50,6 +50,8 @@ func ForKind(kind schema.GroupVersionKind) interface{} {
|
|||
return &operatorv1alpha1.DaprInstanceStatusApplyConfiguration{}
|
||||
case v1alpha1.SchemeGroupVersion.WithKind("JSON"):
|
||||
return &operatorv1alpha1.JSONApplyConfiguration{}
|
||||
case v1alpha1.SchemeGroupVersion.WithKind("Status"):
|
||||
return &operatorv1alpha1.StatusApplyConfiguration{}
|
||||
|
||||
}
|
||||
return nil
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"fmt"
|
||||
"net/http"
|
||||
"net/http/pprof"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
|
||||
|
@ -105,3 +106,14 @@ func Start(options Options, setup func(manager.Manager, Options) error) error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
func OperatorNamespace() string {
|
||||
// by default, the controller expect singleton resources to be created in the same
|
||||
// namespace where it runs, if not fallback to the default namespace
|
||||
ns := os.Getenv(NamespaceEnv)
|
||||
if ns == "" {
|
||||
ns = NamespaceDefault
|
||||
}
|
||||
|
||||
return ns
|
||||
}
|
||||
|
|
|
@ -3,12 +3,23 @@ package reconciler
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/dapr/kubernetes-operator/pkg/conditions"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
|
||||
"github.com/dapr/kubernetes-operator/pkg/controller/client"
|
||||
k8serrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/builder"
|
||||
ctrlClient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
ctrlutil "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||
|
||||
"github.com/dapr/kubernetes-operator/pkg/controller"
|
||||
"github.com/dapr/kubernetes-operator/pkg/controller/client"
|
||||
)
|
||||
|
||||
type Reconciler interface {
|
||||
|
@ -54,3 +65,73 @@ func RemoveFinalizer(ctx context.Context, client ctrlClient.Client, o ctrlClient
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
type BaseReconciler[T controller.ResourceObject] struct {
|
||||
Log logr.Logger
|
||||
Name string
|
||||
Namespace string
|
||||
FinalizerName string
|
||||
FinalizerAction func(ctx context.Context, res T) error
|
||||
Delegate reconcile.ObjectReconciler[T]
|
||||
Client ctrlClient.Client
|
||||
}
|
||||
|
||||
//nolint:forcetypeassert,wrapcheck,nestif
|
||||
func (s *BaseReconciler[T]) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
|
||||
res := reflect.New(reflect.TypeOf(*new(T)).Elem()).Interface().(T)
|
||||
if err := s.Client.Get(ctx, req.NamespacedName, res); err != nil {
|
||||
return ctrl.Result{}, ctrlClient.IgnoreNotFound(err)
|
||||
}
|
||||
|
||||
if res.GetName() != s.Name || res.GetNamespace() != s.Namespace {
|
||||
res.GetStatus().Phase = conditions.TypeError
|
||||
|
||||
meta.SetStatusCondition(&res.GetStatus().Conditions, metav1.Condition{
|
||||
Type: conditions.TypeReconciled,
|
||||
Status: metav1.ConditionFalse,
|
||||
Reason: conditions.ReasonUnsupportedConfiguration,
|
||||
Message: fmt.Sprintf(
|
||||
"Unsupported resource, the operator handles a single %s resource named %s in namespace %s",
|
||||
res.GetObjectKind().GroupVersionKind().String(),
|
||||
s.Name,
|
||||
s.Namespace),
|
||||
})
|
||||
|
||||
err := s.Client.Status().Update(ctx, res)
|
||||
|
||||
if err != nil && k8serrors.IsConflict(err) {
|
||||
s.Log.Info(err.Error())
|
||||
return ctrl.Result{Requeue: true}, nil
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return ctrl.Result{}, fmt.Errorf("error updating %s resource: %w", res.GetObjectKind().GroupVersionKind().String(), err)
|
||||
}
|
||||
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
//nolint:wrapcheck
|
||||
if res.GetDeletionTimestamp().IsZero() {
|
||||
err := AddFinalizer(ctx, s.Client, res, s.FinalizerName)
|
||||
if err != nil {
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
} else {
|
||||
if s.FinalizerAction != nil {
|
||||
err := s.FinalizerAction(ctx, res)
|
||||
if err != nil {
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
}
|
||||
|
||||
err := RemoveFinalizer(ctx, s.Client, res, s.FinalizerName)
|
||||
if err != nil {
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
return s.Delegate.Reconcile(ctx, res)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package controller
|
||||
|
||||
import (
|
||||
daptCtrlApi "github.com/dapr/kubernetes-operator/api/operator/v1alpha1"
|
||||
rtcache "sigs.k8s.io/controller-runtime/pkg/cache"
|
||||
rtclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
@ -26,3 +27,12 @@ type Options struct {
|
|||
ReleaseLeaderElectionOnCancel bool
|
||||
WatchSelectors map[rtclient.Object]rtcache.ByObject
|
||||
}
|
||||
|
||||
type WithStatus interface {
|
||||
GetStatus() *daptCtrlApi.Status
|
||||
}
|
||||
|
||||
type ResourceObject interface {
|
||||
rtclient.Object
|
||||
WithStatus
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue