Skip to content

Commit 7c58797

Browse files
authored
fix: fix setting secret or configmap label selector to empty (#2815) (#2826)
1 parent d68e764 commit 7c58797

File tree

4 files changed

+185
-27
lines changed

4 files changed

+185
-27
lines changed

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
## Table of Contents
44

5+
- [v2.0.7](#v207)
56
- [v2.0.6](#v206)
67
- [v2.0.5](#v205)
78
- [v2.0.4](#v204)
@@ -36,6 +37,16 @@
3637
- [v0.1.1](#v011)
3738
- [v0.1.0](#v010)
3839

40+
## [v2.0.7]
41+
42+
> Release date: TBD
43+
44+
### Fixed
45+
46+
- Fixed an issue where users could set the secret of configmap label selectors
47+
to empty when the other one was left non-empty.
48+
[#2815](https://github.com/Kong/kong-operator/pull/2815)
49+
3950
## [v2.0.6]
4051

4152
> Release date: 2025-12-01
@@ -1415,6 +1426,7 @@ leftovers from previous operator deployments in the cluster. The user needs to d
14151426
(clusterrole, clusterrolebinding, validatingWebhookConfiguration) before
14161427
re-installing the operator through the bundle.
14171428

1429+
[v2.0.7]: https://github.com/Kong/kong-operator/compare/v2.0.6..v2.0.7
14181430
[v2.0.6]: https://github.com/Kong/kong-operator/compare/v2.0.5..v2.0.6
14191431
[v2.0.5]: https://github.com/Kong/kong-operator/compare/v2.0.4..v2.0.5
14201432
[v2.0.4]: https://github.com/Kong/kong-operator/compare/v2.0.3..v2.0.4

modules/manager/cache_options.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package manager
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/go-logr/logr"
7+
corev1 "k8s.io/api/core/v1"
8+
"sigs.k8s.io/controller-runtime/pkg/cache"
9+
"sigs.k8s.io/controller-runtime/pkg/client"
10+
)
11+
12+
func createCacheOptions(l logr.Logger, cfg Config) (cache.Options, error) {
13+
var cacheOptions cache.Options
14+
if cfg.CacheSyncPeriod > 0 {
15+
l.Info("cache sync period set", "period", cfg.CacheSyncPeriod)
16+
cacheOptions.SyncPeriod = &cfg.CacheSyncPeriod
17+
}
18+
19+
// If there are no configured watch namespaces, then we're watching ALL namespaces,
20+
// and we don't have to bother individually caching any particular namespaces.
21+
// This is the default behavior of the controller-runtime manager.
22+
// If there are configured watch namespaces, then we're watching only those namespaces.
23+
if len(cfg.WatchNamespaces) > 0 {
24+
l.Info("Manager set up with multiple namespaces", "namespaces", cfg.WatchNamespaces)
25+
watched := make(map[string]cache.Config)
26+
for _, ns := range cfg.WatchNamespaces {
27+
watched[ns] = cache.Config{}
28+
}
29+
cacheOptions.DefaultNamespaces = watched
30+
}
31+
32+
cacheByObject, err := createCacheByObject(cfg)
33+
if err != nil {
34+
return cacheOptions, fmt.Errorf("failed to create cache options: %w", err)
35+
}
36+
cacheOptions.ByObject = cacheByObject
37+
38+
return cacheOptions, nil
39+
}
40+
41+
func createCacheByObject(cfg Config) (map[client.Object]cache.ByObject, error) {
42+
if cfg.ConfigMapLabelSelector == "" && cfg.SecretLabelSelector == "" {
43+
return nil, nil
44+
}
45+
byObject := map[client.Object]cache.ByObject{}
46+
if cfg.SecretLabelSelector != "" {
47+
if err := setByObjectFor[corev1.Secret](cfg.SecretLabelSelector, byObject); err != nil {
48+
return nil, fmt.Errorf("failed to set byObject for Secrets: %w", err)
49+
}
50+
}
51+
if cfg.ConfigMapLabelSelector != "" {
52+
if err := setByObjectFor[corev1.ConfigMap](cfg.ConfigMapLabelSelector, byObject); err != nil {
53+
return nil, fmt.Errorf("failed to set byObject for ConfigMaps: %w", err)
54+
}
55+
}
56+
57+
return byObject, nil
58+
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
package manager
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/require"
7+
corev1 "k8s.io/api/core/v1"
8+
)
9+
10+
func TestCreateCacheByObject(t *testing.T) {
11+
tests := []struct {
12+
name string
13+
cfg Config
14+
expectError bool
15+
expectNil bool
16+
expectedConfigMapLabel string
17+
expectedSecretLabel string
18+
}{
19+
{
20+
name: "no label selectors returns nil",
21+
cfg: Config{
22+
ConfigMapLabelSelector: "",
23+
SecretLabelSelector: "",
24+
},
25+
expectError: false,
26+
expectNil: true,
27+
},
28+
{
29+
name: "only secret label selector",
30+
cfg: Config{
31+
SecretLabelSelector: "app",
32+
},
33+
expectError: false,
34+
expectNil: false,
35+
expectedSecretLabel: "app",
36+
},
37+
{
38+
name: "only configmap label selector",
39+
cfg: Config{
40+
ConfigMapLabelSelector: "configmap.konghq.com",
41+
},
42+
expectError: false,
43+
expectNil: false,
44+
expectedConfigMapLabel: "configmap.konghq.com",
45+
},
46+
{
47+
name: "both label selectors",
48+
cfg: Config{
49+
ConfigMapLabelSelector: "configmap.konghq.com",
50+
SecretLabelSelector: "app",
51+
},
52+
expectError: false,
53+
expectNil: false,
54+
expectedConfigMapLabel: "configmap.konghq.com",
55+
expectedSecretLabel: "app",
56+
},
57+
{
58+
name: "invalid secret label selector",
59+
cfg: Config{
60+
SecretLabelSelector: "invalid==label",
61+
},
62+
expectError: true,
63+
},
64+
{
65+
name: "invalid configmap label selector",
66+
cfg: Config{
67+
ConfigMapLabelSelector: "invalid==label",
68+
},
69+
expectError: true,
70+
},
71+
}
72+
73+
for _, tt := range tests {
74+
t.Run(tt.name, func(t *testing.T) {
75+
result, err := createCacheByObject(tt.cfg)
76+
77+
if tt.expectError {
78+
require.Error(t, err)
79+
return
80+
}
81+
82+
require.NoError(t, err)
83+
84+
if tt.expectNil {
85+
require.Nil(t, result)
86+
return
87+
}
88+
89+
require.NotNil(t, result)
90+
91+
if tt.expectedSecretLabel != "" {
92+
for obj, v := range result {
93+
if _, ok := obj.(*corev1.Secret); ok {
94+
r, _ := v.Label.Requirements()
95+
require.Len(t, r, 1)
96+
require.Equal(t, tt.expectedSecretLabel, r[0].Key())
97+
}
98+
}
99+
}
100+
101+
if tt.expectedConfigMapLabel != "" {
102+
for obj, v := range result {
103+
if _, ok := obj.(*corev1.ConfigMap); ok {
104+
r, _ := v.Label.Requirements()
105+
require.Len(t, r, 1)
106+
require.Equal(t, tt.expectedConfigMapLabel, r[0].Key())
107+
}
108+
}
109+
}
110+
})
111+
}
112+
}

modules/manager/run.go

Lines changed: 3 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -205,33 +205,9 @@ func Run(
205205
return err
206206
}
207207

208-
var cacheOptions cache.Options
209-
if cfg.CacheSyncPeriod > 0 {
210-
setupLog.Info("cache sync period set", "period", cfg.CacheSyncPeriod)
211-
cacheOptions.SyncPeriod = &cfg.CacheSyncPeriod
212-
}
213-
214-
// If there are no configured watch namespaces, then we're watching ALL namespaces,
215-
// and we don't have to bother individually caching any particular namespaces.
216-
// This is the default behavior of the controller-runtime manager.
217-
// If there are configured watch namespaces, then we're watching only those namespaces.
218-
if len(cfg.WatchNamespaces) > 0 {
219-
setupLog.Info("Manager set up with multiple namespaces", "namespaces", cfg.WatchNamespaces)
220-
watched := make(map[string]cache.Config)
221-
for _, ns := range cfg.WatchNamespaces {
222-
watched[ns] = cache.Config{}
223-
}
224-
cacheOptions.DefaultNamespaces = watched
225-
}
226-
227-
if cfg.ConfigMapLabelSelector != "" || cfg.SecretLabelSelector != "" {
228-
cacheOptions.ByObject = map[client.Object]cache.ByObject{}
229-
if err := setByObjectFor[corev1.Secret](cfg.SecretLabelSelector, cacheOptions.ByObject); err != nil {
230-
return fmt.Errorf("failed to set byObject for Secrets: %w", err)
231-
}
232-
if err := setByObjectFor[corev1.ConfigMap](cfg.ConfigMapLabelSelector, cacheOptions.ByObject); err != nil {
233-
return fmt.Errorf("failed to set byObject for ConfigMaps: %w", err)
234-
}
208+
cacheOptions, err := createCacheOptions(setupLog, cfg)
209+
if err != nil {
210+
return fmt.Errorf("failed to create cache options: %w", err)
235211
}
236212

237213
managerOpts := ctrl.Options{

0 commit comments

Comments
 (0)