Skip to content

Commit 513281b

Browse files
authored
Fix issue where the Operator did not delete secondary resources when a Coherence resource was updated (#792)
1 parent 4eca872 commit 513281b

File tree

4 files changed

+146
-6
lines changed

4 files changed

+146
-6
lines changed

controllers/coherence_controller.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ package controllers
99
import (
1010
"context"
1111
"fmt"
12+
"strconv"
13+
"time"
14+
1215
"github.com/go-logr/logr"
1316
coh "github.com/oracle/coherence-operator/api/v1"
1417
"github.com/oracle/coherence-operator/controllers/errorhandling"
@@ -37,8 +40,6 @@ import (
3740
"sigs.k8s.io/controller-runtime/pkg/handler"
3841
"sigs.k8s.io/controller-runtime/pkg/reconcile"
3942
"sigs.k8s.io/controller-runtime/pkg/source"
40-
"strconv"
41-
"time"
4243
)
4344

4445
const (

controllers/reconciler/base_controller.go

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ package reconciler
99
import (
1010
"context"
1111
"fmt"
12+
"sort"
13+
"strings"
14+
"sync"
15+
1216
"github.com/go-logr/logr"
1317
coh "github.com/oracle/coherence-operator/api/v1"
1418
"github.com/oracle/coherence-operator/controllers/errorhandling"
@@ -30,9 +34,6 @@ import (
3034
logf "sigs.k8s.io/controller-runtime/pkg/log"
3135
"sigs.k8s.io/controller-runtime/pkg/manager"
3236
"sigs.k8s.io/controller-runtime/pkg/reconcile"
33-
"sort"
34-
"strings"
35-
"sync"
3637
)
3738

3839
//goland:noinspection GoUnusedConst
@@ -722,9 +723,27 @@ func (in *ReconcileSecondaryResource) CanWatch() bool { return !in.S
722723

723724
// ReconcileAllResourceOfKind reconciles the state of all the desired resources of the specified Kind for the reconciler
724725
func (in *ReconcileSecondaryResource) ReconcileAllResourceOfKind(ctx context.Context, request reconcile.Request, deployment coh.CoherenceResource, storage utils.Storage) (reconcile.Result, error) {
725-
logger := in.GetLog().WithValues("Namespace", request.Namespace, "Name", request.Name, "Kind", in.Kind.Name())
726+
logger := in.GetLog().WithValues("Namespace", request.Namespace, "CoherenceName", request.Name, "Kind", in.Kind.Name())
726727

727728
var err error
729+
730+
for _, del := range storage.GetDeletions() {
731+
if del.Kind == in.Kind {
732+
logger.Info("Deleting resource", "Name", del.Name)
733+
resource, exists, _ := in.FindResource(ctx, request.Namespace, del.Name)
734+
if exists {
735+
err = in.Delete(ctx, request.Namespace, del.Name, logger)
736+
if err != nil && !errorhandling.IsNotFound(err) {
737+
logger.Info("Failed to delete resource", "Name", del.Name, "error", err.Error())
738+
return reconcile.Result{}, errors.Wrapf(err, "Failed to delete resource %v/%s", in.Kind, del.Name)
739+
}
740+
if err == nil {
741+
in.GetEventRecorder().Event(resource, corev1.EventTypeNormal, EventReasonDeleted, fmt.Sprintf("Deleted resource after update to Coherence resource %s", deployment.GetName()))
742+
}
743+
}
744+
}
745+
}
746+
728747
resources := storage.GetLatest().GetResourcesOfKind(in.Kind)
729748
for _, res := range resources {
730749
if res.IsDelete() {

pkg/utils/storage.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"context"
1111
"encoding/json"
1212
"fmt"
13+
1314
coh "github.com/oracle/coherence-operator/api/v1"
1415
"github.com/oracle/coherence-operator/pkg/patching"
1516
"github.com/pkg/errors"
@@ -47,6 +48,9 @@ type Storage interface {
4748
ResetHash(context.Context, coh.CoherenceResource) error
4849
// IsJob returns true if the Coherence deployment is a Job
4950
IsJob(reconcile.Request) bool
51+
// GetDeletions returns an array of resources that existed in the previous version
52+
// but do not exist in the latest version
53+
GetDeletions() []coh.Resource
5054
}
5155

5256
// NewStorage creates a new storage for the given key.
@@ -78,6 +82,25 @@ func (in *secretStore) IsJob(request reconcile.Request) bool {
7882
return found
7983
}
8084

85+
func (in *secretStore) GetDeletions() []coh.Resource {
86+
var deletions []coh.Resource
87+
if in != nil {
88+
for _, prev := range in.previous.Items {
89+
found := false
90+
for _, res := range in.latest.Items {
91+
if prev.Name == res.Name && prev.Kind == res.Kind {
92+
found = true
93+
break
94+
}
95+
}
96+
if !found {
97+
deletions = append(deletions, prev)
98+
}
99+
}
100+
}
101+
return deletions
102+
}
103+
81104
func (in *secretStore) createSecretStruct() *corev1.Secret {
82105
labels := make(map[string]string)
83106
labels[coh.LabelCoherenceStore] = "true"

pkg/utils/storage_test.go

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/*
2+
* Copyright (c) 2020, 2025, Oracle and/or its affiliates.
3+
* Licensed under the Universal Permissive License v 1.0 as shown at
4+
* http://oss.oracle.com/licenses/upl.
5+
*/
6+
7+
package utils
8+
9+
import (
10+
"testing"
11+
12+
. "github.com/onsi/gomega"
13+
coh "github.com/oracle/coherence-operator/api/v1"
14+
)
15+
16+
func TestGetDeletionsWhenLatestAndPrevAreNil(t *testing.T) {
17+
g := NewGomegaWithT(t)
18+
s := &secretStore{}
19+
g.Expect(s.GetDeletions()).To(BeNil())
20+
}
21+
22+
func TestGetDeletionsWhenLatestAndPrevItemsAreNil(t *testing.T) {
23+
g := NewGomegaWithT(t)
24+
s := &secretStore{
25+
latest: coh.Resources{},
26+
previous: coh.Resources{},
27+
}
28+
g.Expect(s.GetDeletions()).To(BeNil())
29+
}
30+
31+
func TestGetDeletionsWhenLatestAndPrevItemsAreEmpty(t *testing.T) {
32+
g := NewGomegaWithT(t)
33+
s := &secretStore{
34+
latest: coh.Resources{
35+
Items: make([]coh.Resource, 0),
36+
},
37+
previous: coh.Resources{
38+
Items: make([]coh.Resource, 0),
39+
},
40+
}
41+
g.Expect(s.GetDeletions()).To(BeNil())
42+
}
43+
44+
func TestGetDeletionsWhenPrevItemsAreEmpty(t *testing.T) {
45+
g := NewGomegaWithT(t)
46+
s := &secretStore{
47+
latest: coh.Resources{
48+
Items: []coh.Resource{
49+
{Name: "foo", Kind: coh.ResourceTypeService},
50+
{Name: "svc1", Kind: coh.ResourceTypeService},
51+
{Name: "foo", Kind: coh.ResourceTypeSecret},
52+
{Name: "bar", Kind: coh.ResourceTypeSecret},
53+
{Name: "sec2", Kind: coh.ResourceTypeSecret},
54+
},
55+
},
56+
previous: coh.Resources{
57+
Items: make([]coh.Resource, 0),
58+
},
59+
}
60+
g.Expect(s.GetDeletions()).To(BeNil())
61+
}
62+
63+
func TestGetDeletions(t *testing.T) {
64+
g := NewGomegaWithT(t)
65+
66+
s := &secretStore{
67+
latest: coh.Resources{
68+
Items: []coh.Resource{
69+
{Name: "svc1", Kind: coh.ResourceTypeService},
70+
{Name: "foo", Kind: coh.ResourceTypeSecret},
71+
{Name: "bar", Kind: coh.ResourceTypeSecret},
72+
{Name: "sec2", Kind: coh.ResourceTypeSecret},
73+
},
74+
},
75+
previous: coh.Resources{
76+
Items: []coh.Resource{
77+
{Name: "foo", Kind: coh.ResourceTypeService},
78+
{Name: "bar", Kind: coh.ResourceTypeService},
79+
{Name: "svc1", Kind: coh.ResourceTypeService},
80+
{Name: "svc2", Kind: coh.ResourceTypeService},
81+
{Name: "foo", Kind: coh.ResourceTypeSecret},
82+
{Name: "sec1", Kind: coh.ResourceTypeSecret},
83+
{Name: "sec2", Kind: coh.ResourceTypeSecret},
84+
},
85+
},
86+
}
87+
g.Expect(s.GetDeletions()).NotTo(BeNil())
88+
89+
expected := []coh.Resource{
90+
{Name: "foo", Kind: coh.ResourceTypeService},
91+
{Name: "bar", Kind: coh.ResourceTypeService},
92+
{Name: "svc2", Kind: coh.ResourceTypeService},
93+
{Name: "sec1", Kind: coh.ResourceTypeSecret},
94+
}
95+
96+
g.Expect(s.GetDeletions()).To(Equal(expected))
97+
}

0 commit comments

Comments
 (0)