Skip to content

Commit

Permalink
feat: Trigger instance updates when Perses CR changes
Browse files Browse the repository at this point in the history
Signed-off-by: Douglass Kirkley <doug.kirkley@gmail.com>
  • Loading branch information
dougkirkley committed Feb 11, 2025
1 parent 5c86542 commit 9c039f2
Show file tree
Hide file tree
Showing 4 changed files with 145 additions and 62 deletions.
54 changes: 37 additions & 17 deletions controllers/perses/configmap_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,49 +19,55 @@ package perses
import (
"context"
"fmt"
"time"

"github.com/perses/perses-operator/api/v1alpha1"
"github.com/perses/perses-operator/internal/perses/common"
"github.com/perses/perses-operator/internal/subreconciler"
logger "github.com/sirupsen/logrus"
"gopkg.in/yaml.v2"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/equality"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"

"github.com/perses/perses-operator/api/v1alpha1"
"github.com/perses/perses-operator/internal/perses/common"
"github.com/perses/perses-operator/internal/subreconciler"
)

var cmlog = logger.WithField("module", "configmap_controller")

func (r *PersesReconciler) reconcileConfigMap(ctx context.Context, req ctrl.Request) (*ctrl.Result, error) {
perses := &v1alpha1.Perses{}

if r, err := r.getLatestPerses(ctx, req, perses); subreconciler.ShouldHaltOrRequeue(r, err) {
return r, err
if result, err := r.getLatestPerses(ctx, req, perses); subreconciler.ShouldHaltOrRequeue(result, err) {
return result, err
}

configName := common.GetConfigName(perses.Name)

found := &corev1.ConfigMap{}
err := r.Get(ctx, types.NamespacedName{Name: configName, Namespace: perses.Namespace}, found)
if err != nil && apierrors.IsNotFound(err) {
cm, err := createPersesConfigMap(r, perses)
if err != nil {
cmlog.WithError(err).Error("Failed to define new ConfigMap resource for perses")
if err := r.Get(ctx, types.NamespacedName{Name: configName, Namespace: perses.Namespace}, found); err != nil {
if !apierrors.IsNotFound(err) {
cmlog.WithError(err).Error("Failed to get ConfigMap")
return subreconciler.RequeueWithError(err)
}

cm, err2 := r.createPersesConfigMap(perses)
if err2 != nil {
cmlog.WithError(err2).Error("Failed to define new ConfigMap resource for perses")

meta.SetStatusCondition(&perses.Status.Conditions, metav1.Condition{Type: common.TypeAvailablePerses,
Status: metav1.ConditionFalse, Reason: "Reconciling",
Message: fmt.Sprintf("Failed to create ConfigMap for the custom resource (%s): (%s)", perses.Name, err)})
Message: fmt.Sprintf("Failed to create ConfigMap for the custom resource (%s): (%s)", perses.Name, err2)})

if err := r.Status().Update(ctx, perses); err != nil {
if err = r.Status().Update(ctx, perses); err != nil {
cmlog.WithError(err).Error("Failed to update perses status")
return subreconciler.RequeueWithError(err)
}

return subreconciler.RequeueWithError(err)
return subreconciler.RequeueWithError(err2)
}

cmlog.Infof("Creating a new ConfigMap: ConfigMap.Namespace %s ConfigMap.Name %s", cm.Namespace, cm.Name)
Expand All @@ -70,18 +76,32 @@ func (r *PersesReconciler) reconcileConfigMap(ctx context.Context, req ctrl.Requ
return subreconciler.RequeueWithError(err)
}

return subreconciler.RequeueWithDelay(time.Minute)
return subreconciler.ContinueReconciling()
}

cm, err := r.createPersesConfigMap(perses)
if err != nil {
cmlog.WithError(err).Error("Failed to get ConfigMap")
cmlog.WithError(err).Error("Failed to define new ConfigMap resource for perses")
return subreconciler.RequeueWithError(err)
}

// call update with dry run to fill out fields that are also returned via the k8s api
if err := r.Update(ctx, cm, client.DryRunAll); err != nil {
cmlog.Error(err, "Failed to update ConfigMap with dry run")
return subreconciler.RequeueWithError(err)
}

if !equality.Semantic.DeepEqual(found, cm) {
if err := r.Update(ctx, cm); err != nil {
cmlog.Error(err, "Failed to update ConfigMap")
return subreconciler.RequeueWithError(err)
}
}

return subreconciler.ContinueReconciling()
}

func createPersesConfigMap(r *PersesReconciler, perses *v1alpha1.Perses) (*corev1.ConfigMap, error) {
func (r *PersesReconciler) createPersesConfigMap(perses *v1alpha1.Perses) (*corev1.ConfigMap, error) {
configName := common.GetConfigName(perses.Name)
ls, err := common.LabelsForPerses(r.Config.PersesImage, configName, perses.Name, perses.Spec.Metadata)

Expand Down
46 changes: 33 additions & 13 deletions controllers/perses/deployment_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,30 +19,32 @@ package perses
import (
"context"
"fmt"
"time"

"github.com/perses/perses-operator/api/v1alpha1"
"github.com/perses/perses-operator/internal/perses/common"
"github.com/perses/perses-operator/internal/subreconciler"
logger "github.com/sirupsen/logrus"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/equality"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/utils/ptr"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"

"github.com/perses/perses-operator/api/v1alpha1"
"github.com/perses/perses-operator/internal/perses/common"
"github.com/perses/perses-operator/internal/subreconciler"
)

var dlog = logger.WithField("module", "deployment_controller")

func (r *PersesReconciler) reconcileDeployment(ctx context.Context, req ctrl.Request) (*ctrl.Result, error) {
perses := &v1alpha1.Perses{}

if r, err := r.getLatestPerses(ctx, req, perses); subreconciler.ShouldHaltOrRequeue(r, err) {
return r, err
if result, err := r.getLatestPerses(ctx, req, perses); subreconciler.ShouldHaltOrRequeue(result, err) {
return result, err
}

if perses.Spec.Config.Database.SQL == nil {
Expand All @@ -62,11 +64,14 @@ func (r *PersesReconciler) reconcileDeployment(ctx context.Context, req ctrl.Req
}

found := &appsv1.Deployment{}
err := r.Get(ctx, types.NamespacedName{Name: perses.Name, Namespace: perses.Namespace}, found)
if err != nil && apierrors.IsNotFound(err) {
if err := r.Get(ctx, types.NamespacedName{Name: perses.Name, Namespace: perses.Namespace}, found); err != nil {
if !apierrors.IsNotFound(err) {
dlog.WithError(err).Error("Failed to get Deployment")
return subreconciler.RequeueWithError(err)
}

dep, err := r.createPersesDeployment(perses)
if err != nil {
dep, err2 := r.createPersesDeployment(perses)
if err2 != nil {
dlog.WithError(err).Error("Failed to define new Deployment resource for perses")

meta.SetStatusCondition(&perses.Status.Conditions, metav1.Condition{Type: common.TypeAvailablePerses,
Expand All @@ -87,13 +92,28 @@ func (r *PersesReconciler) reconcileDeployment(ctx context.Context, req ctrl.Req
return subreconciler.RequeueWithError(err)
}

return subreconciler.RequeueWithDelay(time.Minute)
} else if err != nil {
dlog.WithError(err).Error("Failed to get Deployment")
return subreconciler.ContinueReconciling()
}

dep, err := r.createPersesDeployment(perses)
if err != nil {
dlog.WithError(err).Error("Failed to define new Deployment resource for perses")
return subreconciler.RequeueWithError(err)
}

// call update with dry run to fill out fields that are also returned via the k8s api
if err = r.Update(ctx, dep, client.DryRunAll); err != nil {
dlog.Error(err, "Failed to update Deployment with dry run")
return subreconciler.RequeueWithError(err)
}

if !equality.Semantic.DeepEqual(found.Spec, dep.Spec) {
if err = r.Update(ctx, dep); err != nil {
dlog.Error(err, "Failed to update Deployment")
return subreconciler.RequeueWithError(err)
}
}

return subreconciler.ContinueReconciling()
}

Expand Down
57 changes: 39 additions & 18 deletions controllers/perses/service_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,48 +19,54 @@ package perses
import (
"context"
"fmt"
"time"

"github.com/perses/perses-operator/api/v1alpha1"
"github.com/perses/perses-operator/internal/perses/common"
"github.com/perses/perses-operator/internal/subreconciler"
logger "github.com/sirupsen/logrus"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/equality"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/intstr"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"

"github.com/perses/perses-operator/api/v1alpha1"
"github.com/perses/perses-operator/internal/perses/common"
"github.com/perses/perses-operator/internal/subreconciler"
)

var slog = logger.WithField("module", "service_controller")

func (r *PersesReconciler) reconcileService(ctx context.Context, req ctrl.Request) (*ctrl.Result, error) {
perses := &v1alpha1.Perses{}

if r, err := r.getLatestPerses(ctx, req, perses); subreconciler.ShouldHaltOrRequeue(r, err) {
return r, err
if result, err := r.getLatestPerses(ctx, req, perses); subreconciler.ShouldHaltOrRequeue(result, err) {
return result, err
}

found := &corev1.Service{}
err := r.Get(ctx, types.NamespacedName{Name: perses.Name, Namespace: perses.Namespace}, found)
if err != nil && apierrors.IsNotFound(err) {
if err := r.Get(ctx, types.NamespacedName{Name: perses.Name, Namespace: perses.Namespace}, found); err != nil {
if !apierrors.IsNotFound(err) {
log.WithError(err).Error("Failed to get Service")

return subreconciler.RequeueWithError(err)
}

ser, err := r.createPersesService(perses)
if err != nil {
slog.WithError(err).Error("Failed to define new Service resource for perses")
ser, err2 := r.createPersesService(perses)
if err2 != nil {
slog.WithError(err2).Error("Failed to define new Service resource for perses")

meta.SetStatusCondition(&perses.Status.Conditions, metav1.Condition{Type: common.TypeAvailablePerses,
Status: metav1.ConditionFalse, Reason: "Reconciling",
Message: fmt.Sprintf("Failed to create Service for the custom resource (%s): (%s)", perses.Name, err)})
Message: fmt.Sprintf("Failed to create Service for the custom resource (%s): (%s)", perses.Name, err2)})

if err := r.Status().Update(ctx, perses); err != nil {
if err = r.Status().Update(ctx, perses); err != nil {
slog.Error(err, "Failed to update perses status")
return subreconciler.RequeueWithError(err)
}

return subreconciler.RequeueWithError(err)
return subreconciler.RequeueWithError(err2)
}

slog.Infof("Creating a new Service: Service.Namespace %s Service.Name %s", ser.Namespace, ser.Name)
Expand All @@ -69,13 +75,28 @@ func (r *PersesReconciler) reconcileService(ctx context.Context, req ctrl.Reques
return subreconciler.RequeueWithError(err)
}

return subreconciler.RequeueWithDelay(time.Minute)
} else if err != nil {
slog.WithError(err).Error("Failed to get Service")
return subreconciler.ContinueReconciling()
}

svc, err := r.createPersesService(perses)
if err != nil {
slog.WithError(err).Error("Failed to define new Service resource for perses")
return subreconciler.RequeueWithError(err)
}

// call update with dry run to fill out fields that are also returned via the k8s api
if err = r.Update(ctx, svc, client.DryRunAll); err != nil {
slog.Error(err, "Failed to update Service with dry run")
return subreconciler.RequeueWithError(err)
}

if !equality.Semantic.DeepEqual(found, svc) {
if err = r.Update(ctx, svc); err != nil {
slog.Error(err, "Failed to update Service")
return subreconciler.RequeueWithError(err)
}
}

return subreconciler.ContinueReconciling()
}

Expand Down Expand Up @@ -105,7 +126,7 @@ func (r *PersesReconciler) createPersesService(
Name: "http",
Port: 8080,
Protocol: corev1.ProtocolTCP,
TargetPort: intstr.FromInt(8080),
TargetPort: intstr.FromInt32(8080),
}},
Selector: ls,
},
Expand Down
Loading

0 comments on commit 9c039f2

Please sign in to comment.