Skip to content

Commit bcd3551

Browse files
authored
Merge pull request fluxcd#325 from fluxcd/label-selector
Add LabelSelectors for Event Sources
2 parents bf33786 + 519b6a5 commit bcd3551

File tree

10 files changed

+244
-71
lines changed

10 files changed

+244
-71
lines changed

api/v1beta1/reference_types.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,10 @@ type CrossNamespaceObjectReference struct {
4040
// +kubebuilder:validation:Optional
4141
// +optional
4242
Namespace string `json:"namespace,omitempty"`
43+
44+
// MatchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
45+
// map is equivalent to an element of matchExpressions, whose key field is "key", the
46+
// operator is "In", and the values array contains only "value". The requirements are ANDed.
47+
// +optional
48+
MatchLabels map[string]string `json:"matchLabels,omitempty"`
4349
}

api/v1beta1/zz_generated.deepcopy.go

Lines changed: 13 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/crd/bases/notification.toolkit.fluxcd.io_alerts.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,15 @@ spec:
7777
- ImagePolicy
7878
- ImageUpdateAutomation
7979
type: string
80+
matchLabels:
81+
additionalProperties:
82+
type: string
83+
description: MatchLabels is a map of {key,value} pairs. A single
84+
{key,value} in the matchLabels map is equivalent to an element
85+
of matchExpressions, whose key field is "key", the operator
86+
is "In", and the values array contains only "value". The requirements
87+
are ANDed.
88+
type: object
8089
name:
8190
description: Name of the referent
8291
maxLength: 53

config/crd/bases/notification.toolkit.fluxcd.io_receivers.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,15 @@ spec:
7474
- ImagePolicy
7575
- ImageUpdateAutomation
7676
type: string
77+
matchLabels:
78+
additionalProperties:
79+
type: string
80+
description: MatchLabels is a map of {key,value} pairs. A single
81+
{key,value} in the matchLabels map is equivalent to an element
82+
of matchExpressions, whose key field is "key", the operator
83+
is "In", and the values array contains only "value". The requirements
84+
are ANDed.
85+
type: object
7786
name:
7887
description: Name of the referent
7988
maxLength: 53

controllers/event_handling_test.go

Lines changed: 110 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"testing"
1111
"time"
1212

13+
"github.com/fluxcd/pkg/ssa"
1314
. "github.com/onsi/gomega"
1415
"github.com/sethvargo/go-limiter/memorystore"
1516
prommetrics "github.com/slok/go-http-metrics/metrics/prometheus"
@@ -78,6 +79,22 @@ func TestEventHandler(t *testing.T) {
7879
}
7980
g.Expect(k8sClient.Create(context.Background(), provider)).To(Succeed())
8081

82+
repo, err := readManifest("./testdata/repo.yaml", namespace)
83+
g.Expect(err).ToNot(HaveOccurred())
84+
85+
secondRepo, err := readManifest("./testdata/gitrepo2.yaml", namespace)
86+
g.Expect(err).ToNot(HaveOccurred())
87+
88+
_, err = manager.Apply(context.Background(), repo, ssa.ApplyOptions{
89+
Force: true,
90+
})
91+
g.Expect(err).ToNot(HaveOccurred())
92+
93+
_, err = manager.Apply(context.Background(), secondRepo, ssa.ApplyOptions{
94+
Force: true,
95+
})
96+
g.Expect(err).ToNot(HaveOccurred())
97+
8198
alertKey := types.NamespacedName{
8299
Name: fmt.Sprintf("alert-%s", randStringRunes(5)),
83100
Namespace: namespace,
@@ -103,6 +120,13 @@ func TestEventHandler(t *testing.T) {
103120
Kind: "Kustomization",
104121
Name: "*",
105122
},
123+
{
124+
Kind: "GitRepository",
125+
Name: "*",
126+
MatchLabels: map[string]string{
127+
"app": "podinfo",
128+
},
129+
},
106130
{
107131
Kind: "Kustomization",
108132
Name: "*",
@@ -163,74 +187,98 @@ func TestEventHandler(t *testing.T) {
163187
}, "1s", "0.1s").Should(BeTrue())
164188
}
165189

