Skip to content

Commit

Permalink
Merge pull request #5 from 3scale-ops/feat/show-resource-diff
Browse files Browse the repository at this point in the history
feat/show-resource-diff
  • Loading branch information
3scale-robot authored Oct 13, 2023
2 parents 2b99921 + e048e97 commit 62e4905
Show file tree
Hide file tree
Showing 16 changed files with 186 additions and 509 deletions.
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
module github.com/3scale-ops/basereconciler

go 1.19
go 1.20

require (
github.com/davecgh/go-spew v1.1.1
github.com/external-secrets/external-secrets v0.8.1
github.com/go-logr/logr v1.2.4
github.com/go-test/deep v1.1.0
github.com/google/go-cmp v0.5.9
github.com/goombaio/namegenerator v0.0.0-20181006234301-989e774b106e
github.com/grafana-operator/grafana-operator/v4 v4.10.0
github.com/onsi/ginkgo/v2 v2.9.1
Expand Down Expand Up @@ -43,7 +44,6 @@ require (
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/gnostic v0.6.9 // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/google/go-containerregistry v0.15.2 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/pprof v0.0.0-20230309165930-d61513b1440d // indirect
Expand Down
47 changes: 47 additions & 0 deletions property/changeset.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package property

import (
"github.com/go-logr/logr"
"github.com/google/go-cmp/cmp"
"k8s.io/apimachinery/pkg/api/equality"
)

type ChangeSet[T any] struct {
path string
current *T
desired *T
}

func NewChangeSet[T any](path string, current *T, desired *T) *ChangeSet[T] {
return &ChangeSet[T]{path: path, current: current, desired: desired}
}

// EnsureDesired checks if two structs are equal. If they are not, current is overwriten
// with the value of desired. Bool flag is returned to indicate if the value of current was changed.
func (set *ChangeSet[T]) EnsureDesired(logger logr.Logger) bool {

if equality.Semantic.DeepEqual(set.current, set.desired) {
return false
}

logger.V(1).Info("differences detected", "path", set.path, "diff", cmp.Diff(set.current, set.desired))
*set.current = *set.desired
return true
}

type ReconcilableProperty interface {
EnsureDesired(logger logr.Logger) bool
}

func EnsureDesired(logger logr.Logger, changeSets ...ReconcilableProperty) bool {
changed := false

for _, set := range changeSets {

if set.EnsureDesired(logger) {
changed = true
}
}

return changed
}
18 changes: 6 additions & 12 deletions resources/configmap.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import (
"context"
"fmt"

"github.com/3scale-ops/basereconciler/property"
"github.com/3scale-ops/basereconciler/reconciler"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
Expand Down Expand Up @@ -69,17 +69,11 @@ func (cmt ConfigMapTemplate) ResourceReconciler(ctx context.Context, cl client.C
return nil
}

/* Reconcile metadata */
if !equality.Semantic.DeepEqual(instance.GetLabels(), desired.GetLabels()) {
instance.ObjectMeta.Labels = desired.GetLabels()
needsUpdate = true
}

/* Reconcile the data */
if !equality.Semantic.DeepEqual(instance.Data, desired.Data) {
instance.Data = desired.Data
needsUpdate = true
}
/* Ensure the resource is in its desired state */
needsUpdate = property.EnsureDesired(logger,
property.NewChangeSet[map[string]string]("metadata.labels", &instance.ObjectMeta.Labels, &desired.ObjectMeta.Labels),
property.NewChangeSet[map[string]string]("data", &instance.Data, &desired.Data),
)

if needsUpdate {
err := cl.Update(ctx, instance)
Expand Down
117 changes: 16 additions & 101 deletions resources/deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@ import (
"context"
"fmt"

"github.com/3scale-ops/basereconciler/property"
"github.com/3scale-ops/basereconciler/reconciler"
"github.com/3scale-ops/basereconciler/util"
"github.com/go-test/deep"
appsv1 "k8s.io/api/apps/v1"
"k8s.io/apimachinery/pkg/api/equality"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/log"
Expand Down Expand Up @@ -81,101 +82,13 @@ func (dep DeploymentTemplate) ResourceReconciler(ctx context.Context, cl client.
return nil
}

/* Reconcile metadata */

/* Merge annotations */
desired.ObjectMeta.Annotations = util.MergeMaps(
map[string]string{},
desired.GetAnnotations(),
map[string]string{"deployment.kubernetes.io/revision": instance.GetAnnotations()["deployment.kubernetes.io/revision"]},
)

if !equality.Semantic.DeepEqual(instance.GetAnnotations(), desired.GetAnnotations()) {
logger.Info("resource update required due to differences in metadata.annotations.")
logger.V(1).Info(
fmt.Sprintf("metadata.annotations differences: %s",
deep.Equal(instance.GetAnnotations(), desired.GetAnnotations())),
)
instance.ObjectMeta.Annotations = desired.GetAnnotations()
needsUpdate = true
}
if !equality.Semantic.DeepEqual(instance.GetLabels(), desired.GetLabels()) {
logger.Info("resource update required due to differences in metadata.labels.")
logger.V(1).Info(
fmt.Sprintf("metadata.labels differences: %s",
deep.Equal(instance.GetLabels(), desired.GetLabels())),
)
instance.ObjectMeta.Labels = desired.GetLabels()
needsUpdate = true
}

/* Reconcile the MinReadySeconds */
if !equality.Semantic.DeepEqual(instance.Spec.MinReadySeconds, desired.Spec.MinReadySeconds) {
logger.Info("resource update required due to differences in spec.minReadySeconds.")
logger.V(1).Info(
fmt.Sprintf("spec.minReadySeconds differences: %s",
deep.Equal(instance.Spec.MinReadySeconds, desired.Spec.MinReadySeconds)),
)
instance.Spec.MinReadySeconds = desired.Spec.MinReadySeconds
needsUpdate = true
}

/* Reconcile the Replicas */
if !equality.Semantic.DeepEqual(instance.Spec.Replicas, desired.Spec.Replicas) {
logger.Info("resource update required due to differences in spec.replicas.")
logger.V(1).Info(
fmt.Sprintf("spec.replicas differences: %s",
deep.Equal(instance.Spec.Replicas, desired.Spec.Replicas)),
)
instance.Spec.Replicas = desired.Spec.Replicas
needsUpdate = true
}

/* Reconcile the Selector */
if !equality.Semantic.DeepEqual(instance.Spec.Selector, desired.Spec.Selector) {
logger.Info("resource update required due to differences in spec.selector.")
logger.V(1).Info(
fmt.Sprintf("spec.selector differences: %s",
deep.Equal(instance.Spec.Selector, desired.Spec.Selector)),
)
instance.Spec.Selector = desired.Spec.Selector
needsUpdate = true
}

/* Reconcile the Strategy */
if !equality.Semantic.DeepEqual(instance.Spec.Strategy, desired.Spec.Strategy) {
logger.Info("resource update required due to differences in spec.strategy.")
logger.V(1).Info(
fmt.Sprintf("spec.strategy differences: %s",
deep.Equal(instance.Spec.Strategy, desired.Spec.Strategy)),
)
instance.Spec.Strategy = desired.Spec.Strategy
needsUpdate = true
}

/* Reconcile the Template Labels */
if !equality.Semantic.DeepEqual(
instance.Spec.Template.ObjectMeta.Labels, desired.Spec.Template.ObjectMeta.Labels) {
logger.Info("resource update required due to differences in spec.template.metadata.labels.")
logger.V(1).Info(
fmt.Sprintf("spec.template.metadata.labels differences: %s",
deep.Equal(instance.Spec.Template.ObjectMeta.Labels, desired.Spec.Template.ObjectMeta.Labels)),
)
instance.Spec.Template.ObjectMeta.Labels = desired.Spec.Template.ObjectMeta.Labels
needsUpdate = true
}

/* Reconcile the Template Annotations */
if !equality.Semantic.DeepEqual(
instance.Spec.Template.ObjectMeta.Annotations, desired.Spec.Template.ObjectMeta.Annotations) {
logger.Info("resource update required due differences in spec.template.metadata.annotations.")
logger.V(1).Info(
fmt.Sprintf("spec.template.metadata.annotations differences: %s",
deep.Equal(instance.Spec.Template.ObjectMeta.Annotations, desired.Spec.Template.ObjectMeta.Annotations)),
)
instance.Spec.Template.ObjectMeta.Annotations = desired.Spec.Template.ObjectMeta.Annotations
needsUpdate = true
}

/* Inherit some values usually defaulted by the cluster if not defined on the template */
if desired.Spec.Template.Spec.DNSPolicy == "" {
desired.Spec.Template.Spec.DNSPolicy = instance.Spec.Template.Spec.DNSPolicy
Expand All @@ -184,16 +97,18 @@ func (dep DeploymentTemplate) ResourceReconciler(ctx context.Context, cl client.
desired.Spec.Template.Spec.SchedulerName = instance.Spec.Template.Spec.SchedulerName
}

/* Reconcile the Template Spec */
if !equality.Semantic.DeepEqual(instance.Spec.Template.Spec, desired.Spec.Template.Spec) {
logger.Info("resource update required due to differences in spec.template.spec.")
logger.V(1).Info(
fmt.Sprintf("spec.template.spec differences: %s",
deep.Equal(instance.Spec.Template.Spec, desired.Spec.Template.Spec)),
)
instance.Spec.Template.Spec = desired.Spec.Template.Spec
needsUpdate = true
}
/* Ensure the resource is in its desired state */
needsUpdate = property.EnsureDesired(logger,
property.NewChangeSet[map[string]string]("metadata.labels", &instance.ObjectMeta.Labels, &desired.ObjectMeta.Labels),
property.NewChangeSet[map[string]string]("metadata.annotations", &instance.ObjectMeta.Annotations, &desired.ObjectMeta.Annotations),
property.NewChangeSet[int32]("spec.minReadySeconds", &instance.Spec.MinReadySeconds, &desired.Spec.MinReadySeconds),
property.NewChangeSet[int32]("spec.replicas", instance.Spec.Replicas, desired.Spec.Replicas),
property.NewChangeSet[metav1.LabelSelector]("spec.selector", instance.Spec.Selector, desired.Spec.Selector),
property.NewChangeSet[appsv1.DeploymentStrategy]("spec.strategy", &instance.Spec.Strategy, &desired.Spec.Strategy),
property.NewChangeSet[map[string]string]("spec.template.metadata.labels", &instance.Spec.Template.ObjectMeta.Labels, &desired.Spec.Template.ObjectMeta.Labels),
property.NewChangeSet[map[string]string]("spec.template.metadata.annotations", &instance.Spec.Template.ObjectMeta.Annotations, &desired.Spec.Template.ObjectMeta.Annotations),
property.NewChangeSet[corev1.PodSpec]("spec.template.spec", &instance.Spec.Template.Spec, &desired.Spec.Template.Spec),
)

if needsUpdate {
err := cl.Update(ctx, instance)
Expand Down
18 changes: 6 additions & 12 deletions resources/external_secret.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import (
"context"
"fmt"

"github.com/3scale-ops/basereconciler/property"
"github.com/3scale-ops/basereconciler/reconciler"
externalsecretsv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
"k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
Expand Down Expand Up @@ -69,17 +69,11 @@ func (est ExternalSecretTemplate) ResourceReconciler(ctx context.Context, cl cli
return nil
}

/* Reconcile metadata */
if !equality.Semantic.DeepEqual(instance.GetLabels(), desired.GetLabels()) {
instance.ObjectMeta.Labels = desired.GetLabels()
needsUpdate = true
}

/* Reconcile the spec */
if !equality.Semantic.DeepEqual(instance.Spec, desired.Spec) {
instance.Spec = desired.Spec
needsUpdate = true
}
/* Ensure the resource is in its desired state */
needsUpdate = property.EnsureDesired(logger,
property.NewChangeSet[map[string]string]("metadata.labels", &instance.ObjectMeta.Labels, &desired.ObjectMeta.Labels),
property.NewChangeSet[externalsecretsv1beta1.ExternalSecretSpec]("spec", &instance.Spec, &desired.Spec),
)

if needsUpdate {
err := cl.Update(ctx, instance)
Expand Down
18 changes: 6 additions & 12 deletions resources/grafana_dashboard.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import (
"context"
"fmt"

"github.com/3scale-ops/basereconciler/property"
"github.com/3scale-ops/basereconciler/reconciler"
grafanav1alpha1 "github.com/grafana-operator/grafana-operator/v4/api/integreatly/v1alpha1"
"k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
Expand Down Expand Up @@ -69,17 +69,11 @@ func (gdt GrafanaDashboardTemplate) ResourceReconciler(ctx context.Context, cl c
return nil
}

/* Reconcile metadata */
if !equality.Semantic.DeepEqual(instance.GetLabels(), desired.GetLabels()) {
instance.ObjectMeta.Labels = desired.GetLabels()
needsUpdate = true
}

/* Reconcile the spec */
if !equality.Semantic.DeepEqual(instance.Spec, desired.Spec) {
instance.Spec = desired.Spec
needsUpdate = true
}
/* Ensure the resource is in its desired state */
needsUpdate = property.EnsureDesired(logger,
property.NewChangeSet[map[string]string]("metadata.labels", &instance.ObjectMeta.Labels, &desired.ObjectMeta.Labels),
property.NewChangeSet[grafanav1alpha1.GrafanaDashboardSpec]("spec", &instance.Spec, &desired.Spec),
)

if needsUpdate {
err := cl.Update(ctx, instance)
Expand Down
29 changes: 10 additions & 19 deletions resources/hpa.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"fmt"

"github.com/3scale-ops/basereconciler/property"
"github.com/3scale-ops/basereconciler/reconciler"
autoscalingv2 "k8s.io/api/autoscaling/v2"
"k8s.io/apimachinery/pkg/api/equality"
Expand Down Expand Up @@ -79,25 +80,15 @@ func (hpat HorizontalPodAutoscalerTemplate) ResourceReconciler(ctx context.Conte
needsUpdate = true
}

/* Reconcile the ScaleTargetRef, MinReplicas, MaxReplicas and Metrics properties */
if !equality.Semantic.DeepEqual(instance.Spec.ScaleTargetRef, desired.Spec.ScaleTargetRef) {
instance.Spec.ScaleTargetRef = desired.Spec.ScaleTargetRef
needsUpdate = true
}

if !equality.Semantic.DeepEqual(instance.Spec.MinReplicas, desired.Spec.MinReplicas) {
instance.Spec.MinReplicas = desired.Spec.MinReplicas
needsUpdate = true
}
if !equality.Semantic.DeepEqual(instance.Spec.MaxReplicas, desired.Spec.MaxReplicas) {
instance.Spec.MaxReplicas = desired.Spec.MaxReplicas
needsUpdate = true
}

if !equality.Semantic.DeepEqual(instance.Spec.Metrics, desired.Spec.Metrics) {
instance.Spec.Metrics = desired.Spec.Metrics
needsUpdate = true
}
/* Ensure the resource is in its desired state */
needsUpdate = property.EnsureDesired(logger,
property.NewChangeSet[map[string]string]("metadata.labels", &instance.ObjectMeta.Labels, &desired.ObjectMeta.Labels),
property.NewChangeSet[map[string]string]("metadata.annotations", &instance.ObjectMeta.Annotations, &desired.ObjectMeta.Annotations),
property.NewChangeSet[autoscalingv2.CrossVersionObjectReference]("spec.scaleTargetRef", &instance.Spec.ScaleTargetRef, &desired.Spec.ScaleTargetRef),
property.NewChangeSet[int32]("spec.minReplicas", instance.Spec.MinReplicas, desired.Spec.MinReplicas),
property.NewChangeSet[int32]("spec.maxReplicas", &instance.Spec.MaxReplicas, &desired.Spec.MaxReplicas),
property.NewChangeSet[[]autoscalingv2.MetricSpec]("spec.metrics", &instance.Spec.Metrics, &desired.Spec.Metrics),
)

if needsUpdate {
err := cl.Update(ctx, instance)
Expand Down
Loading

0 comments on commit 62e4905

Please sign in to comment.