Skip to content

Commit 717a627

Browse files
Extract shared watch map helpers into internal/common
Replace duplicated controller watch map functions with generic helpers in internal/common/watch.go. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 213704b commit 717a627

10 files changed

Lines changed: 271 additions & 530 deletions

internal/common/watch.go

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
/*
2+
Copyright 2026.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package common //nolint:revive // common is the established package name for multi-group shared code
18+
19+
import (
20+
"context"
21+
"fmt"
22+
23+
"github.com/go-logr/logr"
24+
"github.com/openstack-k8s-operators/lib-common/modules/common"
25+
"github.com/openstack-k8s-operators/lib-common/modules/common/util"
26+
"k8s.io/apimachinery/pkg/api/meta"
27+
"k8s.io/apimachinery/pkg/fields"
28+
"k8s.io/apimachinery/pkg/runtime"
29+
"k8s.io/apimachinery/pkg/types"
30+
"sigs.k8s.io/controller-runtime/pkg/client"
31+
"sigs.k8s.io/controller-runtime/pkg/reconcile"
32+
)
33+
34+
// FindObjectsForSrcByField returns reconcile requests for CRs in src's namespace
35+
// that reference src via one of the indexed watchFields.
36+
func FindObjectsForSrcByField(
37+
ctx context.Context,
38+
log logr.Logger,
39+
reader client.Reader,
40+
src client.Object,
41+
watchFields []string,
42+
newList func() client.ObjectList,
43+
) []reconcile.Request {
44+
var requests []reconcile.Request
45+
46+
for _, field := range watchFields {
47+
crList := newList()
48+
listOps := &client.ListOptions{
49+
FieldSelector: fields.OneTermEqualSelector(field, src.GetName()),
50+
Namespace: src.GetNamespace(),
51+
}
52+
err := reader.List(ctx, crList, listOps)
53+
if err != nil {
54+
log.Error(err, fmt.Sprintf("listing %s for field: %s - %s", crList.GetObjectKind().GroupVersionKind().Kind, field, src.GetNamespace()))
55+
return requests
56+
}
57+
58+
items, err := meta.ExtractList(crList)
59+
if err != nil {
60+
log.Error(err, fmt.Sprintf("extracting items from %s", crList.GetObjectKind().GroupVersionKind().Kind))
61+
return requests
62+
}
63+
requests = appendRequestsForObjects(log, src, requests, items)
64+
}
65+
66+
return requests
67+
}
68+
69+
// FindObjectsForSrcInNamespace returns reconcile requests for all CRs in src's namespace.
70+
func FindObjectsForSrcInNamespace(
71+
ctx context.Context,
72+
log logr.Logger,
73+
reader client.Reader,
74+
src client.Object,
75+
newList func() client.ObjectList,
76+
) []reconcile.Request {
77+
crList := newList()
78+
listOps := &client.ListOptions{
79+
Namespace: src.GetNamespace(),
80+
}
81+
err := reader.List(ctx, crList, listOps)
82+
if err != nil {
83+
log.Error(err, fmt.Sprintf("listing %s for namespace: %s", crList.GetObjectKind().GroupVersionKind().Kind, src.GetNamespace()))
84+
return nil
85+
}
86+
87+
items, err := meta.ExtractList(crList)
88+
if err != nil {
89+
log.Error(err, fmt.Sprintf("extracting items from %s", crList.GetObjectKind().GroupVersionKind().Kind))
90+
return nil
91+
}
92+
return appendRequestsForObjects(log, src, nil, items)
93+
}
94+
95+
// FindObjectsWithAppSelectorLabelInNamespace returns reconcile requests for all CRs
96+
// in src's namespace when src carries an AppSelector label matching allowedServices.
97+
func FindObjectsWithAppSelectorLabelInNamespace(
98+
ctx context.Context,
99+
log logr.Logger,
100+
reader client.Reader,
101+
src client.Object,
102+
allowedServices []string,
103+
newList func() client.ObjectList,
104+
) []reconcile.Request {
105+
if svc, ok := src.GetLabels()[common.AppSelector]; ok && util.StringInSlice(svc, allowedServices) {
106+
return FindObjectsForSrcInNamespace(ctx, log, reader, src, newList)
107+
}
108+
109+
return nil
110+
}
111+
112+
func appendRequestsForObjects(
113+
log logr.Logger,
114+
src client.Object,
115+
requests []reconcile.Request,
116+
items []runtime.Object,
117+
) []reconcile.Request {
118+
for _, item := range items {
119+
accessor, err := meta.Accessor(item)
120+
if err != nil {
121+
log.Error(err, "extracting object metadata")
122+
continue
123+
}
124+
log.Info(fmt.Sprintf("input source %s changed, reconcile: %s - %s", src.GetName(), accessor.GetName(), accessor.GetNamespace()))
125+
126+
requests = append(requests,
127+
reconcile.Request{
128+
NamespacedName: types.NamespacedName{
129+
Name: accessor.GetName(),
130+
Namespace: accessor.GetNamespace(),
131+
},
132+
},
133+
)
134+
}
135+
136+
return requests
137+
}

internal/controller/nova/nova_controller.go

Lines changed: 15 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ import (
2828
rbacv1 "k8s.io/api/rbac/v1"
2929
k8s_errors "k8s.io/apimachinery/pkg/api/errors"
3030
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
31-
"k8s.io/apimachinery/pkg/fields"
3231
"k8s.io/apimachinery/pkg/types"
3332
ctrl "sigs.k8s.io/controller-runtime"
3433
"sigs.k8s.io/controller-runtime/pkg/builder"
@@ -2264,68 +2263,24 @@ func (r *NovaReconciler) ensureTopLevelSecret(
22642263
}
22652264

22662265
func (r *NovaReconciler) findObjectsForSrc(ctx context.Context, src client.Object) []reconcile.Request {
2267-
requests := []reconcile.Request{}
2268-
2269-
Log := r.GetLogger(ctx)
2270-
2271-
for _, field := range novaWatchFields {
2272-
crList := &novav1.NovaList{}
2273-
listOps := &client.ListOptions{
2274-
FieldSelector: fields.OneTermEqualSelector(field, src.GetName()),
2275-
Namespace: src.GetNamespace(),
2276-
}
2277-
err := r.Client.List(ctx, crList, listOps)
2278-
if err != nil {
2279-
Log.Error(err, fmt.Sprintf("listing %s for field: %s - %s", crList.GroupVersionKind().Kind, field, src.GetNamespace()))
2280-
return requests
2281-
}
2282-
2283-
for _, item := range crList.Items {
2284-
Log.Info(fmt.Sprintf("input source %s changed, reconcile: %s - %s", src.GetName(), item.GetName(), item.GetNamespace()))
2285-
2286-
requests = append(requests,
2287-
reconcile.Request{
2288-
NamespacedName: types.NamespacedName{
2289-
Name: item.GetName(),
2290-
Namespace: item.GetNamespace(),
2291-
},
2292-
},
2293-
)
2294-
}
2295-
}
2296-
2297-
return requests
2266+
return internalcommon.FindObjectsForSrcByField(
2267+
ctx,
2268+
r.GetLogger(ctx),
2269+
r.Client,
2270+
src,
2271+
novaWatchFields,
2272+
func() client.ObjectList { return &novav1.NovaList{} },
2273+
)
22982274
}
22992275

23002276
func (r *NovaReconciler) findObjectForSrc(ctx context.Context, src client.Object) []reconcile.Request {
2301-
requests := []reconcile.Request{}
2302-
2303-
Log := r.GetLogger(ctx)
2304-
2305-
crList := &novav1.NovaList{}
2306-
listOps := &client.ListOptions{
2307-
Namespace: src.GetNamespace(),
2308-
}
2309-
err := r.Client.List(ctx, crList, listOps)
2310-
if err != nil {
2311-
Log.Error(err, fmt.Sprintf("listing %s for namespace: %s", crList.GroupVersionKind().Kind, src.GetNamespace()))
2312-
return requests
2313-
}
2314-
2315-
for _, item := range crList.Items {
2316-
Log.Info(fmt.Sprintf("input source %s changed, reconcile: %s - %s", src.GetName(), item.GetName(), item.GetNamespace()))
2317-
2318-
requests = append(requests,
2319-
reconcile.Request{
2320-
NamespacedName: types.NamespacedName{
2321-
Name: item.GetName(),
2322-
Namespace: item.GetNamespace(),
2323-
},
2324-
},
2325-
)
2326-
}
2327-
2328-
return requests
2277+
return internalcommon.FindObjectsForSrcInNamespace(
2278+
ctx,
2279+
r.GetLogger(ctx),
2280+
r.Client,
2281+
src,
2282+
func() client.ObjectList { return &novav1.NovaList{} },
2283+
)
23292284
}
23302285

23312286
func (r *NovaReconciler) memcachedNamespaceMapFunc(ctx context.Context, src client.Object) []reconcile.Request {

internal/controller/nova/novaapi_controller.go

Lines changed: 16 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import (
2323

2424
v1 "k8s.io/api/apps/v1"
2525
corev1 "k8s.io/api/core/v1"
26-
"k8s.io/apimachinery/pkg/fields"
2726
"k8s.io/apimachinery/pkg/types"
2827
"k8s.io/utils/ptr"
2928
ctrl "sigs.k8s.io/controller-runtime"
@@ -927,71 +926,25 @@ func getAPIServiceLabels() map[string]string {
927926
}
928927

929928
func (r *NovaAPIReconciler) findObjectsForSrc(ctx context.Context, src client.Object) []reconcile.Request {
930-
requests := []reconcile.Request{}
931-
932-
Log := r.GetLogger(ctx)
933-
934-
for _, field := range apiWatchFields {
935-
crList := &novav1.NovaAPIList{}
936-
listOps := &client.ListOptions{
937-
FieldSelector: fields.OneTermEqualSelector(field, src.GetName()),
938-
Namespace: src.GetNamespace(),
939-
}
940-
err := r.Client.List(ctx, crList, listOps)
941-
if err != nil {
942-
Log.Error(err, fmt.Sprintf("listing %s for field: %s - %s", crList.GroupVersionKind().Kind, field, src.GetNamespace()))
943-
return requests
944-
}
945-
946-
for _, item := range crList.Items {
947-
Log.Info(fmt.Sprintf("input source %s changed, reconcile: %s - %s", src.GetName(), item.GetName(), item.GetNamespace()))
948-
949-
requests = append(requests,
950-
reconcile.Request{
951-
NamespacedName: types.NamespacedName{
952-
Name: item.GetName(),
953-
Namespace: item.GetNamespace(),
954-
},
955-
},
956-
)
957-
}
958-
}
959-
960-
return requests
929+
return internalcommon.FindObjectsForSrcByField(
930+
ctx,
931+
r.GetLogger(ctx),
932+
r.Client,
933+
src,
934+
apiWatchFields,
935+
func() client.ObjectList { return &novav1.NovaAPIList{} },
936+
)
961937
}
962938

963939
func (r *NovaAPIReconciler) findObjectsWithAppSelectorLabelInNamespace(ctx context.Context, src client.Object) []reconcile.Request {
964-
requests := []reconcile.Request{}
965-
966-
Log := r.GetLogger(ctx)
967-
968-
// if the endpoint has the service label and its in our endpointList, reconcile the CR in the namespace
969-
if svc, ok := src.GetLabels()[common.AppSelector]; ok && util.StringInSlice(svc, endpointList) {
970-
crList := &novav1.NovaAPIList{}
971-
listOps := &client.ListOptions{
972-
Namespace: src.GetNamespace(),
973-
}
974-
err := r.Client.List(ctx, crList, listOps)
975-
if err != nil {
976-
Log.Error(err, fmt.Sprintf("listing %s for namespace: %s", crList.GroupVersionKind().Kind, src.GetNamespace()))
977-
return requests
978-
}
979-
980-
for _, item := range crList.Items {
981-
Log.Info(fmt.Sprintf("input source %s changed, reconcile: %s - %s", src.GetName(), item.GetName(), item.GetNamespace()))
982-
983-
requests = append(requests,
984-
reconcile.Request{
985-
NamespacedName: types.NamespacedName{
986-
Name: item.GetName(),
987-
Namespace: item.GetNamespace(),
988-
},
989-
},
990-
)
991-
}
992-
}
993-
994-
return requests
940+
return internalcommon.FindObjectsWithAppSelectorLabelInNamespace(
941+
ctx,
942+
r.GetLogger(ctx),
943+
r.Client,
944+
src,
945+
endpointList,
946+
func() client.ObjectList { return &novav1.NovaAPIList{} },
947+
)
995948
}
996949

997950
// fields to index to reconcile when change

internal/controller/nova/novacell_controller.go

Lines changed: 8 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ import (
2424
corev1 "k8s.io/api/core/v1"
2525
k8s_errors "k8s.io/apimachinery/pkg/api/errors"
2626
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
27-
"k8s.io/apimachinery/pkg/fields"
2827
"k8s.io/apimachinery/pkg/types"
2928
"k8s.io/utils/ptr"
3029
ctrl "sigs.k8s.io/controller-runtime"
@@ -867,37 +866,14 @@ func (r *NovaCellReconciler) getVNCProxyURL(
867866
}
868867

869868
func (r *NovaCellReconciler) findObjectsForSrc(ctx context.Context, src client.Object) []reconcile.Request {
870-
requests := []reconcile.Request{}
871-
872-
Log := r.GetLogger(ctx)
873-
874-
for _, field := range cellWatchFields {
875-
crList := &novav1.NovaCellList{}
876-
listOps := &client.ListOptions{
877-
FieldSelector: fields.OneTermEqualSelector(field, src.GetName()),
878-
Namespace: src.GetNamespace(),
879-
}
880-
err := r.Client.List(ctx, crList, listOps)
881-
if err != nil {
882-
Log.Error(err, fmt.Sprintf("listing %s for field: %s - %s", crList.GroupVersionKind().Kind, field, src.GetNamespace()))
883-
return requests
884-
}
885-
886-
for _, item := range crList.Items {
887-
Log.Info(fmt.Sprintf("input source %s changed, reconcile: %s - %s", src.GetName(), item.GetName(), item.GetNamespace()))
888-
889-
requests = append(requests,
890-
reconcile.Request{
891-
NamespacedName: types.NamespacedName{
892-
Name: item.GetName(),
893-
Namespace: item.GetNamespace(),
894-
},
895-
},
896-
)
897-
}
898-
}
899-
900-
return requests
869+
return internalcommon.FindObjectsForSrcByField(
870+
ctx,
871+
r.GetLogger(ctx),
872+
r.Client,
873+
src,
874+
cellWatchFields,
875+
func() client.ObjectList { return &novav1.NovaCellList{} },
876+
)
901877
}
902878

903879
// fields to index to reconcile when change

0 commit comments

Comments
 (0)