166-
t.Run("event forwarding", func(t *testing.T) {
167-
tests := []struct {
168-
name string
169-
modifyEventFunc func(e events.Event) events.Event
170-
forwarded bool
171-
}{
172-
{
173-
name: "forwards when source is a match",
174-
modifyEventFunc: func(e events.Event) events.Event { return e },
175-
forwarded: true,
190+
tests := []struct {
191+
name string
192+
modifyEventFunc func(e events.Event) events.Event
193+
forwarded bool
194+
}{
195+
{
196+
name: "forwards when source is a match",
197+
modifyEventFunc: func(e events.Event) events.Event { return e },
198+
forwarded: true,
199+
},
200+
{
201+
name: "drops event when source Kind does not match",
202+
modifyEventFunc: func(e events.Event) events.Event {
203+
e.InvolvedObject.Kind = "GitRepository"
204+
return e
176205
},
177-
{
178-
name: "drops event when source Kind does not match",
179-
modifyEventFunc: func(e events.Event) events.Event {
180-
e.InvolvedObject.Kind = "GitRepository"
181-
return e
182-
},
183-
forwarded: false,
206+
forwarded: false,
207+
},
208+
{
209+
name: "drops event when source name does not match",
210+
modifyEventFunc: func(e events.Event) events.Event {
211+
e.InvolvedObject.Name = "slop"
212+
return e
184213
},
185-
{
186-
name: "drops event when source name does not match",
187-
modifyEventFunc: func(e events.Event) events.Event {
188-
e.InvolvedObject.Name = "slop"
189-
return e
190-
},
191-
forwarded: false,
214+
forwarded: false,
215+
},
216+
{
217+
name: "drops event when source namespace does not match",
218+
modifyEventFunc: func(e events.Event) events.Event {
219+
e.InvolvedObject.Namespace = "all-buckets"
220+
return e
192221
},
193-
{
194-
name: "drops event when source namespace does not match",
195-
modifyEventFunc: func(e events.Event) events.Event {
196-
e.InvolvedObject.Namespace = "all-buckets"
197-
return e
198-
},
199-
forwarded: false,
222+
forwarded: false,
223+
},
224+
{
225+
name: "drops event that is matched by exclusion",
226+
modifyEventFunc: func(e events.Event) events.Event {
227+
e.Message = "this is excluded"
228+
return e
200229
},
201-
{
202-
name: "drops event that is matched by exclusion",
203-
modifyEventFunc: func(e events.Event) events.Event {
204-
e.Message = "this is excluded"
205-
return e
206-
},
207-
forwarded: false,
230+
forwarded: false,
231+
},
232+
{
233+
name: "forwards events when name wildcard is used",
234+
modifyEventFunc: func(e events.Event) events.Event {
235+
e.InvolvedObject.Kind = "Kustomization"
236+
e.InvolvedObject.Name = "test"
237+
e.InvolvedObject.Namespace = namespace
238+
e.Message = "test"
239+
return e
208240
},
209-
{
210-
name: "forwards events when name wildcard is used",
211-
modifyEventFunc: func(e events.Event) events.Event {
212-
e.InvolvedObject.Kind = "Kustomization"
213-
e.InvolvedObject.Name = "test"
214-
e.InvolvedObject.Namespace = namespace
215-
e.Message = "test"
216-
return e
217-
},
218-
forwarded: true,
241+
forwarded: true,
242+
},
243+
{
244+
name: "forwards events when the label matches",
245+
modifyEventFunc: func(e events.Event) events.Event {
246+
e.InvolvedObject.Kind = "GitRepository"
247+
e.InvolvedObject.Name = "podinfo"
248+
e.InvolvedObject.APIVersion = "source.toolkit.fluxcd.io/v1beta1"
249+
e.InvolvedObject.Namespace = namespace
250+
e.Message = "test"
251+
return e
219252
},
220-
{
221-
name: "drops events for cross-namespace sources",
222-
modifyEventFunc: func(e events.Event) events.Event {
223-
e.InvolvedObject.Kind = "Kustomization"
224-
e.InvolvedObject.Name = "test"
225-
e.InvolvedObject.Namespace = "test"
226-
e.Message = "test"
227-
return e
228-
},
229-
forwarded: false,
253+
forwarded: true,
254+
},
255+
{
256+
name: "drops events when the labels don't match",
257+
modifyEventFunc: func(e events.Event) events.Event {
258+
e.InvolvedObject.Kind = "GitRepository"
259+
e.InvolvedObject.Name = "podinfo-two"
260+
e.InvolvedObject.APIVersion = "source.toolkit.fluxcd.io/v1beta1"
261+
e.InvolvedObject.Namespace = namespace
262+
e.Message = "test"
263+
return e
264+
},
265+
forwarded: false,
266+
},
267+
{
268+
name: "drops events for cross-namespace sources",
269+
modifyEventFunc: func(e events.Event) events.Event {
270+
e.InvolvedObject.Kind = "Kustomization"
271+
e.InvolvedObject.Name = "test"
272+
e.InvolvedObject.Namespace = "test"
273+
e.Message = "test"
274+
return e
230275
},
231-
}
276+
forwarded: false,
277+
},
278+
}
232279

233-
for _, tt := range tests {
280+
for _, tt := range tests {
281+
t.Run(tt.name, func(t *testing.T) {
234282
event = tt.modifyEventFunc(event)
235283
testSent()
236284
if tt.forwarded {
@@ -239,6 +287,6 @@ func TestEventHandler(t *testing.T) {
239287
testFiltered()
240288
}
241289
req = nil
242-
}
243-
})
290+
})
291+
}
244292
}

controllers/testdata/gitrepo2.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
apiVersion: source.toolkit.fluxcd.io/v1beta1
3+
kind: GitRepository
4+
metadata:
5+
name: podinfo-two
6+
namespace: "%[1]s"
7+
labels:
8+
app: podinfo-two
9+
spec:
10+
interval: 1m
11+
url: https://github.com/stefanprodan/podinfo
12+
ref:
13+
semver: 6.0.x

controllers/testdata/repo.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ kind: GitRepository
44
metadata:
55
name: podinfo
66
namespace: "%[1]s"
7+
labels:
8+
app: podinfo
79
spec:
810
interval: 1m
911
url: https://github.com/stefanprodan/podinfo

docs/api/notification.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -694,6 +694,20 @@ string
694694
<p>Namespace of the referent</p>
695695
</td>
696696
</tr>
697+
<tr>
698+
<td>
699+
<code>matchLabels</code><br>
700+
<em>
701+
map[string]string
702+
</em>
703+
</td>
704+
<td>
705+
<em>(Optional)</em>
706+
<p>MatchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
707+
map is equivalent to an element of matchExpressions, whose key field is &ldquo;key&rdquo;, the
708+
operator is &ldquo;In&rdquo;, and the values array contains only &ldquo;value&rdquo;. The requirements are ANDed.</p>
709+
</td>
710+
</tr>
697711
</tbody>
698712
</table>
699713
</div>

docs/spec/v1beta1/alert.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,28 @@ spec:
100100
suspend: false
101101
```
102102

103+
You can target resources with a particular set of labels using `spec.EventSource[].matchLabels`.
104+
It is only possible when the name of the event source is set to a wildcard `*`.
105+
106+
```yaml
107+
apiVersion: notification.toolkit.fluxcd.io/v1beta1
108+
kind: Alert
109+
metadata:
110+
name: dev-kustomizations
111+
namespace: default
112+
spec:
113+
providerRef:
114+
name: dev-msteams
115+
eventSeverity: error
116+
eventSources:
117+
- kind: Kustomization
118+
namespace: default
119+
name: '*'
120+
matchLabels:
121+
app: dev
122+
suspend: false
123+
```
124+
103125
If you don't specify an event source namespace, the alert namespace will be used.
104126

105127
> **Note** that on multi-tenant clusters, platform admins can disable cross-namespace references

0 commit comments

Comments
 (0)