Compare commits
550 Commits
Author | SHA1 | Date |
---|---|---|
|
a22d67edbb | |
|
955d24142c | |
|
e8a909fac7 | |
|
febff88be7 | |
|
5bea87e16b | |
|
a8c2fc0759 | |
|
6e18c487d7 | |
|
d1c85df902 | |
|
9e150256c7 | |
|
e4160c509c | |
|
fc4adfd030 | |
|
3f4e962c83 | |
|
98ecf2de79 | |
|
a3e6dd6a10 | |
|
8858332c27 | |
|
2503bda903 | |
|
fc126284ab | |
|
8f207d65db | |
|
61f24e3376 | |
|
3f4ba79594 | |
|
d65c81d035 | |
|
47b95d86a3 | |
|
3a6de1fcef | |
|
a52f071bb9 | |
|
0e0e912182 | |
|
7383fe8be5 | |
|
2284a0db5a | |
|
d32f5e26cc | |
|
b416d68479 | |
|
3842f0c471 | |
|
f2e2340807 | |
|
01dfe1208a | |
|
0464717037 | |
|
f3065c67b3 | |
|
882383e44c | |
|
8dd496a132 | |
|
de484cd447 | |
|
b906831c5e | |
|
e95f8d5b38 | |
|
d78779e80b | |
|
637d55d0b9 | |
|
99c6dbb70f | |
|
c32f9e1559 | |
|
f5ddc97108 | |
|
0beb3d02f7 | |
|
5dfaa1a5ef | |
|
4d3a53ac86 | |
|
5b72532bb1 | |
|
3f7486168e | |
|
e970526b1e | |
|
0338a311f4 | |
|
671f7dd377 | |
|
fdeab17bff | |
|
f313afa287 | |
|
30d8d01687 | |
|
d62be26a3f | |
|
bc7166d419 | |
|
c476965793 | |
|
1a9858d725 | |
|
e2eac40c33 | |
|
1967bc0c74 | |
|
2763e548bd | |
|
cc51c36926 | |
|
543a2b0da2 | |
|
85d897c59d | |
|
ff00d11dae | |
|
2b3ccd7ddf | |
|
384ae9889f | |
|
2295fcf8e2 | |
|
b64453ba2f | |
|
3dc0b66390 | |
|
022b97cabe | |
|
7a34aee2bd | |
|
7e14e41f0f | |
|
b72ecab696 | |
|
5df5b78783 | |
|
c4eed6b243 | |
|
83ed0c59e5 | |
|
d52c41e0c4 | |
|
652d3d331e | |
|
232e66c985 | |
|
2eb3c35ec3 | |
|
28deef923f | |
|
9b83efa21f | |
|
e68bc3b7e3 | |
|
f4001109db | |
|
ed7f6adac6 | |
|
dcbf4a7f73 | |
|
b7cef8af24 | |
|
1aea3c2275 | |
|
7b8535bce0 | |
|
d9bb201c36 | |
|
764123c6d3 | |
|
7ee7239ff3 | |
|
b362a258fe | |
|
8235026aa1 | |
|
ecc3395615 | |
|
fa7d9f260c | |
|
9dc18128c8 | |
|
a2eb8ea3be | |
|
e0b98ca519 | |
|
5469e2a1f0 | |
|
56c5a5a4bc | |
|
d455ac69fe | |
|
939a16620f | |
|
51db46dfee | |
|
f3438f7709 | |
|
8b1d9a1e0b | |
|
a27f00191a | |
|
0667ba6629 | |
|
fb2adadc43 | |
|
276511a10a | |
|
effda518f4 | |
|
632437c78e | |
|
e7a4503e51 | |
|
2ebbf4803a | |
|
b6bdd3c2ce | |
|
278fd67d9a | |
|
2525f2ce4e | |
|
52a4049be2 | |
|
6fcfb6337c | |
|
c43e6a93a6 | |
|
b2ab2c2b07 | |
|
3acbe68075 | |
|
4997635afa | |
|
b4a9933f59 | |
|
519248ff29 | |
|
05be0bd5a1 | |
|
3585b77c40 | |
|
edb88c62fb | |
|
7d279b98f5 | |
|
7407570bee | |
|
46813c05b9 | |
|
7c15798aaa | |
|
205cd17fb0 | |
|
e0cf7a1fc7 | |
|
b81755d3f3 | |
|
c85b1eb391 | |
|
ab58c812bd | |
|
0871ad710a | |
|
42c2c79d2b | |
|
117bc7a91d | |
|
e6c53a0ae2 | |
|
478718ee48 | |
|
7373cf4b62 | |
|
d20a810652 | |
|
bd12728d0f | |
|
4e01193860 | |
|
f9610afa8d | |
|
fa93b71722 | |
|
1f4cdff23c | |
|
86f2a6d20f | |
|
fd2df2cffe | |
|
48675f2426 | |
|
86b33d0f3c | |
|
d9216e5c58 | |
|
84b8c037e9 | |
|
39f345231f | |
|
9c4d43f32a | |
|
a1cf5e0d43 | |
|
e70166d5e3 | |
|
0f8ff3c0d8 | |
|
b6037078a3 | |
|
5572c7fa04 | |
|
ef7db0026b | |
|
7adf4f2c41 | |
|
c518265dae | |
|
6240b16776 | |
|
3ae80f6475 | |
|
219f86fd11 | |
|
129f60e6e6 | |
|
580497beeb | |
|
f4e8df6360 | |
|
eb62655b73 | |
|
e0a1f00358 | |
|
a8f81b3a00 | |
|
696f065673 | |
|
1b5dbd997a | |
|
5bfdcc04fc | |
|
5f0f561ac0 | |
|
9a948c7290 | |
|
b2c799203d | |
|
05abe0a9de | |
|
3aba5bbd39 | |
|
35e2a0ebc0 | |
|
fd635f7dff | |
|
838514c874 | |
|
b7b9a018e8 | |
|
c4835fbdbd | |
|
3407bf5486 | |
|
6d7913063d | |
|
531c5873e7 | |
|
cf2f554c11 | |
|
d29f5f4919 | |
|
f9c93e2952 | |
|
f5026a7443 | |
|
678f374bc3 | |
|
633e33bf4b | |
|
f22dd2bfff | |
|
94ce6da0f2 | |
|
0bea894c2e | |
|
857c11dd26 | |
|
2bac104a69 | |
|
e3ae7c2d48 | |
|
952ccd000f | |
|
0106b53e02 | |
|
6ba1a713fe | |
|
c6b89cd2d6 | |
|
e30844fe7b | |
|
1fa1e28e33 | |
|
cb595180b1 | |
|
7659221a4a | |
|
08e74d5209 | |
|
17adf69aeb | |
|
b4949b6e05 | |
|
20eee15786 | |
|
bf918b9b3c | |
|
440aad84b0 | |
|
c2302f8fed | |
|
cd529f5588 | |
|
aef940033c | |
|
34a9099884 | |
|
e73db32382 | |
|
b3e4bf2ad5 | |
|
bd242e091c | |
|
36a83074f2 | |
|
eceae7774f | |
|
edb771fa6c | |
|
ee50f74164 | |
|
6dafac748f | |
|
333e6c3d07 | |
|
32c59b2474 | |
|
681ad49b98 | |
|
4e8bb2e4d5 | |
|
8cedefd341 | |
|
5ed66321a9 | |
|
f325f774d8 | |
|
bba04db89d | |
|
c71a90e01a | |
|
56120e9afc | |
|
f455608bfd | |
|
b816076657 | |
|
f5c0f6d33b | |
|
d72c7df6a5 | |
|
b4deeb98be | |
|
4df3ce451a | |
|
70b93d3f3d | |
|
ec61423cc5 | |
|
5371d8a79d | |
|
071bf10fa3 | |
|
d29d1f0804 | |
|
0d39d277d2 | |
|
c368adbbcc | |
|
69dfee9318 | |
|
e7a241d777 | |
|
8ce32f9553 | |
|
dcabd7c42b | |
|
5b152f583d | |
|
0b48a065e3 | |
|
a88f97eb44 | |
|
0bb0c6041c | |
|
6ae9bb6fa7 | |
|
f9933507d0 | |
|
20423eb80a | |
|
a817cf91c1 | |
|
68c38244cc | |
|
7834608f77 | |
|
7f5eea0a2e | |
|
73e1965419 | |
|
143a0b3ee0 | |
|
e48be82c89 | |
|
2a8ab214c9 | |
|
ef5c602fb1 | |
|
74bd37a992 | |
|
52da6c48ca | |
|
879f9576e2 | |
|
6ffb5f3f70 | |
|
40ba471d6b | |
|
791d34ef46 | |
|
57c32c15be | |
|
9492ef1b96 | |
|
b007f42139 | |
|
9f90225f04 | |
|
39a3853c5c | |
|
cd51b02fdd | |
|
c857eb65b3 | |
|
46d54b024d | |
|
c8d287e9c3 | |
|
f045217d70 | |
|
5acc9a12a8 | |
|
f4f6cdc73b | |
|
42870e46ce | |
|
fe333842be | |
|
29fb291738 | |
|
5500739269 | |
|
998cec97b8 | |
|
832757c139 | |
|
b732427a7a | |
|
bf58d33bd0 | |
|
3c05438d62 | |
|
427d20046e | |
|
6e1ccfe653 | |
|
52d8945284 | |
|
78f5509fe7 | |
|
6df2c74b2a | |
|
9a5debde32 | |
|
b2e533af67 | |
|
b99de58dd3 | |
|
84e1d74e32 | |
|
19a60e98ea | |
|
80f7237673 | |
|
36bc6529ae | |
|
4bf469e61b | |
|
c52522bd8b | |
|
7ad92b51de | |
|
26ddbbd726 | |
|
49d510de81 | |
|
9869e395fe | |
|
504dc991cc | |
|
e425a6e307 | |
|
603c48fbbe | |
|
9549ebfc07 | |
|
da52599998 | |
|
5d8924a319 | |
|
0377782fe6 | |
|
f4a050871e | |
|
341a819d65 | |
|
968ab5ee3c | |
|
3087c0e291 | |
|
38a8562b63 | |
|
15efcb55b6 | |
|
820fe53ce7 | |
|
c51ac08026 | |
|
c64d76801a | |
|
4c5c0eadd7 | |
|
56facfa96b | |
|
3dce75a07e | |
|
edb6a54e23 | |
|
bdda58062f | |
|
16fb90ed84 | |
|
23d57eb9d3 | |
|
30db06d0df | |
|
7d6dc52fdb | |
|
dab1c00a2a | |
|
8c67c1e473 | |
|
e0c88e9bb1 | |
|
60e2525330 | |
|
823c76342b | |
|
e333d95872 | |
|
9c0fcac72c | |
|
0b4eee1446 | |
|
4137ce50c4 | |
|
795a9db0f3 | |
|
61137e5eeb | |
|
4735dc5578 | |
|
c6b1ef67a3 | |
|
ec834ff3ae | |
|
c33b88d946 | |
|
bb8cfd3ead | |
|
7de11b33d9 | |
|
441ce1d9ee | |
|
6a27f537e1 | |
|
c04ad842fc | |
|
23e733b9c7 | |
|
1ce7d99dad | |
|
6b9c0bdf7d | |
|
d353de4f74 | |
|
f8cba731d2 | |
|
3a34275307 | |
|
2a56e4e30e | |
|
e760ef2080 | |
|
71ed90ee8c | |
|
049ded50b9 | |
|
72c5b1fc6e | |
|
ec10ba84fe | |
|
bebf461de3 | |
|
96037fc899 | |
|
6510b70412 | |
|
d99428c7dd | |
|
9dc7e129b9 | |
|
447c938d16 | |
|
9f0c112b3d | |
|
0f62755bc9 | |
|
6a07c3fa0f | |
|
e1d3a59b5a | |
|
16605cb55c | |
|
4f5d2dfdb8 | |
|
04fbfaeb6c | |
|
002474c3d5 | |
|
8c7ff2169e | |
|
926efbc120 | |
|
a786a4866e | |
|
937da68766 | |
|
b80c2c4060 | |
|
8cb4eab874 | |
|
0c3408bbd0 | |
|
1a3ce97ee6 | |
|
3c4c5d5244 | |
|
c65fdd0f84 | |
|
7a211dd4f9 | |
|
3f75068a06 | |
|
4731f44e94 | |
|
2671a73bab | |
|
03f72410e8 | |
|
092d3d3f20 | |
|
a77613619d | |
|
7cecd3d2c4 | |
|
bf960d1582 | |
|
8f11af7167 | |
|
13b2236bb2 | |
|
0f21d59f26 | |
|
4dd70490b2 | |
|
13d3d8f9ee | |
|
c6b83623c1 | |
|
e45f43a01f | |
|
223666dc47 | |
|
cbdc4acdf5 | |
|
364eace4ec | |
|
21abdab841 | |
|
213ceaa047 | |
|
226571ca7e | |
|
b71140b164 | |
|
4a90bebc11 | |
|
1cc1bce1c5 | |
|
e4284dcd5f | |
|
061ea8166d | |
|
b4233b1b76 | |
|
dbdc4dee73 | |
|
01de1f7033 | |
|
749a6c4cb7 | |
|
9566e80d91 | |
|
a9f613ecfa | |
|
671ca98087 | |
|
48b7e6325b | |
|
b45fb81120 | |
|
b208a820af | |
|
a6a5970935 | |
|
39b504b196 | |
|
52a0f6ae23 | |
|
5a74c753e6 | |
|
46a504c36f | |
|
e33e7b6333 | |
|
a1711b6de6 | |
|
9b508abc2f | |
|
aa358fe680 | |
|
61cd4d0365 | |
|
ac9b203638 | |
|
605b42dcae | |
|
4343908a70 | |
|
1e851d47fa | |
|
508e8f13b2 | |
|
04cea9d51e | |
|
9ec2696bf0 | |
|
bd1c659ffb | |
|
3944f2ea50 | |
|
ae6cc4b4f6 | |
|
189755192c | |
|
827c634c1e | |
|
9717b09617 | |
|
e43e2f2a91 | |
|
cd407645dd | |
|
df773afef0 | |
|
25a8cd0db1 | |
|
51043241cb | |
|
ac51165090 | |
|
d3cc2f6911 | |
|
56a77b73c2 | |
|
4c1978bc73 | |
|
6af6b15ad2 | |
|
bfed8d6d0a | |
|
94cd2a6a8f | |
|
1571308a3a | |
|
f20e2b704e | |
|
51e4ae98a3 | |
|
5ef19dc26e | |
|
f1fc135ffa | |
|
3aa030f366 | |
|
7043ca4d8c | |
|
8e823b02bb | |
|
d8988a23bc | |
|
3581abc4a6 | |
|
b7cccbee81 | |
|
639d66d330 | |
|
8c11d8a19b | |
|
d8254c39cb | |
|
4e05bc8ee2 | |
|
97b4bc4e9f | |
|
0337f50d34 | |
|
963b3da8a7 | |
|
52196f39e4 | |
|
24b84e29b6 | |
|
dcb5d0af46 | |
|
dde2def52c | |
|
49122b90b1 | |
|
5eff905b8e | |
|
ffb901d7d4 | |
|
8548a6db36 | |
|
81be272c10 | |
|
461688bd56 | |
|
a8af5647e8 | |
|
e9d1fb3d86 | |
|
ed5b2fe266 | |
|
6c171a6421 | |
|
72d2eafdd9 | |
|
c6e2948bb9 | |
|
13081a2602 | |
|
d3c2d87e8b | |
|
73499fb6a4 | |
|
7e678487c2 | |
|
88e2cf0e8b | |
|
8ece31da39 | |
|
13fe515890 | |
|
4effb1542d | |
|
00fab6693b | |
|
f798c7638f | |
|
9b7a80942f | |
|
18c49ad361 | |
|
24509ce458 | |
|
4b32bfd8d3 | |
|
69f7ddbcc4 | |
|
2ad774cf8a | |
|
0af806c492 | |
|
0c0109a4bd | |
|
75b1cc109f | |
|
a5fe4c1a8f | |
|
dbeb5a3241 | |
|
ec03bd20a3 | |
|
0863edc6e6 | |
|
e7c8c7b6a8 | |
|
f8ab99e080 | |
|
ef8c97323e | |
|
4fcde0026d | |
|
c32fed1c67 | |
|
abc4991505 | |
|
57f62f400c | |
|
36bf7456ba | |
|
0f4f23739e | |
|
49a0e46e67 | |
|
755a4f2550 | |
|
44483c3904 | |
|
fddd3d6fda | |
|
8299ed926a | |
|
24555c6f25 | |
|
c5baac49cf | |
|
7372581bc3 | |
|
8050564018 | |
|
d8d71b0cb0 | |
|
bfa7d5e139 | |
|
ad9b54e812 | |
|
109b4a4fab |
|
@ -0,0 +1,30 @@
|
|||
version: 2
|
||||
|
||||
updates:
|
||||
- package-ecosystem: "gomod"
|
||||
directory: "/"
|
||||
labels: ["dependencies"]
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
groups:
|
||||
go-deps:
|
||||
patterns:
|
||||
- "*"
|
||||
allow:
|
||||
- dependency-type: "direct"
|
||||
ignore:
|
||||
# Kubernetes deps are updated by fluxcd/pkg
|
||||
- dependency-name: "k8s.io/*"
|
||||
- dependency-name: "sigs.k8s.io/*"
|
||||
- dependency-name: "github.com/go-logr/*"
|
||||
# Flux APIs pkg are updated at release time
|
||||
- dependency-name: "github.com/fluxcd/notification-controller/api"
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
labels: ["area/ci", "dependencies"]
|
||||
groups:
|
||||
ci:
|
||||
patterns:
|
||||
- "*"
|
||||
schedule:
|
||||
interval: "monthly"
|
|
@ -0,0 +1,30 @@
|
|||
# Configuration file to declaratively configure labels
|
||||
# Ref: https://github.com/EndBug/label-sync#Config-files
|
||||
|
||||
- name: area/alerting
|
||||
description: Alerting related issues and PRs
|
||||
color: '#93edcf'
|
||||
- name: area/receiver
|
||||
description: Webhook receiver related issues and PRs
|
||||
color: '#c5def5'
|
||||
- name: backport:release/v1.0.x
|
||||
description: To be backported to release/v1.0.x
|
||||
color: '#ffd700'
|
||||
- name: backport:release/v1.1.x
|
||||
description: To be backported to release/v1.1.x
|
||||
color: '#ffd700'
|
||||
- name: backport:release/v1.2.x
|
||||
description: To be backported to release/v1.2.x
|
||||
color: '#ffd700'
|
||||
- name: backport:release/v1.3.x
|
||||
description: To be backported to release/v1.3.x
|
||||
color: '#ffd700'
|
||||
- name: backport:release/v1.4.x
|
||||
description: To be backported to release/v1.4.x
|
||||
color: '#ffd700'
|
||||
- name: backport:release/v1.5.x
|
||||
description: To be backported to release/v1.5.x
|
||||
color: '#ffd700'
|
||||
- name: backport:release/v1.6.x
|
||||
description: To be backported to release/v1.6.x
|
||||
color: '#ffd700'
|
|
@ -0,0 +1,31 @@
|
|||
name: backport
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [closed, labeled]
|
||||
|
||||
jobs:
|
||||
pull-request:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
if: github.event.pull_request.state == 'closed' && github.event.pull_request.merged && (github.event_name != 'labeled' || startsWith('backport:', github.event.label.name))
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
- name: Create backport PRs
|
||||
uses: korthout/backport-action@436145e922f9561fc5ea157ff406f21af2d6b363 # v3.2.0
|
||||
# xref: https://github.com/korthout/backport-action#inputs
|
||||
with:
|
||||
# Use token to allow workflows to be triggered for the created PR
|
||||
github_token: ${{ secrets.BOT_GITHUB_TOKEN }}
|
||||
# Match labels with a pattern `backport:<target-branch>`
|
||||
label_pattern: '^backport:([^ ]+)$'
|
||||
# A bit shorter pull-request title than the default
|
||||
pull_title: '[${target_branch}] ${pull_title}'
|
||||
# Simpler PR description than default
|
||||
pull_description: |-
|
||||
Automated backport to `${target_branch}`, triggered by a label in #${pull_number}.
|
|
@ -1,8 +1,7 @@
|
|||
name: fuzz
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
branches: [ 'main', 'release/**' ]
|
||||
|
||||
permissions:
|
||||
contents: read # for actions/checkout to fetch code
|
||||
|
@ -11,21 +10,14 @@ jobs:
|
|||
smoketest:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: 1.19.x
|
||||
- id: go-env
|
||||
run: |
|
||||
echo "go-mod-cache=$(go env GOMODCACHE)" >> $GITHUB_OUTPUT
|
||||
- name: Restore Go cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{ steps.go-env.outputs.go-mod-cache }}
|
||||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-go
|
||||
- name: Smoke test Fuzzers
|
||||
run: make fuzz-smoketest
|
||||
- name: Checkout
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
|
||||
with:
|
||||
go-version: 1.24.x
|
||||
cache-dependency-path: |
|
||||
**/go.sum
|
||||
**/go.mod
|
||||
- name: Smoke test Fuzzers
|
||||
run: make fuzz-smoketest
|
||||
|
|
|
@ -2,8 +2,7 @@ name: e2e
|
|||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
branches: [ 'main', 'release/**' ]
|
||||
|
||||
permissions:
|
||||
contents: read # for actions/checkout to fetch code
|
||||
|
@ -13,25 +12,14 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- name: Setup QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
with:
|
||||
platforms: all
|
||||
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0
|
||||
- name: Setup Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
with:
|
||||
buildkitd-flags: "--debug"
|
||||
- name: Restore Go cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-go-
|
||||
uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0
|
||||
- name: Cache Docker layers
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
|
||||
id: cache
|
||||
with:
|
||||
path: /tmp/.buildx-cache
|
||||
|
@ -39,16 +27,18 @@ jobs:
|
|||
restore-keys: |
|
||||
${{ runner.os }}-buildx-ghcache-
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v3
|
||||
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
|
||||
with:
|
||||
go-version: 1.19.x
|
||||
go-version: 1.24.x
|
||||
cache-dependency-path: |
|
||||
**/go.sum
|
||||
**/go.mod
|
||||
- name: Setup Kubernetes
|
||||
uses: helm/kind-action@v1.5.0
|
||||
uses: helm/kind-action@a1b0e391336a6ee6713a0583f8c6240d70863de3 # v1.12.0
|
||||
with:
|
||||
version: v0.17.0
|
||||
cluster_name: kind
|
||||
- name: Setup Kustomize
|
||||
uses: fluxcd/pkg//actions/kustomize@main
|
||||
uses: fluxcd/pkg/actions/kustomize@main
|
||||
- name: Run tests
|
||||
run: make test
|
||||
- name: Check if working tree is dirty
|
||||
|
@ -79,7 +69,7 @@ jobs:
|
|||
- name: Run default status test
|
||||
run: |
|
||||
kubectl apply -f config/testdata/status-defaults
|
||||
for crd in alert provider receiver ; do
|
||||
for crd in receiver ; do
|
||||
RESULT=$(kubectl get ${crd} status-defaults -o go-template={{.status}})
|
||||
EXPECTED='map[observedGeneration:-1]'
|
||||
if [ "${RESULT}" != "${EXPECTED}" ] ; then
|
||||
|
@ -96,9 +86,6 @@ jobs:
|
|||
- name: Run smoke tests
|
||||
run: |
|
||||
kubectl -n notification-system apply -f ./config/samples
|
||||
kubectl -n notification-system wait provider/slack-provider-sample --for=condition=ready --timeout=1m
|
||||
kubectl -n notification-system wait provider/generic-provider-sample --for=condition=ready --timeout=1m
|
||||
kubectl -n notification-system wait alert/alert-sample --for=condition=ready --timeout=1m
|
||||
kubectl -n notification-system wait receiver/receiver-sample --for=condition=ready --timeout=1m
|
||||
- name: Logs
|
||||
run: |
|
||||
|
|
|
@ -7,22 +7,29 @@ on:
|
|||
inputs:
|
||||
tag:
|
||||
description: 'image tag prefix'
|
||||
default: 'rc'
|
||||
default: 'preview'
|
||||
required: true
|
||||
|
||||
permissions:
|
||||
contents: write # needed to write releases
|
||||
id-token: write # needed for keyless signing
|
||||
packages: write # needed for ghcr access
|
||||
contents: read
|
||||
|
||||
env:
|
||||
CONTROLLER: ${{ github.event.repository.name }}
|
||||
|
||||
jobs:
|
||||
build-push:
|
||||
release:
|
||||
outputs:
|
||||
hashes: ${{ steps.slsa.outputs.hashes }}
|
||||
image_url: ${{ steps.slsa.outputs.image_url }}
|
||||
image_digest: ${{ steps.slsa.outputs.image_digest }}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write # for creating the GitHub release.
|
||||
id-token: write # for creating OIDC tokens for signing.
|
||||
packages: write # for pushing and signing container images.
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Checkout
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- name: Setup Kustomize
|
||||
uses: fluxcd/pkg/actions/kustomize@main
|
||||
- name: Prepare
|
||||
|
@ -35,24 +42,24 @@ jobs:
|
|||
echo "BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_OUTPUT
|
||||
echo "VERSION=${VERSION}" >> $GITHUB_OUTPUT
|
||||
- name: Setup QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0
|
||||
- name: Setup Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: fluxcdbot
|
||||
password: ${{ secrets.GHCR_TOKEN }}
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
|
||||
with:
|
||||
username: fluxcdbot
|
||||
password: ${{ secrets.DOCKER_FLUXCD_PASSWORD }}
|
||||
- name: Generate images meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v4
|
||||
uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0
|
||||
with:
|
||||
images: |
|
||||
fluxcd/${{ env.CONTROLLER }}
|
||||
|
@ -60,7 +67,8 @@ jobs:
|
|||
tags: |
|
||||
type=raw,value=${{ steps.prep.outputs.VERSION }}
|
||||
- name: Publish images
|
||||
uses: docker/build-push-action@v3
|
||||
id: build-push
|
||||
uses: docker/build-push-action@1dc73863535b631f98b2378be8619f83b136f4a0 # v6.17.0
|
||||
with:
|
||||
sbom: true
|
||||
provenance: true
|
||||
|
@ -71,32 +79,82 @@ jobs:
|
|||
platforms: linux/amd64,linux/arm/v7,linux/arm64
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
- name: Check images
|
||||
run: |
|
||||
docker buildx imagetools inspect docker.io/fluxcd/${{ env.CONTROLLER }}:${{ steps.prep.outputs.VERSION }}
|
||||
docker buildx imagetools inspect ghcr.io/fluxcd/${{ env.CONTROLLER }}:${{ steps.prep.outputs.VERSION }}
|
||||
docker pull docker.io/fluxcd/${{ env.CONTROLLER }}:${{ steps.prep.outputs.VERSION }}
|
||||
docker pull ghcr.io/fluxcd/${{ env.CONTROLLER }}:${{ steps.prep.outputs.VERSION }}
|
||||
- uses: sigstore/cosign-installer@main
|
||||
- uses: sigstore/cosign-installer@3454372f43399081ed03b604cb2d021dabca52bb # v3.8.2
|
||||
- name: Sign images
|
||||
env:
|
||||
COSIGN_EXPERIMENTAL: 1
|
||||
run: |
|
||||
cosign sign fluxcd/${{ env.CONTROLLER }}:${{ steps.prep.outputs.VERSION }}
|
||||
cosign sign ghcr.io/fluxcd/${{ env.CONTROLLER }}:${{ steps.prep.outputs.VERSION }}
|
||||
cosign sign --yes fluxcd/${{ env.CONTROLLER }}@${{ steps.build-push.outputs.digest }}
|
||||
cosign sign --yes ghcr.io/fluxcd/${{ env.CONTROLLER }}@${{ steps.build-push.outputs.digest }}
|
||||
- name: Generate release artifacts
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
run: |
|
||||
mkdir -p config/release
|
||||
kustomize build ./config/crd > ./config/release/${{ env.CONTROLLER }}.crds.yaml
|
||||
kustomize build ./config/manager > ./config/release/${{ env.CONTROLLER }}.deployment.yaml
|
||||
echo '[CHANGELOG](https://github.com/fluxcd/${{ env.CONTROLLER }}/blob/main/CHANGELOG.md)' > ./config/release/notes.md
|
||||
- uses: anchore/sbom-action/download-syft@v0
|
||||
- uses: anchore/sbom-action/download-syft@e11c554f704a0b820cbf8c51673f6945e0731532 # v0.20.0
|
||||
- name: Create release and SBOM
|
||||
id: run-goreleaser
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
uses: goreleaser/goreleaser-action@v3
|
||||
uses: goreleaser/goreleaser-action@9c156ee8a17a598857849441385a2041ef570552 # v6.3.0
|
||||
with:
|
||||
version: latest
|
||||
args: release --release-notes=config/release/notes.md --rm-dist --skip-validate
|
||||
args: release --clean --skip=validate
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Generate SLSA metadata
|
||||
id: slsa
|
||||
env:
|
||||
ARTIFACTS: "${{ steps.run-goreleaser.outputs.artifacts }}"
|
||||
run: |
|
||||
hashes=$(echo -E $ARTIFACTS | jq --raw-output '.[] | {name, "digest": (.extra.Digest // .extra.Checksum)} | select(.digest) | {digest} + {name} | join(" ") | sub("^sha256:";"")' | base64 -w0)
|
||||
echo "hashes=$hashes" >> $GITHUB_OUTPUT
|
||||
|
||||
image_url=fluxcd/${{ env.CONTROLLER }}:${{ steps.prep.outputs.version }}
|
||||
echo "image_url=$image_url" >> $GITHUB_OUTPUT
|
||||
|
||||
image_digest=${{ steps.build-push.outputs.digest }}
|
||||
echo "image_digest=$image_digest" >> $GITHUB_OUTPUT
|
||||
|
||||
release-provenance:
|
||||
needs: [release]
|
||||
permissions:
|
||||
actions: read # for detecting the Github Actions environment.
|
||||
id-token: write # for creating OIDC tokens for signing.
|
||||
contents: write # for uploading attestations to GitHub releases.
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.1.0
|
||||
with:
|
||||
provenance-name: "provenance.intoto.jsonl"
|
||||
base64-subjects: "${{ needs.release.outputs.hashes }}"
|
||||
upload-assets: true
|
||||
|
||||
dockerhub-provenance:
|
||||
needs: [release]
|
||||
permissions:
|
||||
actions: read # for detecting the Github Actions environment.
|
||||
id-token: write # for creating OIDC tokens for signing.
|
||||
packages: write # for uploading attestations.
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v2.1.0
|
||||
with:
|
||||
image: ${{ needs.release.outputs.image_url }}
|
||||
digest: ${{ needs.release.outputs.image_digest }}
|
||||
registry-username: fluxcdbot
|
||||
secrets:
|
||||
registry-password: ${{ secrets.DOCKER_FLUXCD_PASSWORD }}
|
||||
|
||||
ghcr-provenance:
|
||||
needs: [release]
|
||||
permissions:
|
||||
actions: read # for detecting the Github Actions environment.
|
||||
id-token: write # for creating OIDC tokens for signing.
|
||||
packages: write # for uploading attestations.
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v2.1.0
|
||||
with:
|
||||
image: ghcr.io/${{ needs.release.outputs.image_url }}
|
||||
digest: ${{ needs.release.outputs.image_digest }}
|
||||
registry-username: fluxcdbot
|
||||
secrets:
|
||||
registry-password: ${{ secrets.GHCR_TOKEN }}
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
name: scan
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
branches: [ 'main', 'release/**' ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
branches: [ 'main', 'release/**' ]
|
||||
schedule:
|
||||
- cron: '18 10 * * 3'
|
||||
|
||||
|
@ -16,9 +17,10 @@ jobs:
|
|||
name: FOSSA
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Checkout
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- name: Run FOSSA scan and upload build data
|
||||
uses: fossa-contrib/fossa-action@v1
|
||||
uses: fossa-contrib/fossa-action@3d2ef181b1820d6dcd1972f86a767d18167fa19b # v3.0.1
|
||||
with:
|
||||
# FOSSA Push-Only API Token
|
||||
fossa-api-key: 5ee8bf422db1471e0bcf2bcb289185de
|
||||
|
@ -28,17 +30,23 @@ jobs:
|
|||
name: CodeQL
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
- name: Checkout
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v3
|
||||
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
|
||||
with:
|
||||
go-version: 1.19.x
|
||||
go-version: 1.24.x
|
||||
cache-dependency-path: |
|
||||
**/go.sum
|
||||
**/go.mod
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
uses: github/codeql-action/init@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18
|
||||
with:
|
||||
languages: go
|
||||
# xref: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
|
||||
# xref: https://codeql.github.com/codeql-query-help/go/
|
||||
queries: security-and-quality
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
uses: github/codeql-action/autobuild@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
uses: github/codeql-action/analyze@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
name: sync-labels
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- .github/labels.yaml
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
labels:
|
||||
name: Run sync
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
issues: write
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: EndBug/label-sync@52074158190acb45f3077f9099fea818aa43f97a # v2.3.3
|
||||
with:
|
||||
# Configuration file
|
||||
config-file: |
|
||||
https://raw.githubusercontent.com/fluxcd/community/main/.github/standard-labels.yaml
|
||||
.github/labels.yaml
|
||||
# Strictly declarative
|
||||
delete-other-labels: true
|
|
@ -4,9 +4,26 @@ builds:
|
|||
- skip: true
|
||||
|
||||
release:
|
||||
prerelease: "true"
|
||||
extra_files:
|
||||
- glob: config/release/*.yaml
|
||||
prerelease: "auto"
|
||||
header: |
|
||||
## Changelog
|
||||
|
||||
[{{.Tag}} changelog](https://github.com/fluxcd/{{.ProjectName}}/blob/{{.Tag}}/CHANGELOG.md)
|
||||
footer: |
|
||||
## Container images
|
||||
|
||||
- `docker.io/fluxcd/{{.ProjectName}}:{{.Tag}}`
|
||||
- `ghcr.io/fluxcd/{{.ProjectName}}:{{.Tag}}`
|
||||
|
||||
Supported architectures: `linux/amd64`, `linux/arm64` and `linux/arm/v7`.
|
||||
|
||||
The container images are built on GitHub hosted runners and are signed with cosign and GitHub OIDC.
|
||||
To verify the images and their provenance (SLSA level 3), please see the [security documentation](https://fluxcd.io/flux/security/).
|
||||
|
||||
changelog:
|
||||
disable: true
|
||||
|
||||
checksum:
|
||||
extra_files:
|
||||
|
@ -32,6 +49,7 @@ signs:
|
|||
certificate: "${artifact}.pem"
|
||||
args:
|
||||
- sign-blob
|
||||
- "--yes"
|
||||
- "--output-certificate=${certificate}"
|
||||
- "--output-signature=${signature}"
|
||||
- "${artifact}"
|
||||
|
|
616
CHANGELOG.md
616
CHANGELOG.md
|
@ -2,6 +2,622 @@
|
|||
|
||||
All notable changes to this project are documented in this file.
|
||||
|
||||
## 1.6.0
|
||||
|
||||
**Release date:** 2025-05-27
|
||||
|
||||
This minor release comes with various bug fixes and improvements.
|
||||
|
||||
### Provider
|
||||
|
||||
The `azureeventhub` provider now supports workload identity both
|
||||
at the controller and object levels. For object level, the
|
||||
`.spec.serviceAccountName` field can be set to the name of a
|
||||
service account in the same namespace that was configured with
|
||||
a Managed Identity.
|
||||
For object level to work, the controller feature gate
|
||||
`ObjectLevelWorkloadIdentity` must be enabled. See a complete guide
|
||||
[here](https://fluxcd.io/flux/integrations/azure/).
|
||||
|
||||
The `github` and `githubdispatch` providers now support authenticating
|
||||
with a GitHub App. See docs
|
||||
[here](https://fluxcd.io/flux/components/notification/providers/#github)
|
||||
and
|
||||
[here](https://fluxcd.io/flux/components/notification/providers/#github-dispatch).
|
||||
|
||||
For commit status providers it is now possible to define a custom
|
||||
status string by defining a CEL expression in the `.spec.commitStatusExpr`
|
||||
field. The variables `event`, `alert` and `provider` are available
|
||||
for the CEL expression. See
|
||||
[docs](https://fluxcd.io/flux/components/notification/providers/#custom-commit-status-messages).
|
||||
|
||||
### General updates
|
||||
|
||||
In addition, the Kubernetes dependencies have been updated to v1.33 and
|
||||
various other controller dependencies have been updated to their latest
|
||||
version. The controller is now built with Go 1.24.
|
||||
|
||||
Fixes:
|
||||
- Fix Slack chat.postMessage error handling
|
||||
[#1086](https://github.com/fluxcd/notification-controller/pull/1086)
|
||||
- Fix pass 'certPool' to Gitea client on creation
|
||||
[#1084](https://github.com/fluxcd/notification-controller/pull/1084)
|
||||
- CrossNamespaceObjectReference: Fix MaxLength validation to kubernetes max size of 253
|
||||
[#1108](https://github.com/fluxcd/notification-controller/pull/1108)
|
||||
- Sanitize proxy error logging
|
||||
[#1093](https://github.com/fluxcd/notification-controller/pull/1093)
|
||||
|
||||
Improvements:
|
||||
- [RFC-0010] Workload Identity support for `azureeventhub` provider
|
||||
[#1106](https://github.com/fluxcd/notification-controller/pull/1106)
|
||||
[#1116](https://github.com/fluxcd/notification-controller/pull/1116)
|
||||
[#1120](https://github.com/fluxcd/notification-controller/pull/1120)
|
||||
[#1109](https://github.com/fluxcd/notification-controller/pull/1109)
|
||||
[#1112](https://github.com/fluxcd/notification-controller/pull/1112)
|
||||
- GitHub App authentication support for `github` and `githubdispatch`
|
||||
[#1058](https://github.com/fluxcd/notification-controller/pull/1058)
|
||||
- Support CEL expressions to construct commit statuses
|
||||
[#1068](https://github.com/fluxcd/notification-controller/pull/1068)
|
||||
- Add proxy support to `gitea` provider
|
||||
[#1087](https://github.com/fluxcd/notification-controller/pull/1087)
|
||||
- Various dependency updates
|
||||
[#1101](https://github.com/fluxcd/notification-controller/pull/1101)
|
||||
[#1119](https://github.com/fluxcd/notification-controller/pull/1119)
|
||||
[#1118](https://github.com/fluxcd/notification-controller/pull/1118)
|
||||
[#1113](https://github.com/fluxcd/notification-controller/pull/1113)
|
||||
[#1104](https://github.com/fluxcd/notification-controller/pull/1104)
|
||||
|
||||
## 1.5.0
|
||||
|
||||
**Release date:** 2025-02-13
|
||||
|
||||
This minor release comes with various bug fixes and improvements.
|
||||
|
||||
### Alert
|
||||
|
||||
Now notification-controller also sends event metadata specified in Flux objects through
|
||||
annotations. See [docs](https://fluxcd.io/flux/components/notification/alerts/#event-metadata-from-object-annotations).
|
||||
|
||||
Now notification-controller is also capable of updating Git commit statuses
|
||||
from events about Kustomizations that consume OCIRepositories. See
|
||||
[docs](https://fluxcd.io/flux/cheatsheets/oci-artifacts/#git-commit-status-updates).
|
||||
|
||||
### Receiver
|
||||
|
||||
The Receiver API now supports filtering the declared resources that
|
||||
match a given Common Expression Language (CEL) expression. See
|
||||
[docs](https://fluxcd.io/flux/components/notification/receivers/#filtering-reconciled-objects-with-cel).
|
||||
|
||||
In addition, the Kubernetes dependencies have been updated to v1.32.1 and
|
||||
various other controller dependencies have been updated to their latest
|
||||
version.
|
||||
|
||||
Fixes:
|
||||
- Remove deprecated object metrics from controllers
|
||||
[#997](https://github.com/fluxcd/notification-controller/pull/997)
|
||||
- msteams notifier: adaptive cards full width
|
||||
[#1017](https://github.com/fluxcd/notification-controller/pull/1017)
|
||||
- fix: adding of duplicate commit statuses in gitlab
|
||||
[#1010](https://github.com/fluxcd/notification-controller/pull/1010)
|
||||
- Fix add missing return statement and a few style issues
|
||||
[#1039](https://github.com/fluxcd/notification-controller/pull/1039)
|
||||
|
||||
Improvements:
|
||||
- [RFC-0008] Custom Event Metadata from Annotations
|
||||
[#1014](https://github.com/fluxcd/notification-controller/pull/1014)
|
||||
- Add support for MetaOriginRevisionKey from the Event API
|
||||
[#1018](https://github.com/fluxcd/notification-controller/pull/1018)
|
||||
- Add subsection for Git providers supporting commit status updates
|
||||
[#1019](https://github.com/fluxcd/notification-controller/pull/1019)
|
||||
- Add support for Bearer Token authentication to Provider alertmanager
|
||||
[#1021](https://github.com/fluxcd/notification-controller/pull/1021)
|
||||
- Enforce namespace check on receiver
|
||||
[#1022](https://github.com/fluxcd/notification-controller/pull/1022)
|
||||
- Implement Receiver resource filtering with CEL
|
||||
[#948](https://github.com/fluxcd/notification-controller/pull/948)
|
||||
- Clarify gitlab provider usage
|
||||
[#953](https://github.com/fluxcd/notification-controller/pull/953)
|
||||
- Add involved object reference as annotations for the grafana provider
|
||||
[#1040](https://github.com/fluxcd/notification-controller/pull/1040)
|
||||
- Improvements after CEL resource filtering
|
||||
[#1041](https://github.com/fluxcd/notification-controller/pull/1041)
|
||||
- Various dependency updates
|
||||
[#1002](https://github.com/fluxcd/notification-controller/pull/1002)
|
||||
[#1016](https://github.com/fluxcd/notification-controller/pull/1016)
|
||||
[#1023](https://github.com/fluxcd/notification-controller/pull/1023)
|
||||
[#1025](https://github.com/fluxcd/notification-controller/pull/1025)
|
||||
[#1027](https://github.com/fluxcd/notification-controller/pull/1027)
|
||||
[#1032](https://github.com/fluxcd/notification-controller/pull/1032)
|
||||
[#1036](https://github.com/fluxcd/notification-controller/pull/1036)
|
||||
[#1037](https://github.com/fluxcd/notification-controller/pull/1037)
|
||||
[#1042](https://github.com/fluxcd/notification-controller/pull/1042)
|
||||
|
||||
## 1.4.0
|
||||
|
||||
**Release date:** 2024-09-27
|
||||
|
||||
This minor release comes with various bug fixes and improvements.
|
||||
|
||||
MS Teams Provider has been updated to support MS Adaptive Card payloads.
|
||||
This allows users to migrate from the deprecated
|
||||
[Office 365 Connector for Incoming Webhooks](https://devblogs.microsoft.com/microsoft365dev/retirement-of-office-365-connectors-within-microsoft-teams/)
|
||||
to the new [Microsoft Teams Incoming Webhooks with Workflows](https://support.microsoft.com/en-us/office/create-incoming-webhooks-with-workflows-for-microsoft-teams-8ae491c7-0394-4861-ba59-055e33f75498).
|
||||
See the [Provider API documentation](https://fluxcd.io/flux/components/notification/providers/#microsoft-teams)
|
||||
for more information. After getting the URL for the new Incoming Webhook Workflow,
|
||||
update the secret used by the `msteams` Provider object with the new URL.
|
||||
|
||||
In addition, the Kubernetes dependencies have been updated to v1.31.1 and
|
||||
various other controller dependencies have been updated to their latest
|
||||
version. The controller is now built with Go 1.23.
|
||||
|
||||
Fixes:
|
||||
- telegram notifier should escape with metadata key
|
||||
[#829](https://github.com/fluxcd/notification-controller/pull/829)
|
||||
- docs: use stringData for secret of GitHub PAT
|
||||
[#873](https://github.com/fluxcd/notification-controller/pull/873)
|
||||
- Fix incorrect use of format strings with the conditions package.
|
||||
[#879](https://github.com/fluxcd/notification-controller/pull/879)
|
||||
|
||||
Improvements:
|
||||
- New flag to disable detailed metrics for path
|
||||
[#841](https://github.com/fluxcd/notification-controller/pull/841)
|
||||
- Fix telegram test flake
|
||||
[#894](https://github.com/fluxcd/notification-controller/pull/894)
|
||||
- Build with Go 1.23
|
||||
[#907](https://github.com/fluxcd/notification-controller/pull/907)
|
||||
- Add MS Adaptive Card payload to msteams Provider
|
||||
[#920](https://github.com/fluxcd/notification-controller/pull/920)
|
||||
- Various dependency updates
|
||||
[#845](https://github.com/fluxcd/notification-controller/pull/845)
|
||||
[#855](https://github.com/fluxcd/notification-controller/pull/855)
|
||||
[#854](https://github.com/fluxcd/notification-controller/pull/854)
|
||||
[#857](https://github.com/fluxcd/notification-controller/pull/857)
|
||||
[#865](https://github.com/fluxcd/notification-controller/pull/865)
|
||||
[#866](https://github.com/fluxcd/notification-controller/pull/866)
|
||||
[#905](https://github.com/fluxcd/notification-controller/pull/905)
|
||||
[#903](https://github.com/fluxcd/notification-controller/pull/903)
|
||||
[#912](https://github.com/fluxcd/notification-controller/pull/912)
|
||||
[#925](https://github.com/fluxcd/notification-controller/pull/925)
|
||||
[#931](https://github.com/fluxcd/notification-controller/pull/931)
|
||||
[#932](https://github.com/fluxcd/notification-controller/pull/932)
|
||||
[#933](https://github.com/fluxcd/notification-controller/pull/933)
|
||||
[#934](https://github.com/fluxcd/notification-controller/pull/934)
|
||||
|
||||
## 1.3.0
|
||||
|
||||
**Release date:** 2024-05-06
|
||||
|
||||
This minor release comes with new features, improvements and bug fixes.
|
||||
|
||||
The `Receiver` API has been extended to support CDEvents,
|
||||
for more information, please see the
|
||||
[CDEvents Receiver API documentation](https://github.com/fluxcd/notification-controller/blob/release/v1.3.x/docs/spec/v1/receivers.md#cdevents).
|
||||
|
||||
Starting with this version, the controller allows grouping alerts for Alertmanager
|
||||
by setting the `startsAt` label instead of `timestamp`. When sending alerts to
|
||||
OpsGenie, the controller now sets the `severity` field to the alert's details.
|
||||
|
||||
In addition, the controller dependencies have been updated to Kubernetes v1.30
|
||||
and controller-runtime v0.18. Various other dependencies have also been updated to
|
||||
their latest version to patch upstream CVEs.
|
||||
|
||||
Lastly, the controller is now built with Go 1.22.
|
||||
|
||||
Improvements:
|
||||
- Add CDEvent Receiver Support
|
||||
[#772](https://github.com/fluxcd/notification-controller/pull/772)
|
||||
- Add severity to opsgenie alerts
|
||||
[#796](https://github.com/fluxcd/notification-controller/pull/796)
|
||||
- Alertmanager: Change timestamp label to .StartsAt
|
||||
[#795](https://github.com/fluxcd/notification-controller/pull/795)
|
||||
- Use `password` as fallback for the Git provider `token` auth
|
||||
[#790](https://github.com/fluxcd/notification-controller/pull/790)
|
||||
- Add support for Bitbucket Context path
|
||||
[#747](https://github.com/fluxcd/notification-controller/pull/747)
|
||||
- Various dependency updates
|
||||
[#816](https://github.com/fluxcd/notification-controller/pull/816)
|
||||
[#814](https://github.com/fluxcd/notification-controller/pull/814)
|
||||
[#813](https://github.com/fluxcd/notification-controller/pull/813)
|
||||
[#810](https://github.com/fluxcd/notification-controller/pull/810)
|
||||
[#809](https://github.com/fluxcd/notification-controller/pull/809)
|
||||
[#787](https://github.com/fluxcd/notification-controller/pull/787)
|
||||
[#783](https://github.com/fluxcd/notification-controller/pull/783)
|
||||
[#763](https://github.com/fluxcd/notification-controller/pull/763)
|
||||
|
||||
Fixes:
|
||||
- Sanitize provider data loaded from secret
|
||||
[#789](https://github.com/fluxcd/notification-controller/pull/789)
|
||||
- Fix timeout propagation for alerts
|
||||
[#757](https://github.com/fluxcd/notification-controller/pull/757)
|
||||
- Fix Telegram MarkdownV2 escaping
|
||||
[#776](https://github.com/fluxcd/notification-controller/pull/776)
|
||||
- Remove `genclient:Namespaced` tag
|
||||
[#749](https://github.com/fluxcd/notification-controller/pull/749)
|
||||
|
||||
## 1.2.4
|
||||
|
||||
**Release date:** 2024-02-01
|
||||
|
||||
This patch release fixes various issues, updates the Kubernetes dependencies
|
||||
to v1.28.6 and various other dependencies to their latest version to patch
|
||||
upstream CVEs.
|
||||
|
||||
Improvements:
|
||||
- Various dependency updates
|
||||
[#727](https://github.com/fluxcd/notification-controller/pull/727)
|
||||
[#726](https://github.com/fluxcd/notification-controller/pull/726)
|
||||
[#721](https://github.com/fluxcd/notification-controller/pull/721)
|
||||
[#718](https://github.com/fluxcd/notification-controller/pull/718)
|
||||
[#707](https://github.com/fluxcd/notification-controller/pull/707)
|
||||
[#695](https://github.com/fluxcd/notification-controller/pull/695)
|
||||
|
||||
Fixes:
|
||||
- Fix BitBucket status update panic
|
||||
[#722](https://github.com/fluxcd/notification-controller/pull/722)
|
||||
- fix typo in docs/spec/v1beta3/providers.md
|
||||
[#699](https://github.com/fluxcd/notification-controller/pull/699)
|
||||
- fix(grafana-provider): replace ":" character in eventMetadata
|
||||
[#703](https://github.com/fluxcd/notification-controller/pull/703)
|
||||
- Remove old/incorrect API version usage
|
||||
[#693](https://github.com/fluxcd/notification-controller/pull/693)
|
||||
|
||||
## 1.2.3
|
||||
|
||||
**Release date:** 2023-12-14
|
||||
|
||||
This patch release fixes various issues, most notably, the Provider v1beta3 API
|
||||
backwards compatibility issue when `.spec.interval` was explicitly set in a
|
||||
v1beta2 version of Provider.
|
||||
|
||||
Fixes:
|
||||
- Exclude eventv1.MetaTokenKey from event metadata
|
||||
[#686](https://github.com/fluxcd/notification-controller/pull/686)
|
||||
- Add .spec.interval in v1beta3 Provider
|
||||
[#683](https://github.com/fluxcd/notification-controller/pull/683)
|
||||
- Remove URL syntax validation for provider address entirely
|
||||
[#682](https://github.com/fluxcd/notification-controller/pull/682)
|
||||
|
||||
## 1.2.2
|
||||
|
||||
**Release date:** 2023-12-11
|
||||
|
||||
This patch releases updates a variety of dependencies, including an update of
|
||||
the container base image to Alpine v3.19.
|
||||
|
||||
Improvements:
|
||||
- build: update Alpine to 3.19
|
||||
[#675](https://github.com/fluxcd/notification-controller/pull/675)
|
||||
- Update dependencies
|
||||
[#677](https://github.com/fluxcd/notification-controller/pull/677)
|
||||
|
||||
## 1.2.1
|
||||
|
||||
**Release date:** 2023-12-08
|
||||
|
||||
This patch release updates the Go version the controller is built with to
|
||||
`1.21.x`, while mitigating recently published security vulnerabilities in the
|
||||
`net/http` package.
|
||||
|
||||
In addition, it ensures static analyzers no longer detect a vulnerability in the
|
||||
`whilp/git-urls` module by using `chainguard-dev/git-urls`. For which the
|
||||
(potential) issue itself got already addressed internally in the [previous
|
||||
v1.2.0 release](#120).
|
||||
|
||||
Lastly, a small number of dependencies got updated to their latest versions.
|
||||
|
||||
Improvements:
|
||||
- Update Go to 1.21.x
|
||||
[#666](https://github.com/fluxcd/notification-controller/pull/666)
|
||||
- Replace whilp/git-urls module by chainguard-dev/git-urls
|
||||
[#667](https://github.com/fluxcd/notification-controller/pull/667)
|
||||
- Update dependencies
|
||||
[#669](https://github.com/fluxcd/notification-controller/pull/669)
|
||||
|
||||
## 1.2.0
|
||||
|
||||
**Release date:** 2023-12-05
|
||||
|
||||
This minor release graduates the notification `Alert` and `Provider` APIs to
|
||||
`v1beta3`. In addition, this version comes with alert Provider support for
|
||||
[BitBucket
|
||||
Server](https://github.com/fluxcd/notification-controller/blob/api/v1.2.0/docs/spec/v1beta3/providers.md#bitbucket-serverdata-center)
|
||||
and
|
||||
[NATS](https://github.com/fluxcd/notification-controller/blob/api/v1.2.0/docs/spec/v1beta3/providers.md#nats).
|
||||
|
||||
### `notification.toolkit.fluxcd.io/v1beta3`
|
||||
|
||||
After upgrading the controller to v1.2.0, please update the notification Custom
|
||||
Resources for `Alert` and `Provider` in Git by replacing
|
||||
`notification.toolkit.fluxcd.io/v1beta2` with
|
||||
`notification.toolkit.fluxcd.io/v1beta3` in all the YAML manifests.
|
||||
|
||||
#### Static Alerts and Providers
|
||||
|
||||
The notification Alert and Provider API resources will become static objects
|
||||
with configurations that will be used by the event handlers for processing the
|
||||
respective incoming events. They will no longer be reconciled by a reconciler
|
||||
and will not advertise any status. Once `Alerts` and `Providers` are created,
|
||||
they can be considered ready. Users of
|
||||
[kstatus](https://github.com/kubernetes-sigs/cli-utils/blob/master/pkg/kstatus/README.md)
|
||||
shouldn't see any difference. Existing `Alerts` and `Providers` objects in
|
||||
`v1beta2` API will undergo a one-time automatic migration to be converted into
|
||||
static objects without any status.
|
||||
|
||||
#### Enhanced Alert events
|
||||
|
||||
The event handler will emit Kubernetes native events on the respective Alert
|
||||
object for any relevant information, including failures due to any
|
||||
misconfiguration.
|
||||
|
||||
Improvements:
|
||||
- Add Provider for NATS Subject
|
||||
[#651](https://github.com/fluxcd/notification-controller/pull/651)
|
||||
- Cap provider address at 2048 bytes
|
||||
[#654](https://github.com/fluxcd/notification-controller/pull/654)
|
||||
- Refactor events and introduce v1beta3 API for Alert and Provider
|
||||
[#540](https://github.com/fluxcd/notification-controller/pull/540)
|
||||
- Add Bitbucket server/Bitbucket Data Center provider for git commit status
|
||||
[#639](https://github.com/fluxcd/notification-controller/pull/639)
|
||||
- Address miscellaneous issues throughout code base
|
||||
[#627](https://github.com/fluxcd/notification-controller/pull/627)
|
||||
- Update dependencies
|
||||
[#609](https://github.com/fluxcd/notification-controller/pull/609)
|
||||
[#612](https://github.com/fluxcd/notification-controller/pull/612)
|
||||
[#613](https://github.com/fluxcd/notification-controller/pull/613)
|
||||
[#617](https://github.com/fluxcd/notification-controller/pull/617)
|
||||
[#621](https://github.com/fluxcd/notification-controller/pull/621)
|
||||
[#623](https://github.com/fluxcd/notification-controller/pull/623)
|
||||
[#628](https://github.com/fluxcd/notification-controller/pull/628)
|
||||
[#629](https://github.com/fluxcd/notification-controller/pull/629)
|
||||
[#632](https://github.com/fluxcd/notification-controller/pull/632)
|
||||
[#635](https://github.com/fluxcd/notification-controller/pull/635)
|
||||
[#637](https://github.com/fluxcd/notification-controller/pull/637)
|
||||
[#641](https://github.com/fluxcd/notification-controller/pull/641)
|
||||
[#643](https://github.com/fluxcd/notification-controller/pull/643)
|
||||
[#646](https://github.com/fluxcd/notification-controller/pull/646)
|
||||
[#648](https://github.com/fluxcd/notification-controller/pull/648)
|
||||
[#652](https://github.com/fluxcd/notification-controller/pull/652)
|
||||
[#656](https://github.com/fluxcd/notification-controller/pull/656)
|
||||
[#657](https://github.com/fluxcd/notification-controller/pull/657)
|
||||
|
||||
Fixes:
|
||||
- Fix README.md links to notification APIs
|
||||
[#619](https://github.com/fluxcd/notification-controller/pull/619)
|
||||
|
||||
## 1.1.0
|
||||
|
||||
**Release date:** 2023-08-23
|
||||
|
||||
This minor release comes with support for sending alerts
|
||||
to [PagerDuty](https://github.com/fluxcd/notification-controller/blob/v1.1.0/docs/spec/v1beta2/providers.md#datadog).
|
||||
|
||||
In addition, this version deprecates the usage of the `caFile` key in favor of `ca.crt`
|
||||
for the `.spec.certSecretRef` secret in the Provider v1beta2 API.
|
||||
|
||||
Starting with this version, the controller now stops exporting an object's
|
||||
metrics as soon as the object has been deleted.
|
||||
|
||||
Improvements:
|
||||
|
||||
- Add support for Datadog
|
||||
[#592](https://github.com/fluxcd/notification-controller/pull/592)
|
||||
- Adopt Kubernetes style TLS Secret
|
||||
[#597](https://github.com/fluxcd/notification-controller/pull/597)
|
||||
- Remove checks for empty user and channel parameters in Rocket notifier
|
||||
[#603](https://github.com/fluxcd/notification-controller/pull/603)
|
||||
- Clarify permission requirements for Gitea provider token
|
||||
[#583](https://github.com/fluxcd/notification-controller/pull/583)
|
||||
- Align docs structure with other controllers
|
||||
[#582](https://github.com/fluxcd/notification-controller/pull/582)
|
||||
- Update dependencies
|
||||
[#600](https://github.com/fluxcd/notification-controller/pull/600)
|
||||
[#606](https://github.com/fluxcd/notification-controller/pull/606)
|
||||
|
||||
Fixes:
|
||||
|
||||
- Use TrimPrefix instead of TrimLeft
|
||||
[#590](https://github.com/fluxcd/notification-controller/pull/590)
|
||||
- Handle delete before adding finalizer
|
||||
[#584](https://github.com/fluxcd/notification-controller/pull/584)
|
||||
- Delete stale metrics on object delete
|
||||
[#599](https://github.com/fluxcd/notification-controller/pull/599)
|
||||
- docs: change key type to `[]byte` in provider spec
|
||||
[#585](https://github.com/fluxcd/notification-controller/pull/585)
|
||||
|
||||
## 1.0.0
|
||||
|
||||
**Release date:** 2023-07-04
|
||||
|
||||
This is the first stable release of the controller. From now on, this controller
|
||||
follows the [Flux 2 release cadence and support pledge](https://fluxcd.io/flux/releases/).
|
||||
|
||||
Starting with this version, the build, release and provenance portions of the
|
||||
Flux project supply chain [provisionally meet SLSA Build Level 3](https://fluxcd.io/flux/security/slsa-assessment/).
|
||||
|
||||
This release comes with support for sending alerts
|
||||
to [PagerDuty](https://github.com/fluxcd/notification-controller/blob/v1.0.0/docs/spec/v1beta2/providers.md#pagerduty)
|
||||
and [Google Pub/Sub](https://github.com/fluxcd/notification-controller/blob/v1.0.0/docs/spec/v1beta2/providers.md#google-pubsub).
|
||||
|
||||
In addition, dependencies have been updated
|
||||
to their latest version, including an update of Kubernetes to v1.27.3.
|
||||
|
||||
For a comprehensive list of changes since `v0.33.x`, please refer to the
|
||||
changelog for [v1.0.0-rc.1](#100-rc1), [v1.0.0-rc.2](#100-rc2),
|
||||
[v1.0.0-rc.3](#100-rc3) and [`v1.0.0-rc.4](#100-rc4).
|
||||
|
||||
Improvements:
|
||||
|
||||
- Add support for PagerDuty
|
||||
[#527](https://github.com/fluxcd/notification-controller/pull/527)
|
||||
- Add support for Google Pub/Sub
|
||||
[#543](https://github.com/fluxcd/notification-controller/pull/543)
|
||||
- Lift HTTP/S validation from Provider spec.address
|
||||
[#565](https://github.com/fluxcd/notification-controller/pull/565)
|
||||
- Improve error messages in Gitea notifier
|
||||
[#556](https://github.com/fluxcd/notification-controller/pull/556)
|
||||
- Make Gitea tests independent of 3rd-party service
|
||||
[#558](https://github.com/fluxcd/notification-controller/pull/558)
|
||||
- Align go.mod version with Kubernetes (Go 1.20)
|
||||
[#558](https://github.com/fluxcd/notification-controller/pull/558)
|
||||
- Update dependencies
|
||||
[#563](https://github.com/fluxcd/notification-controller/pull/563)
|
||||
- Update GCP dependencies
|
||||
[#569](https://github.com/fluxcd/notification-controller/pull/569)
|
||||
|
||||
Fixes:
|
||||
|
||||
- Fix Alert `.spec.eventMetadata` documentation
|
||||
[#541](https://github.com/fluxcd/notification-controller/pull/541)
|
||||
- Fix `TestProviderReconciler_Reconcile/finalizes_suspended_object` to use patch instead of update
|
||||
[#550](https://github.com/fluxcd/notification-controller/pull/550)
|
||||
|
||||
## 1.0.0-rc.4
|
||||
|
||||
**Release date:** 2023-05-26
|
||||
|
||||
This release candidate comes with support for Kubernetes v1.27.
|
||||
|
||||
The `Event` API has been modified to have a dedicated key for `metadata` called
|
||||
`token`. The value of the `token` key is meant to be defined on a per event
|
||||
emitter basis for uniquely identifying the contents of the event payload.
|
||||
This key if present, is included in calculating the unique key used for rate
|
||||
limiting events.
|
||||
Furthermore, the event attributes are prefixed with an identifier to avoid
|
||||
collisions between different event attributes.
|
||||
|
||||
In addition, a bug in the event rate limiting key calculation logic which led
|
||||
to the inconsideration of the revision specified in `.metadata` of the event has
|
||||
been fixed.
|
||||
|
||||
Lastly, the behavior of `.spec.eventMetadata` has been modified such that if a
|
||||
key present in the map already exists in the original event's `metadata`, then
|
||||
the key in the latter takes precedence and an error log is printed for visibility.
|
||||
|
||||
Improvements:
|
||||
|
||||
- Include eventv1.MetaTokenKey on event rate limiting key calculation
|
||||
[#530](https://github.com/fluxcd/notification-controller/pull/530)
|
||||
- Update dependencies and Kubernetes to 1.27.2
|
||||
[#532](https://github.com/fluxcd/notification-controller/pull/532)
|
||||
- Remove the tini supervisor
|
||||
[#533](https://github.com/fluxcd/notification-controller/pull/533)
|
||||
- Prefix event key attributes with identifier
|
||||
[#534](https://github.com/fluxcd/notification-controller/pull/534)
|
||||
- Update workflows and enable dependabot
|
||||
[#535](https://github.com/fluxcd/notification-controller/pull/535)
|
||||
- build(deps): bump github/codeql-action from 2.3.3 to 2.3.4
|
||||
[#536](https://github.com/fluxcd/notification-controller/pull/536)
|
||||
|
||||
Fixes:
|
||||
|
||||
- Fix revision discarded on event rate limiting key calculation
|
||||
[#517](https://github.com/fluxcd/notification-controller/pull/517)
|
||||
- Fix Alert .spec.eventMetadata behavior
|
||||
[#529](https://github.com/fluxcd/notification-controller/pull/529)
|
||||
|
||||
## 1.0.0-rc.3
|
||||
|
||||
**Release date:** 2023-05-12
|
||||
|
||||
This release candidate comes with support for
|
||||
adding [custom metadata](https://github.com/fluxcd/notification-controller/blob/v1.0.0-rc.3/docs/spec/v1beta2/alerts.md#event-metadata)
|
||||
to Flux events. A new field was added to the Alert v1beta2 API named
|
||||
`.spec.eventMetadata` that allows users to enrich the alerts with
|
||||
information about the cluster name, region, environment, etc.
|
||||
|
||||
In addition, the controller dependencies have been updated to patch
|
||||
CVE-2023-1732 and the base image has been updated to Alpine 3.18.
|
||||
|
||||
Improvements:
|
||||
- Add event metadata field to Alert spec
|
||||
[#519](https://github.com/fluxcd/notification-controller/pull/506)
|
||||
- Update Alpine to 3.18
|
||||
[#524](https://github.com/fluxcd/notification-controller/pull/524)
|
||||
- build(deps): bump github.com/cloudflare/circl from 1.3.2 to 1.3.3
|
||||
[#525](https://github.com/fluxcd/notification-controller/pull/525)
|
||||
|
||||
## 1.0.0-rc.2
|
||||
|
||||
**Release date:** 2023-05-09
|
||||
|
||||
This release candidate comes with performance improvements for Receivers
|
||||
and removes the deprecated `.status.url` field from the Receiver v1 API.
|
||||
|
||||
A new field was added to the Alert v1beta2 API named `.spec.inclusionList` for
|
||||
better control over events filtering.
|
||||
|
||||
In addition, the controller dependencies have been updated to their latest
|
||||
versions.
|
||||
|
||||
Improvements:
|
||||
- Index receivers using webhook path as key
|
||||
[#506](https://github.com/fluxcd/notification-controller/pull/506)
|
||||
- Append the Alert summary to Azure DevOps genre field
|
||||
[#514](https://github.com/fluxcd/notification-controller/pull/514)
|
||||
- Add InclusionList to Alert CRD
|
||||
[#515](https://github.com/fluxcd/notification-controller/pull/515)
|
||||
- Update dependencies
|
||||
[#520](https://github.com/fluxcd/notification-controller/pull/520)
|
||||
- Improve event handler tests
|
||||
[#521](https://github.com/fluxcd/notification-controller/pull/521)
|
||||
- receiver/v1: Remove deprecated `.status.url` field
|
||||
[#482](https://github.com/fluxcd/notification-controller/pull/482)
|
||||
|
||||
## 1.0.0-rc.1
|
||||
|
||||
**Release date:** 2023-03-30
|
||||
|
||||
This release candidate promotes the Receiver API from v1beta2 to v1. The Receiver v1 API now supports triggering the reconciliation of multiple
|
||||
resources using match labels.
|
||||
|
||||
### Highlights
|
||||
|
||||
#### API changes
|
||||
|
||||
The `Receiver` kind was promoted from v1beta2 to v1 (GA). All other kinds of the notification.toolkit.fluxcd.io group stay at version v1beta2.
|
||||
|
||||
The receivers.notification.toolkit.fluxcd.io CRD contains the following versions:
|
||||
|
||||
- v1 (storage version)
|
||||
- v1beta2 (deprecated)
|
||||
- v1beta1 (deprecated)
|
||||
|
||||
#### Upgrade Procedure
|
||||
|
||||
The `Receiver` v1 API is backwards compatible with v1beta2.
|
||||
|
||||
To upgrade from v1beta2, after deploying the new CRD and controller, set `apiVersion: notification.toolkit.fluxcd.io/v1` in the YAML files that
|
||||
contain `Receiver` definitions. Bumping the API version in manifests can be done gradually. It is advised to not delay this procedure as the beta
|
||||
versions will be removed after 6 months.
|
||||
|
||||
### Full Changelog
|
||||
|
||||
Improvements:
|
||||
- GA: Promote Receiver API to notification.toolkit.fluxcd.io/v1
|
||||
[#498](https://github.com/fluxcd/notification-controller/pull/498)
|
||||
- support multiple resources in Receivers by using match labels
|
||||
[#482](https://github.com/fluxcd/notification-controller/pull/482)
|
||||
- docs: fixes to the Receiver documentation
|
||||
[#495](https://github.com/fluxcd/notification-controller/pull/495)
|
||||
|
||||
## 0.33.0
|
||||
|
||||
**Release date:** 2023-03-08
|
||||
|
||||
This release updates to Go version the controller is build with to `1.20`,
|
||||
and updates the dependencies to their latest versions.
|
||||
|
||||
In addition, `klog` is now configured to log using the same logger as the rest
|
||||
of the controller (providing a consistent log format).
|
||||
|
||||
Improvements:
|
||||
* Update Go to 1.20
|
||||
[#483](https://github.com/fluxcd/notification-controller/pull/483)
|
||||
* Update dependencies
|
||||
[#485](https://github.com/fluxcd/notification-controller/pull/485)
|
||||
* Use `logger.SetLogger` to also configure `klog`
|
||||
[#486](https://github.com/fluxcd/notification-controller/pull/486)
|
||||
|
||||
## 0.32.1
|
||||
|
||||
**Release date:** 2023-02-28
|
||||
|
|
|
@ -24,7 +24,7 @@ If any of the above dependencies are not present on your system, the first invoc
|
|||
## How to run the test suite
|
||||
|
||||
Prerequisites:
|
||||
- Go >= 1.17
|
||||
- Go >= 1.24
|
||||
|
||||
You can run the test suite by simply doing:
|
||||
|
||||
|
|
16
Dockerfile
16
Dockerfile
|
@ -1,9 +1,9 @@
|
|||
ARG GO_VERSION=1.19
|
||||
ARG XX_VERSION=1.1.0
|
||||
ARG GO_VERSION=1.24
|
||||
ARG XX_VERSION=1.6.1
|
||||
|
||||
FROM --platform=$BUILDPLATFORM tonistiigi/xx:${XX_VERSION} AS xx
|
||||
|
||||
FROM --platform=$BUILDPLATFORM golang:${GO_VERSION}-alpine as builder
|
||||
FROM --platform=$BUILDPLATFORM golang:${GO_VERSION}-alpine AS builder
|
||||
|
||||
# Copy the build utilities.
|
||||
COPY --from=xx / /
|
||||
|
@ -24,21 +24,21 @@ RUN go mod download
|
|||
|
||||
# copy source code
|
||||
COPY main.go main.go
|
||||
COPY controllers/ controllers/
|
||||
COPY internal/ internal/
|
||||
|
||||
# build
|
||||
ENV CGO_ENABLED=0
|
||||
RUN xx-go build -trimpath -a -o notification-controller main.go
|
||||
|
||||
FROM alpine:3.17
|
||||
FROM alpine:3.21
|
||||
|
||||
LABEL org.opencontainers.image.source="https://github.com/fluxcd/notification-controller"
|
||||
ARG TARGETPLATFORM
|
||||
|
||||
RUN apk add --no-cache ca-certificates tini
|
||||
RUN apk --no-cache add ca-certificates \
|
||||
&& update-ca-certificates
|
||||
|
||||
COPY --from=builder /workspace/notification-controller /usr/local/bin/
|
||||
|
||||
USER 65534:65534
|
||||
|
||||
ENTRYPOINT [ "/sbin/tini", "--", "notification-controller" ]
|
||||
ENTRYPOINT ["notification-controller" ]
|
||||
|
|
|
@ -7,4 +7,6 @@ as listed in
|
|||
|
||||
https://github.com/fluxcd/flux2/blob/main/MAINTAINERS
|
||||
|
||||
Somtochi Onyekwere, Weaveworks <somtochi@weave.works> (github: @SomtochiAma, slack: somtoxhi)
|
||||
In alphabetical order:
|
||||
|
||||
Somtochi Onyekwere, Independent <somtochionyekwere@gmail.com> (github: @somtochiama, slack: somtochiama)
|
||||
|
|
20
Makefile
20
Makefile
|
@ -2,14 +2,14 @@
|
|||
IMG ?= fluxcd/notification-controller:latest
|
||||
# Produce CRDs that work back to Kubernetes 1.16
|
||||
CRD_OPTIONS ?= crd:crdVersions=v1
|
||||
SOURCE_VER ?= v0.35.0
|
||||
SOURCE_VER ?= v1.2.4
|
||||
|
||||
# Repository root based on Git metadata
|
||||
REPOSITORY_ROOT := $(shell git rev-parse --show-toplevel)
|
||||
BUILD_DIR := $(REPOSITORY_ROOT)/build
|
||||
|
||||
# API (doc) generation utilities
|
||||
CONTROLLER_GEN_VERSION ?= v0.11.1
|
||||
CONTROLLER_GEN_VERSION ?= v0.16.1
|
||||
GEN_API_REF_DOCS_VERSION ?= e327d0730470cbd61b06300f81c5fcf91c23c113
|
||||
|
||||
# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
|
||||
|
@ -87,12 +87,14 @@ manifests: controller-gen
|
|||
|
||||
# Generate API reference documentation
|
||||
api-docs: gen-crd-api-reference-docs
|
||||
$(GEN_CRD_API_REFERENCE_DOCS) -api-dir=./api/v1beta2 -config=./hack/api-docs/config.json -template-dir=./hack/api-docs/template -out-file=./docs/api/notification.md
|
||||
$(GEN_CRD_API_REFERENCE_DOCS) -api-dir=./api/v1beta2 -config=./hack/api-docs/config.json -template-dir=./hack/api-docs/template -out-file=./docs/api/v1beta2/notification.md
|
||||
$(GEN_CRD_API_REFERENCE_DOCS) -api-dir=./api/v1beta3 -config=./hack/api-docs/config.json -template-dir=./hack/api-docs/template -out-file=./docs/api/v1beta3/notification.md
|
||||
$(GEN_CRD_API_REFERENCE_DOCS) -api-dir=./api/v1 -config=./hack/api-docs/config.json -template-dir=./hack/api-docs/template -out-file=./docs/api/v1/notification.md
|
||||
|
||||
# Run go mod tidy
|
||||
tidy:
|
||||
cd api; rm -f go.sum; go mod tidy -compat=1.19
|
||||
rm -f go.sum; go mod tidy -compat=1.19
|
||||
cd api; rm -f go.sum; go mod tidy -compat=1.24
|
||||
rm -f go.sum; go mod tidy -compat=1.24
|
||||
|
||||
# Run go fmt against code
|
||||
fmt:
|
||||
|
@ -151,13 +153,13 @@ fuzz-native:
|
|||
./tests/fuzz/native_go_run.sh
|
||||
|
||||
# Find or download controller-gen
|
||||
CONTROLLER_GEN = $(shell pwd)/bin/controller-gen
|
||||
CONTROLLER_GEN = $(GOBIN)/controller-gen
|
||||
.PHONY: controller-gen
|
||||
controller-gen: ## Download controller-gen locally if necessary.
|
||||
$(call go-install-tool,$(CONTROLLER_GEN),sigs.k8s.io/controller-tools/cmd/controller-gen@$(CONTROLLER_GEN_VERSION))
|
||||
|
||||
# Find or download gen-crd-api-reference-docs
|
||||
GEN_CRD_API_REFERENCE_DOCS = $(shell pwd)/bin/gen-crd-api-reference-docs
|
||||
GEN_CRD_API_REFERENCE_DOCS = $(GOBIN)/gen-crd-api-reference-docs
|
||||
.PHONY: gen-crd-api-reference-docs
|
||||
gen-crd-api-reference-docs:
|
||||
$(call go-install-tool,$(GEN_CRD_API_REFERENCE_DOCS),github.com/ahmetb/gen-crd-api-reference-docs@$(GEN_API_REF_DOCS_VERSION))
|
||||
|
@ -169,7 +171,7 @@ install-envtest: setup-envtest
|
|||
mkdir -p ${ENVTEST_ASSETS_DIR}
|
||||
$(ENVTEST) use $(ENVTEST_KUBERNETES_VERSION) --arch=$(ENVTEST_ARCH) --bin-dir=$(ENVTEST_ASSETS_DIR)
|
||||
|
||||
ENVTEST = $(shell pwd)/bin/setup-envtest
|
||||
ENVTEST = $(GOBIN)/setup-envtest
|
||||
.PHONY: envtest
|
||||
setup-envtest: ## Download envtest-setup locally if necessary.
|
||||
$(call go-install-tool,$(ENVTEST),sigs.k8s.io/controller-runtime/tools/setup-envtest@latest)
|
||||
|
@ -183,7 +185,7 @@ TMP_DIR=$$(mktemp -d) ;\
|
|||
cd $$TMP_DIR ;\
|
||||
go mod init tmp ;\
|
||||
echo "Downloading $(2)" ;\
|
||||
GOBIN=$(PROJECT_DIR)/bin go install $(2) ;\
|
||||
GOBIN=$(GOBIN) go install $(2) ;\
|
||||
rm -rf $$TMP_DIR ;\
|
||||
}
|
||||
endef
|
||||
|
|
13
PROJECT
13
PROJECT
|
@ -1,6 +1,13 @@
|
|||
# Code generated by tool. DO NOT EDIT.
|
||||
# This file is used to track the info used to scaffold your project
|
||||
# and allow the plugins properly work.
|
||||
# More info: https://book.kubebuilder.io/reference/project-config.html
|
||||
domain: toolkit.fluxcd.io
|
||||
repo: github.com/fluxcd/notification-controller
|
||||
resources:
|
||||
- group: notification
|
||||
kind: Receiver
|
||||
version: v1
|
||||
- group: notification
|
||||
kind: Provider
|
||||
version: v1beta1
|
||||
|
@ -19,4 +26,10 @@ resources:
|
|||
- group: notification
|
||||
kind: Receiver
|
||||
version: v1beta2
|
||||
- group: notification
|
||||
kind: Provider
|
||||
version: v1beta3
|
||||
- group: notification
|
||||
kind: Alert
|
||||
version: v1beta3
|
||||
version: "2"
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
[](https://github.com/fluxcd/notification-controller/releases)
|
||||
|
||||
Event forwarder and notification dispatcher for the [GitOps Toolkit](https://fluxcd.io/flux/components/) controllers.
|
||||
The notification-controller is an implementation of the [notification.toolkit.fluxcd.io](docs/spec/v1beta1/README.md)
|
||||
The notification-controller is an implementation of the [notification.toolkit.fluxcd.io](docs/spec/v1beta3/README.md)
|
||||
API based on the specifications described in the [RFC](docs/spec/README.md).
|
||||
|
||||

|
||||
|
|
32
api/go.mod
32
api/go.mod
|
@ -1,29 +1,35 @@
|
|||
module github.com/fluxcd/notification-controller/api
|
||||
|
||||
go 1.18
|
||||
go 1.24.0
|
||||
|
||||
require (
|
||||
github.com/fluxcd/pkg/apis/meta v0.19.0
|
||||
k8s.io/apimachinery v0.26.1
|
||||
sigs.k8s.io/controller-runtime v0.14.4
|
||||
github.com/fluxcd/pkg/apis/meta v1.17.0
|
||||
k8s.io/apimachinery v0.33.2
|
||||
sigs.k8s.io/controller-runtime v0.21.0
|
||||
)
|
||||
|
||||
// Fix CVE-2022-28948
|
||||
replace gopkg.in/yaml.v3 => gopkg.in/yaml.v3 v3.0.1
|
||||
|
||||
require (
|
||||
github.com/go-logr/logr v1.2.3 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.8.0 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/kr/pretty v0.3.1 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
golang.org/x/net v0.7.0 // indirect
|
||||
golang.org/x/text v0.7.0 // indirect
|
||||
github.com/spf13/pflag v1.0.6 // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.2 // indirect
|
||||
golang.org/x/net v0.41.0 // indirect
|
||||
golang.org/x/text v0.27.0 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
k8s.io/klog/v2 v2.80.1 // indirect
|
||||
k8s.io/utils v0.0.0-20221128185143-99ec85e7a448 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
|
||||
k8s.io/klog/v2 v2.130.1 // indirect
|
||||
k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e // indirect
|
||||
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
|
||||
sigs.k8s.io/randfill v1.0.0 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.7.0 // indirect
|
||||
sigs.k8s.io/yaml v1.5.0 // indirect
|
||||
)
|
||||
|
|
103
api/go.sum
103
api/go.sum
|
@ -1,38 +1,61 @@
|
|||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/fluxcd/pkg/apis/meta v0.19.0 h1:CX75e/eaRWZDTzNdMSWomY1InlssLKcS8GQDSg/aopI=
|
||||
github.com/fluxcd/pkg/apis/meta v0.19.0/go.mod h1:7b6prDPsViyAzoY7eRfSPS0/MbXpGGsOMvRq2QrTKa4=
|
||||
github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
|
||||
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/fluxcd/pkg/apis/meta v1.17.0 h1:KVMDyJQj1NYCsppsFUkbJGMnKxsqJVpnKBFolHf/q8E=
|
||||
github.com/fluxcd/pkg/apis/meta v1.17.0/go.mod h1:97l3hTwBpJbXBY+wetNbqrUsvES8B1jGioKcBUxmqd8=
|
||||
github.com/fxamacker/cbor/v2 v2.8.0 h1:fFtUGXUzXPHTIUdne5+zzMPTfffl3RD5qYnkY40vtxU=
|
||||
github.com/fxamacker/cbor/v2 v2.8.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
|
||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo=
|
||||
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/onsi/ginkgo/v2 v2.6.0 h1:9t9b9vRUbFq3C4qKFCGkVuq/fIHji802N1nrtkh1mNc=
|
||||
github.com/onsi/gomega v1.24.1 h1:KORJXNNTzJXzu4ScJWssJfJMnJ+2QJqhoQSRwNlze9E=
|
||||
github.com/onsi/ginkgo/v2 v2.22.0 h1:Yed107/8DjTr0lKCNt7Dn8yQ6ybuDRQoMGrNFKzMfHg=
|
||||
github.com/onsi/ginkgo/v2 v2.22.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=
|
||||
github.com/onsi/gomega v1.36.1 h1:bJDPBO7ibjxcbHMgSCoo4Yj18UWbKDlLwX1x9sybDcw=
|
||||
github.com/onsi/gomega v1.36.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
|
||||
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
||||
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
|
||||
go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
|
@ -42,46 +65,54 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
|
|||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
|
||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
|
||||
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
|
||||
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
|
||||
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
|
||||
golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo=
|
||||
golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
k8s.io/api v0.26.1 h1:f+SWYiPd/GsiWwVRz+NbFyCgvv75Pk9NK6dlkZgpCRQ=
|
||||
k8s.io/apimachinery v0.26.1 h1:8EZ/eGJL+hY/MYCNwhmDzVqq2lPl3N3Bo8rvweJwXUQ=
|
||||
k8s.io/apimachinery v0.26.1/go.mod h1:tnPmbONNJ7ByJNz9+n9kMjNP8ON+1qoAIIC70lztu74=
|
||||
k8s.io/klog/v2 v2.80.1 h1:atnLQ121W371wYYFawwYx1aEY2eUfs4l3J72wtgAwV4=
|
||||
k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
|
||||
k8s.io/utils v0.0.0-20221128185143-99ec85e7a448 h1:KTgPnR10d5zhztWptI952TNtt/4u5h3IzDXkdIMuo2Y=
|
||||
k8s.io/utils v0.0.0-20221128185143-99ec85e7a448/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||
sigs.k8s.io/controller-runtime v0.14.4 h1:Kd/Qgx5pd2XUL08eOV2vwIq3L9GhIbJ5Nxengbd4/0M=
|
||||
sigs.k8s.io/controller-runtime v0.14.4/go.mod h1:WqIdsAY6JBsjfc/CqO0CORmNtoCtE4S6qbPc9s68h+0=
|
||||
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 h1:iXTIw73aPyC+oRdyqqvVJuloN1p0AC/kzH07hu3NE+k=
|
||||
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E=
|
||||
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
k8s.io/api v0.33.0 h1:yTgZVn1XEe6opVpP1FylmNrIFWuDqe2H0V8CT5gxfIU=
|
||||
k8s.io/api v0.33.0/go.mod h1:CTO61ECK/KU7haa3qq8sarQ0biLq2ju405IZAd9zsiM=
|
||||
k8s.io/apimachinery v0.33.2 h1:IHFVhqg59mb8PJWTLi8m1mAoepkUNYmptHsV+Z1m5jY=
|
||||
k8s.io/apimachinery v0.33.2/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
|
||||
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
|
||||
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
||||
k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e h1:KqK5c/ghOm8xkHYhlodbp6i6+r+ChV2vuAuVRdFbLro=
|
||||
k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||
sigs.k8s.io/controller-runtime v0.21.0 h1:CYfjpEuicjUecRk+KAeyYh+ouUBn4llGyDYytIGcJS8=
|
||||
sigs.k8s.io/controller-runtime v0.21.0/go.mod h1:OSg14+F65eWqIu4DceX7k/+QRAbTTvxeQSNSOQpukWM=
|
||||
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE=
|
||||
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
|
||||
sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
|
||||
sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
|
||||
sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.7.0 h1:qPeWmscJcXP0snki5IYF79Z8xrl8ETFxgMd7wez1XkI=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.7.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps=
|
||||
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
|
||||
sigs.k8s.io/yaml v1.5.0 h1:M10b2U7aEUY6hRtU870n2VTPgR5RZiL/I6Lcc2F4NUQ=
|
||||
sigs.k8s.io/yaml v1.5.0/go.mod h1:wZs27Rbxoai4C0f8/9urLZtZtF3avA3gKvGyPdDqTO4=
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
Copyright 2023 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1
|
||||
|
||||
const NotificationFinalizer = "finalizers.fluxcd.io"
|
||||
|
||||
const (
|
||||
// InitializedReason represents the fact that a given resource has been initialized.
|
||||
InitializedReason string = "Initialized"
|
||||
|
||||
// ValidationFailedReason represents the fact that some part of the spec of a given resource
|
||||
// couldn't be validated.
|
||||
ValidationFailedReason string = "ValidationFailed"
|
||||
|
||||
// TokenNotFoundReason represents the fact that receiver token can't be found.
|
||||
TokenNotFoundReason string = "TokenNotFound"
|
||||
)
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2020 The Flux authors
|
||||
Copyright 2023 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
@ -14,16 +14,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package notifier
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
eventv1 "github.com/fluxcd/pkg/apis/event/v1beta1"
|
||||
)
|
||||
|
||||
type NopNotifier struct{}
|
||||
|
||||
func (n *NopNotifier) Post(ctx context.Context, event eventv1.Event) error {
|
||||
return nil
|
||||
}
|
||||
// Package v1 contains API Schema definitions for the notification v1 API group.
|
||||
// +kubebuilder:object:generate=true
|
||||
// +groupName=notification.toolkit.fluxcd.io
|
||||
package v1
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
Copyright 2023 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"sigs.k8s.io/controller-runtime/pkg/scheme"
|
||||
)
|
||||
|
||||
var (
|
||||
// GroupVersion is group version used to register these objects.
|
||||
GroupVersion = schema.GroupVersion{Group: "notification.toolkit.fluxcd.io", Version: "v1"}
|
||||
|
||||
// SchemeBuilder is used to add go types to the GroupVersionKind scheme.
|
||||
SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
|
||||
|
||||
// AddToScheme adds the types in this group-version to the given scheme.
|
||||
AddToScheme = SchemeBuilder.AddToScheme
|
||||
)
|
|
@ -0,0 +1,164 @@
|
|||
/*
|
||||
Copyright 2023 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
)
|
||||
|
||||
const (
|
||||
ReceiverKind string = "Receiver"
|
||||
ReceiverWebhookPath string = "/hook/"
|
||||
GenericReceiver string = "generic"
|
||||
GenericHMACReceiver string = "generic-hmac"
|
||||
GitHubReceiver string = "github"
|
||||
GitLabReceiver string = "gitlab"
|
||||
BitbucketReceiver string = "bitbucket"
|
||||
HarborReceiver string = "harbor"
|
||||
DockerHubReceiver string = "dockerhub"
|
||||
QuayReceiver string = "quay"
|
||||
GCRReceiver string = "gcr"
|
||||
NexusReceiver string = "nexus"
|
||||
ACRReceiver string = "acr"
|
||||
CDEventsReceiver string = "cdevents"
|
||||
)
|
||||
|
||||
// ReceiverSpec defines the desired state of the Receiver.
|
||||
type ReceiverSpec struct {
|
||||
// Type of webhook sender, used to determine
|
||||
// the validation procedure and payload deserialization.
|
||||
// +kubebuilder:validation:Enum=generic;generic-hmac;github;gitlab;bitbucket;harbor;dockerhub;quay;gcr;nexus;acr;cdevents
|
||||
// +required
|
||||
Type string `json:"type"`
|
||||
|
||||
// Interval at which to reconcile the Receiver with its Secret references.
|
||||
// +kubebuilder:validation:Type=string
|
||||
// +kubebuilder:validation:Pattern="^([0-9]+(\\.[0-9]+)?(ms|s|m|h))+$"
|
||||
// +kubebuilder:default:="10m"
|
||||
// +optional
|
||||
Interval *metav1.Duration `json:"interval,omitempty"`
|
||||
|
||||
// Events specifies the list of event types to handle,
|
||||
// e.g. 'push' for GitHub or 'Push Hook' for GitLab.
|
||||
// +optional
|
||||
Events []string `json:"events,omitempty"`
|
||||
|
||||
// A list of resources to be notified about changes.
|
||||
// +required
|
||||
Resources []CrossNamespaceObjectReference `json:"resources"`
|
||||
|
||||
// ResourceFilter is a CEL expression expected to return a boolean that is
|
||||
// evaluated for each resource referenced in the Resources field when a
|
||||
// webhook is received. If the expression returns false then the controller
|
||||
// will not request a reconciliation for the resource.
|
||||
// When the expression is specified the controller will parse it and mark
|
||||
// the object as terminally failed if the expression is invalid or does not
|
||||
// return a boolean.
|
||||
// +optional
|
||||
ResourceFilter string `json:"resourceFilter,omitempty"`
|
||||
|
||||
// SecretRef specifies the Secret containing the token used
|
||||
// to validate the payload authenticity.
|
||||
// +required
|
||||
SecretRef meta.LocalObjectReference `json:"secretRef"`
|
||||
|
||||
// Suspend tells the controller to suspend subsequent
|
||||
// events handling for this receiver.
|
||||
// +optional
|
||||
Suspend bool `json:"suspend,omitempty"`
|
||||
}
|
||||
|
||||
// ReceiverStatus defines the observed state of the Receiver.
|
||||
type ReceiverStatus struct {
|
||||
meta.ReconcileRequestStatus `json:",inline"`
|
||||
|
||||
// Conditions holds the conditions for the Receiver.
|
||||
// +optional
|
||||
Conditions []metav1.Condition `json:"conditions,omitempty"`
|
||||
|
||||
// WebhookPath is the generated incoming webhook address in the format
|
||||
// of '/hook/sha256sum(token+name+namespace)'.
|
||||
// +optional
|
||||
WebhookPath string `json:"webhookPath,omitempty"`
|
||||
|
||||
// ObservedGeneration is the last observed generation of the Receiver object.
|
||||
// +optional
|
||||
ObservedGeneration int64 `json:"observedGeneration,omitempty"`
|
||||
}
|
||||
|
||||
// GetConditions returns the status conditions of the object.
|
||||
func (in *Receiver) GetConditions() []metav1.Condition {
|
||||
return in.Status.Conditions
|
||||
}
|
||||
|
||||
// SetConditions sets the status conditions on the object.
|
||||
func (in *Receiver) SetConditions(conditions []metav1.Condition) {
|
||||
in.Status.Conditions = conditions
|
||||
}
|
||||
|
||||
// GetWebhookPath returns the incoming webhook path for the given token.
|
||||
func (in *Receiver) GetWebhookPath(token string) string {
|
||||
digest := sha256.Sum256([]byte(token + in.GetName() + in.GetNamespace()))
|
||||
return fmt.Sprintf("%s%x", ReceiverWebhookPath, digest)
|
||||
}
|
||||
|
||||
// GetInterval returns the interval value with a default of 10m for this Receiver.
|
||||
func (in *Receiver) GetInterval() time.Duration {
|
||||
duration := 10 * time.Minute
|
||||
if in.Spec.Interval != nil {
|
||||
duration = in.Spec.Interval.Duration
|
||||
}
|
||||
|
||||
return duration
|
||||
}
|
||||
|
||||
// +genclient
|
||||
// +kubebuilder:storageversion
|
||||
// +kubebuilder:object:root=true
|
||||
// +kubebuilder:subresource:status
|
||||
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description=""
|
||||
// +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].status",description=""
|
||||
// +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].message",description=""
|
||||
|
||||
// Receiver is the Schema for the receivers API.
|
||||
type Receiver struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
Spec ReceiverSpec `json:"spec,omitempty"`
|
||||
// +kubebuilder:default:={"observedGeneration":-1}
|
||||
Status ReceiverStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// +kubebuilder:object:root=true
|
||||
|
||||
// ReceiverList contains a list of Receivers.
|
||||
type ReceiverList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata,omitempty"`
|
||||
Items []Receiver `json:"items"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
SchemeBuilder.Register(&Receiver{}, &ReceiverList{})
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
Copyright 2023 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1
|
||||
|
||||
// CrossNamespaceObjectReference contains enough information to let you locate the
|
||||
// typed referenced object at cluster level
|
||||
type CrossNamespaceObjectReference struct {
|
||||
// API version of the referent
|
||||
// +optional
|
||||
APIVersion string `json:"apiVersion,omitempty"`
|
||||
|
||||
// Kind of the referent
|
||||
// +kubebuilder:validation:Enum=Bucket;GitRepository;Kustomization;HelmRelease;HelmChart;HelmRepository;ImageRepository;ImagePolicy;ImageUpdateAutomation;OCIRepository
|
||||
// +required
|
||||
Kind string `json:"kind"`
|
||||
|
||||
// Name of the referent
|
||||
// If multiple resources are targeted `*` may be set.
|
||||
// +kubebuilder:validation:MinLength=1
|
||||
// +kubebuilder:validation:MaxLength=253
|
||||
// +required
|
||||
Name string `json:"name"`
|
||||
|
||||
// Namespace of the referent
|
||||
// +kubebuilder:validation:MinLength=1
|
||||
// +kubebuilder:validation:MaxLength=253
|
||||
// +kubebuilder:validation:Optional
|
||||
// +optional
|
||||
Namespace string `json:"namespace,omitempty"`
|
||||
|
||||
// MatchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
|
||||
// map is equivalent to an element of matchExpressions, whose key field is "key", the
|
||||
// operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||
// MatchLabels requires the name to be set to `*`.
|
||||
// +optional
|
||||
MatchLabels map[string]string `json:"matchLabels,omitempty"`
|
||||
}
|
|
@ -0,0 +1,163 @@
|
|||
//go:build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
Copyright 2023 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Code generated by controller-gen. DO NOT EDIT.
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CrossNamespaceObjectReference) DeepCopyInto(out *CrossNamespaceObjectReference) {
|
||||
*out = *in
|
||||
if in.MatchLabels != nil {
|
||||
in, out := &in.MatchLabels, &out.MatchLabels
|
||||
*out = make(map[string]string, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CrossNamespaceObjectReference.
|
||||
func (in *CrossNamespaceObjectReference) DeepCopy() *CrossNamespaceObjectReference {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CrossNamespaceObjectReference)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Receiver) DeepCopyInto(out *Receiver) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
in.Status.DeepCopyInto(&out.Status)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Receiver.
|
||||
func (in *Receiver) DeepCopy() *Receiver {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Receiver)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *Receiver) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ReceiverList) DeepCopyInto(out *ReceiverList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]Receiver, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReceiverList.
|
||||
func (in *ReceiverList) DeepCopy() *ReceiverList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ReceiverList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *ReceiverList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ReceiverSpec) DeepCopyInto(out *ReceiverSpec) {
|
||||
*out = *in
|
||||
if in.Interval != nil {
|
||||
in, out := &in.Interval, &out.Interval
|
||||
*out = new(metav1.Duration)
|
||||
**out = **in
|
||||
}
|
||||
if in.Events != nil {
|
||||
in, out := &in.Events, &out.Events
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.Resources != nil {
|
||||
in, out := &in.Resources, &out.Resources
|
||||
*out = make([]CrossNamespaceObjectReference, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
out.SecretRef = in.SecretRef
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReceiverSpec.
|
||||
func (in *ReceiverSpec) DeepCopy() *ReceiverSpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ReceiverSpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ReceiverStatus) DeepCopyInto(out *ReceiverStatus) {
|
||||
*out = *in
|
||||
out.ReconcileRequestStatus = in.ReconcileRequestStatus
|
||||
if in.Conditions != nil {
|
||||
in, out := &in.Conditions, &out.Conditions
|
||||
*out = make([]metav1.Condition, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReceiverStatus.
|
||||
func (in *ReceiverStatus) DeepCopy() *ReceiverStatus {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ReceiverStatus)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
|
@ -67,9 +67,9 @@ type AlertStatus struct {
|
|||
}
|
||||
|
||||
// +genclient
|
||||
// +genclient:Namespaced
|
||||
// +kubebuilder:object:root=true
|
||||
// +kubebuilder:subresource:status
|
||||
// +kubebuilder:deprecatedversion:warning="v1beta1 Alert is deprecated, upgrade to v1beta3"
|
||||
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description=""
|
||||
// +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].status",description=""
|
||||
// +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].message",description=""
|
||||
|
|
|
@ -110,9 +110,9 @@ type ProviderStatus struct {
|
|||
}
|
||||
|
||||
// +genclient
|
||||
// +genclient:Namespaced
|
||||
// +kubebuilder:object:root=true
|
||||
// +kubebuilder:subresource:status
|
||||
// +kubebuilder:deprecatedversion:warning="v1beta1 Provider is deprecated, upgrade to v1beta3"
|
||||
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description=""
|
||||
// +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].status",description=""
|
||||
// +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].message",description=""
|
||||
|
|
|
@ -97,9 +97,9 @@ func (in *Receiver) SetConditions(conditions []metav1.Condition) {
|
|||
}
|
||||
|
||||
// +genclient
|
||||
// +genclient:Namespaced
|
||||
// +kubebuilder:object:root=true
|
||||
// +kubebuilder:subresource:status
|
||||
// +kubebuilder:deprecatedversion:warning="v1beta1 Receiver is deprecated, upgrade to v1"
|
||||
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description=""
|
||||
// +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].status",description=""
|
||||
// +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].message",description=""
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
//go:build !ignore_autogenerated
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
Copyright 2022 The Flux authors
|
||||
Copyright 2023 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -19,6 +19,8 @@ package v1beta2
|
|||
import (
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
v1 "github.com/fluxcd/notification-controller/api/v1"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -41,7 +43,20 @@ type AlertSpec struct {
|
|||
// EventSources specifies how to filter events based
|
||||
// on the involved object kind, name and namespace.
|
||||
// +required
|
||||
EventSources []CrossNamespaceObjectReference `json:"eventSources"`
|
||||
EventSources []v1.CrossNamespaceObjectReference `json:"eventSources"`
|
||||
|
||||
// InclusionList specifies a list of Golang regular expressions
|
||||
// to be used for including messages.
|
||||
// +optional
|
||||
InclusionList []string `json:"inclusionList,omitempty"`
|
||||
|
||||
// EventMetadata is an optional field for adding metadata to events dispatched by the
|
||||
// controller. This can be used for enhancing the context of the event. If a field
|
||||
// would override one already present on the original event as generated by the emitter,
|
||||
// then the override doesn't happen, i.e. the original value is preserved, and an info
|
||||
// log is printed.
|
||||
// +optional
|
||||
EventMetadata map[string]string `json:"eventMetadata,omitempty"`
|
||||
|
||||
// ExclusionList specifies a list of Golang regular expressions
|
||||
// to be used for excluding messages.
|
||||
|
@ -73,10 +88,9 @@ type AlertStatus struct {
|
|||
}
|
||||
|
||||
// +genclient
|
||||
// +genclient:Namespaced
|
||||
// +kubebuilder:storageversion
|
||||
// +kubebuilder:object:root=true
|
||||
// +kubebuilder:subresource:status
|
||||
// +kubebuilder:deprecatedversion:warning="v1beta2 Alert is deprecated, upgrade to v1beta3"
|
||||
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description=""
|
||||
// +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].status",description=""
|
||||
// +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].message",description=""
|
||||
|
|
|
@ -24,35 +24,39 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
ProviderKind string = "Provider"
|
||||
GenericProvider string = "generic"
|
||||
GenericHMACProvider string = "generic-hmac"
|
||||
SlackProvider string = "slack"
|
||||
GrafanaProvider string = "grafana"
|
||||
DiscordProvider string = "discord"
|
||||
MSTeamsProvider string = "msteams"
|
||||
RocketProvider string = "rocket"
|
||||
GitHubDispatchProvider string = "githubdispatch"
|
||||
GitHubProvider string = "github"
|
||||
GitLabProvider string = "gitlab"
|
||||
GiteaProvider string = "gitea"
|
||||
BitbucketProvider string = "bitbucket"
|
||||
AzureDevOpsProvider string = "azuredevops"
|
||||
GoogleChatProvider string = "googlechat"
|
||||
WebexProvider string = "webex"
|
||||
SentryProvider string = "sentry"
|
||||
AzureEventHubProvider string = "azureeventhub"
|
||||
TelegramProvider string = "telegram"
|
||||
LarkProvider string = "lark"
|
||||
Matrix string = "matrix"
|
||||
OpsgenieProvider string = "opsgenie"
|
||||
AlertManagerProvider string = "alertmanager"
|
||||
ProviderKind string = "Provider"
|
||||
GenericProvider string = "generic"
|
||||
GenericHMACProvider string = "generic-hmac"
|
||||
SlackProvider string = "slack"
|
||||
GrafanaProvider string = "grafana"
|
||||
DiscordProvider string = "discord"
|
||||
MSTeamsProvider string = "msteams"
|
||||
RocketProvider string = "rocket"
|
||||
GitHubDispatchProvider string = "githubdispatch"
|
||||
GitHubProvider string = "github"
|
||||
GitLabProvider string = "gitlab"
|
||||
GiteaProvider string = "gitea"
|
||||
BitbucketServerProvider string = "bitbucketserver"
|
||||
BitbucketProvider string = "bitbucket"
|
||||
AzureDevOpsProvider string = "azuredevops"
|
||||
GoogleChatProvider string = "googlechat"
|
||||
GooglePubSubProvider string = "googlepubsub"
|
||||
WebexProvider string = "webex"
|
||||
SentryProvider string = "sentry"
|
||||
AzureEventHubProvider string = "azureeventhub"
|
||||
TelegramProvider string = "telegram"
|
||||
LarkProvider string = "lark"
|
||||
Matrix string = "matrix"
|
||||
OpsgenieProvider string = "opsgenie"
|
||||
AlertManagerProvider string = "alertmanager"
|
||||
PagerDutyProvider string = "pagerduty"
|
||||
DataDogProvider string = "datadog"
|
||||
)
|
||||
|
||||
// ProviderSpec defines the desired state of the Provider.
|
||||
type ProviderSpec struct {
|
||||
// Type specifies which Provider implementation to use.
|
||||
// +kubebuilder:validation:Enum=slack;discord;msteams;rocket;generic;generic-hmac;github;gitlab;gitea;bitbucket;azuredevops;googlechat;webex;sentry;azureeventhub;telegram;lark;matrix;opsgenie;alertmanager;grafana;githubdispatch;
|
||||
// +kubebuilder:validation:Enum=slack;discord;msteams;rocket;generic;generic-hmac;github;gitlab;gitea;bitbucketserver;bitbucket;azuredevops;googlechat;googlepubsub;webex;sentry;azureeventhub;telegram;lark;matrix;opsgenie;alertmanager;grafana;githubdispatch;pagerduty;datadog
|
||||
// +required
|
||||
Type string `json:"type"`
|
||||
|
||||
|
@ -72,8 +76,10 @@ type ProviderSpec struct {
|
|||
// +optional
|
||||
Username string `json:"username,omitempty"`
|
||||
|
||||
// Address specifies the HTTP/S incoming webhook address of this Provider.
|
||||
// +kubebuilder:validation:Pattern="^(http|https)://.*$"
|
||||
// Address specifies the endpoint, in a generic sense, to where alerts are sent.
|
||||
// What kind of endpoint depends on the specific Provider type being used.
|
||||
// For the generic Provider, for example, this is an HTTP/S address.
|
||||
// For other Provider types this could be a project ID or a namespace.
|
||||
// +kubebuilder:validation:MaxLength:=2048
|
||||
// +kubebuilder:validation:Optional
|
||||
// +optional
|
||||
|
@ -98,8 +104,11 @@ type ProviderSpec struct {
|
|||
SecretRef *meta.LocalObjectReference `json:"secretRef,omitempty"`
|
||||
|
||||
// CertSecretRef specifies the Secret containing
|
||||
// a PEM-encoded CA certificate (`caFile`).
|
||||
// a PEM-encoded CA certificate (in the `ca.crt` key).
|
||||
// +optional
|
||||
//
|
||||
// Note: Support for the `caFile` key has
|
||||
// been deprecated.
|
||||
CertSecretRef *meta.LocalObjectReference `json:"certSecretRef,omitempty"`
|
||||
|
||||
// Suspend tells the controller to suspend subsequent
|
||||
|
@ -122,10 +131,9 @@ type ProviderStatus struct {
|
|||
}
|
||||
|
||||
// +genclient
|
||||
// +genclient:Namespaced
|
||||
// +kubebuilder:storageversion
|
||||
// +kubebuilder:object:root=true
|
||||
// +kubebuilder:subresource:status
|
||||
// +kubebuilder:deprecatedversion:warning="v1beta2 Provider is deprecated, upgrade to v1beta3"
|
||||
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description=""
|
||||
// +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].status",description=""
|
||||
// +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].message",description=""
|
||||
|
|
|
@ -24,6 +24,8 @@ import (
|
|||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
|
||||
v1 "github.com/fluxcd/notification-controller/api/v1"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -63,7 +65,7 @@ type ReceiverSpec struct {
|
|||
|
||||
// A list of resources to be notified about changes.
|
||||
// +required
|
||||
Resources []CrossNamespaceObjectReference `json:"resources"`
|
||||
Resources []v1.CrossNamespaceObjectReference `json:"resources"`
|
||||
|
||||
// SecretRef specifies the Secret containing the token used
|
||||
// to validate the payload authenticity.
|
||||
|
@ -127,10 +129,9 @@ func (in *Receiver) GetInterval() time.Duration {
|
|||
}
|
||||
|
||||
// +genclient
|
||||
// +genclient:Namespaced
|
||||
// +kubebuilder:storageversion
|
||||
// +kubebuilder:object:root=true
|
||||
// +kubebuilder:subresource:status
|
||||
// +kubebuilder:deprecatedversion:warning="v1beta2 Receiver is deprecated, upgrade to v1"
|
||||
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description=""
|
||||
// +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].status",description=""
|
||||
// +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].message",description=""
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
//go:build !ignore_autogenerated
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
Copyright 2022 The Flux authors
|
||||
Copyright 2023 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
@ -22,8 +21,9 @@ limitations under the License.
|
|||
package v1beta2
|
||||
|
||||
import (
|
||||
"github.com/fluxcd/notification-controller/api/v1"
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
|
@ -92,11 +92,23 @@ func (in *AlertSpec) DeepCopyInto(out *AlertSpec) {
|
|||
out.ProviderRef = in.ProviderRef
|
||||
if in.EventSources != nil {
|
||||
in, out := &in.EventSources, &out.EventSources
|
||||
*out = make([]CrossNamespaceObjectReference, len(*in))
|
||||
*out = make([]v1.CrossNamespaceObjectReference, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.InclusionList != nil {
|
||||
in, out := &in.InclusionList, &out.InclusionList
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.EventMetadata != nil {
|
||||
in, out := &in.EventMetadata, &out.EventMetadata
|
||||
*out = make(map[string]string, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
if in.ExclusionList != nil {
|
||||
in, out := &in.ExclusionList, &out.ExclusionList
|
||||
*out = make([]string, len(*in))
|
||||
|
@ -120,7 +132,7 @@ func (in *AlertStatus) DeepCopyInto(out *AlertStatus) {
|
|||
out.ReconcileRequestStatus = in.ReconcileRequestStatus
|
||||
if in.Conditions != nil {
|
||||
in, out := &in.Conditions, &out.Conditions
|
||||
*out = make([]v1.Condition, len(*in))
|
||||
*out = make([]metav1.Condition, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
|
@ -223,12 +235,12 @@ func (in *ProviderSpec) DeepCopyInto(out *ProviderSpec) {
|
|||
*out = *in
|
||||
if in.Interval != nil {
|
||||
in, out := &in.Interval, &out.Interval
|
||||
*out = new(v1.Duration)
|
||||
*out = new(metav1.Duration)
|
||||
**out = **in
|
||||
}
|
||||
if in.Timeout != nil {
|
||||
in, out := &in.Timeout, &out.Timeout
|
||||
*out = new(v1.Duration)
|
||||
*out = new(metav1.Duration)
|
||||
**out = **in
|
||||
}
|
||||
if in.SecretRef != nil {
|
||||
|
@ -259,7 +271,7 @@ func (in *ProviderStatus) DeepCopyInto(out *ProviderStatus) {
|
|||
out.ReconcileRequestStatus = in.ReconcileRequestStatus
|
||||
if in.Conditions != nil {
|
||||
in, out := &in.Conditions, &out.Conditions
|
||||
*out = make([]v1.Condition, len(*in))
|
||||
*out = make([]metav1.Condition, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
|
@ -340,7 +352,7 @@ func (in *ReceiverSpec) DeepCopyInto(out *ReceiverSpec) {
|
|||
*out = *in
|
||||
if in.Interval != nil {
|
||||
in, out := &in.Interval, &out.Interval
|
||||
*out = new(v1.Duration)
|
||||
*out = new(metav1.Duration)
|
||||
**out = **in
|
||||
}
|
||||
if in.Events != nil {
|
||||
|
@ -350,7 +362,7 @@ func (in *ReceiverSpec) DeepCopyInto(out *ReceiverSpec) {
|
|||
}
|
||||
if in.Resources != nil {
|
||||
in, out := &in.Resources, &out.Resources
|
||||
*out = make([]CrossNamespaceObjectReference, len(*in))
|
||||
*out = make([]v1.CrossNamespaceObjectReference, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
|
@ -374,7 +386,7 @@ func (in *ReceiverStatus) DeepCopyInto(out *ReceiverStatus) {
|
|||
out.ReconcileRequestStatus = in.ReconcileRequestStatus
|
||||
if in.Conditions != nil {
|
||||
in, out := &in.Conditions, &out.Conditions
|
||||
*out = make([]v1.Condition, len(*in))
|
||||
*out = make([]metav1.Condition, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
Copyright 2023 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1beta3
|
||||
|
||||
import (
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
v1 "github.com/fluxcd/notification-controller/api/v1"
|
||||
)
|
||||
|
||||
const (
|
||||
AlertKind string = "Alert"
|
||||
)
|
||||
|
||||
// AlertSpec defines an alerting rule for events involving a list of objects.
|
||||
type AlertSpec struct {
|
||||
// ProviderRef specifies which Provider this Alert should use.
|
||||
// +required
|
||||
ProviderRef meta.LocalObjectReference `json:"providerRef"`
|
||||
|
||||
// EventSeverity specifies how to filter events based on severity.
|
||||
// If set to 'info' no events will be filtered.
|
||||
// +kubebuilder:validation:Enum=info;error
|
||||
// +kubebuilder:default:=info
|
||||
// +optional
|
||||
EventSeverity string `json:"eventSeverity,omitempty"`
|
||||
|
||||
// EventSources specifies how to filter events based
|
||||
// on the involved object kind, name and namespace.
|
||||
// +required
|
||||
EventSources []v1.CrossNamespaceObjectReference `json:"eventSources"`
|
||||
|
||||
// InclusionList specifies a list of Golang regular expressions
|
||||
// to be used for including messages.
|
||||
// +optional
|
||||
InclusionList []string `json:"inclusionList,omitempty"`
|
||||
|
||||
// EventMetadata is an optional field for adding metadata to events dispatched by the
|
||||
// controller. This can be used for enhancing the context of the event. If a field
|
||||
// would override one already present on the original event as generated by the emitter,
|
||||
// then the override doesn't happen, i.e. the original value is preserved, and an info
|
||||
// log is printed.
|
||||
// +optional
|
||||
EventMetadata map[string]string `json:"eventMetadata,omitempty"`
|
||||
|
||||
// ExclusionList specifies a list of Golang regular expressions
|
||||
// to be used for excluding messages.
|
||||
// +optional
|
||||
ExclusionList []string `json:"exclusionList,omitempty"`
|
||||
|
||||
// Summary holds a short description of the impact and affected cluster.
|
||||
// Deprecated: Use EventMetadata instead.
|
||||
//
|
||||
// +kubebuilder:validation:MaxLength:=255
|
||||
// +optional
|
||||
// +deprecated
|
||||
Summary string `json:"summary,omitempty"`
|
||||
|
||||
// Suspend tells the controller to suspend subsequent
|
||||
// events handling for this Alert.
|
||||
// +optional
|
||||
Suspend bool `json:"suspend,omitempty"`
|
||||
}
|
||||
|
||||
// +genclient
|
||||
// +kubebuilder:storageversion
|
||||
// +kubebuilder:object:root=true
|
||||
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description=""
|
||||
|
||||
// Alert is the Schema for the alerts API
|
||||
type Alert struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
Spec AlertSpec `json:"spec,omitempty"`
|
||||
}
|
||||
|
||||
//+kubebuilder:object:root=true
|
||||
|
||||
// AlertList contains a list of Alert
|
||||
type AlertList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata,omitempty"`
|
||||
Items []Alert `json:"items"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
SchemeBuilder.Register(&Alert{}, &AlertList{})
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
Copyright 2023 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package v1beta3 contains API Schema definitions for the notification v1beta3 API group.
|
||||
// +kubebuilder:object:generate=true
|
||||
// +groupName=notification.toolkit.fluxcd.io
|
||||
package v1beta3
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
Copyright 2023 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1beta3
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"sigs.k8s.io/controller-runtime/pkg/scheme"
|
||||
)
|
||||
|
||||
var (
|
||||
// GroupVersion is group version used to register these objects
|
||||
GroupVersion = schema.GroupVersion{Group: "notification.toolkit.fluxcd.io", Version: "v1beta3"}
|
||||
|
||||
// SchemeBuilder is used to add go types to the GroupVersionKind scheme
|
||||
SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
|
||||
|
||||
// AddToScheme adds the types in this group-version to the given scheme.
|
||||
AddToScheme = SchemeBuilder.AddToScheme
|
||||
)
|
|
@ -0,0 +1,187 @@
|
|||
/*
|
||||
Copyright 2023 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1beta3
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
const (
|
||||
ProviderKind string = "Provider"
|
||||
GenericProvider string = "generic"
|
||||
GenericHMACProvider string = "generic-hmac"
|
||||
SlackProvider string = "slack"
|
||||
GrafanaProvider string = "grafana"
|
||||
DiscordProvider string = "discord"
|
||||
MSTeamsProvider string = "msteams"
|
||||
RocketProvider string = "rocket"
|
||||
GitHubDispatchProvider string = "githubdispatch"
|
||||
GitHubProvider string = "github"
|
||||
GitLabProvider string = "gitlab"
|
||||
GiteaProvider string = "gitea"
|
||||
BitbucketServerProvider string = "bitbucketserver"
|
||||
BitbucketProvider string = "bitbucket"
|
||||
AzureDevOpsProvider string = "azuredevops"
|
||||
GoogleChatProvider string = "googlechat"
|
||||
GooglePubSubProvider string = "googlepubsub"
|
||||
WebexProvider string = "webex"
|
||||
SentryProvider string = "sentry"
|
||||
AzureEventHubProvider string = "azureeventhub"
|
||||
TelegramProvider string = "telegram"
|
||||
LarkProvider string = "lark"
|
||||
Matrix string = "matrix"
|
||||
OpsgenieProvider string = "opsgenie"
|
||||
AlertManagerProvider string = "alertmanager"
|
||||
PagerDutyProvider string = "pagerduty"
|
||||
DataDogProvider string = "datadog"
|
||||
NATSProvider string = "nats"
|
||||
)
|
||||
|
||||
// ProviderSpec defines the desired state of the Provider.
|
||||
// +kubebuilder:validation:XValidation:rule="self.type == 'github' || self.type == 'gitlab' || self.type == 'gitea' || self.type == 'bitbucketserver' || self.type == 'bitbucket' || self.type == 'azuredevops' || !has(self.commitStatusExpr)", message="spec.commitStatusExpr is only supported for the 'github', 'gitlab', 'gitea', 'bitbucketserver', 'bitbucket', 'azuredevops' provider types"
|
||||
type ProviderSpec struct {
|
||||
// Type specifies which Provider implementation to use.
|
||||
// +kubebuilder:validation:Enum=slack;discord;msteams;rocket;generic;generic-hmac;github;gitlab;gitea;bitbucketserver;bitbucket;azuredevops;googlechat;googlepubsub;webex;sentry;azureeventhub;telegram;lark;matrix;opsgenie;alertmanager;grafana;githubdispatch;pagerduty;datadog;nats
|
||||
// +required
|
||||
Type string `json:"type"`
|
||||
|
||||
// Interval at which to reconcile the Provider with its Secret references.
|
||||
// Deprecated and not used in v1beta3.
|
||||
//
|
||||
// +kubebuilder:validation:Type=string
|
||||
// +kubebuilder:validation:Pattern="^([0-9]+(\\.[0-9]+)?(ms|s|m|h))+$"
|
||||
// +optional
|
||||
// +deprecated
|
||||
Interval *metav1.Duration `json:"interval,omitempty"`
|
||||
|
||||
// Channel specifies the destination channel where events should be posted.
|
||||
// +kubebuilder:validation:MaxLength:=2048
|
||||
// +optional
|
||||
Channel string `json:"channel,omitempty"`
|
||||
|
||||
// Username specifies the name under which events are posted.
|
||||
// +kubebuilder:validation:MaxLength:=2048
|
||||
// +optional
|
||||
Username string `json:"username,omitempty"`
|
||||
|
||||
// Address specifies the endpoint, in a generic sense, to where alerts are sent.
|
||||
// What kind of endpoint depends on the specific Provider type being used.
|
||||
// For the generic Provider, for example, this is an HTTP/S address.
|
||||
// For other Provider types this could be a project ID or a namespace.
|
||||
// +kubebuilder:validation:MaxLength:=2048
|
||||
// +kubebuilder:validation:Optional
|
||||
// +optional
|
||||
Address string `json:"address,omitempty"`
|
||||
|
||||
// Timeout for sending alerts to the Provider.
|
||||
// +kubebuilder:validation:Type=string
|
||||
// +kubebuilder:validation:Pattern="^([0-9]+(\\.[0-9]+)?(ms|s|m))+$"
|
||||
// +optional
|
||||
Timeout *metav1.Duration `json:"timeout,omitempty"`
|
||||
|
||||
// Proxy the HTTP/S address of the proxy server.
|
||||
// Deprecated: Use ProxySecretRef instead. Will be removed in v1.
|
||||
// +kubebuilder:validation:Pattern="^(http|https)://.*$"
|
||||
// +kubebuilder:validation:MaxLength:=2048
|
||||
// +kubebuilder:validation:Optional
|
||||
// +optional
|
||||
Proxy string `json:"proxy,omitempty"`
|
||||
|
||||
// ProxySecretRef specifies the Secret containing the proxy configuration
|
||||
// for this Provider. The Secret should contain an 'address' key with the
|
||||
// HTTP/S address of the proxy server. Optional 'username' and 'password'
|
||||
// keys can be provided for proxy authentication.
|
||||
// +optional
|
||||
ProxySecretRef *meta.LocalObjectReference `json:"proxySecretRef,omitempty"`
|
||||
|
||||
// SecretRef specifies the Secret containing the authentication
|
||||
// credentials for this Provider.
|
||||
// +optional
|
||||
SecretRef *meta.LocalObjectReference `json:"secretRef,omitempty"`
|
||||
|
||||
// ServiceAccountName is the name of the service account used to
|
||||
// authenticate with services from cloud providers. An error is thrown if a
|
||||
// static credential is also defined inside the Secret referenced by the
|
||||
// SecretRef.
|
||||
// +optional
|
||||
ServiceAccountName string `json:"serviceAccountName,omitempty"`
|
||||
|
||||
// CertSecretRef specifies the Secret containing TLS certificates
|
||||
// for secure communication.
|
||||
//
|
||||
// Supported configurations:
|
||||
// - CA-only: Server authentication (provide ca.crt only)
|
||||
// - mTLS: Mutual authentication (provide ca.crt + tls.crt + tls.key)
|
||||
// - Client-only: Client authentication with system CA (provide tls.crt + tls.key only)
|
||||
//
|
||||
// Legacy keys "caFile", "certFile", "keyFile" are supported but deprecated. Use "ca.crt", "tls.crt", "tls.key" instead.
|
||||
//
|
||||
// +optional
|
||||
CertSecretRef *meta.LocalObjectReference `json:"certSecretRef,omitempty"`
|
||||
|
||||
// Suspend tells the controller to suspend subsequent
|
||||
// events handling for this Provider.
|
||||
// +optional
|
||||
Suspend bool `json:"suspend,omitempty"`
|
||||
|
||||
// CommitStatusExpr is a CEL expression that evaluates to a string value
|
||||
// that can be used to generate a custom commit status message for use
|
||||
// with eligible Provider types (github, gitlab, gitea, bitbucketserver,
|
||||
// bitbucket, azuredevops). Supported variables are: event, provider,
|
||||
// and alert.
|
||||
// +optional
|
||||
CommitStatusExpr string `json:"commitStatusExpr,omitempty"`
|
||||
}
|
||||
|
||||
// +genclient
|
||||
// +kubebuilder:storageversion
|
||||
// +kubebuilder:object:root=true
|
||||
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description=""
|
||||
|
||||
// Provider is the Schema for the providers API
|
||||
type Provider struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
Spec ProviderSpec `json:"spec,omitempty"`
|
||||
}
|
||||
|
||||
//+kubebuilder:object:root=true
|
||||
|
||||
// ProviderList contains a list of Provider
|
||||
type ProviderList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata,omitempty"`
|
||||
Items []Provider `json:"items"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
SchemeBuilder.Register(&Provider{}, &ProviderList{})
|
||||
}
|
||||
|
||||
// GetTimeout returns the timeout value with a default of 15s for this Provider.
|
||||
func (in *Provider) GetTimeout() time.Duration {
|
||||
duration := 15 * time.Second
|
||||
if in.Spec.Timeout != nil {
|
||||
duration = in.Spec.Timeout.Duration
|
||||
}
|
||||
|
||||
return duration
|
||||
}
|
|
@ -0,0 +1,224 @@
|
|||
//go:build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
Copyright 2023 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Code generated by controller-gen. DO NOT EDIT.
|
||||
|
||||
package v1beta3
|
||||
|
||||
import (
|
||||
"github.com/fluxcd/notification-controller/api/v1"
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Alert) DeepCopyInto(out *Alert) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Alert.
|
||||
func (in *Alert) DeepCopy() *Alert {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Alert)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *Alert) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *AlertList) DeepCopyInto(out *AlertList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]Alert, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AlertList.
|
||||
func (in *AlertList) DeepCopy() *AlertList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(AlertList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *AlertList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *AlertSpec) DeepCopyInto(out *AlertSpec) {
|
||||
*out = *in
|
||||
out.ProviderRef = in.ProviderRef
|
||||
if in.EventSources != nil {
|
||||
in, out := &in.EventSources, &out.EventSources
|
||||
*out = make([]v1.CrossNamespaceObjectReference, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.InclusionList != nil {
|
||||
in, out := &in.InclusionList, &out.InclusionList
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.EventMetadata != nil {
|
||||
in, out := &in.EventMetadata, &out.EventMetadata
|
||||
*out = make(map[string]string, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
if in.ExclusionList != nil {
|
||||
in, out := &in.ExclusionList, &out.ExclusionList
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AlertSpec.
|
||||
func (in *AlertSpec) DeepCopy() *AlertSpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(AlertSpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Provider) DeepCopyInto(out *Provider) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Provider.
|
||||
func (in *Provider) DeepCopy() *Provider {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Provider)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *Provider) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ProviderList) DeepCopyInto(out *ProviderList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]Provider, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderList.
|
||||
func (in *ProviderList) DeepCopy() *ProviderList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ProviderList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *ProviderList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ProviderSpec) DeepCopyInto(out *ProviderSpec) {
|
||||
*out = *in
|
||||
if in.Interval != nil {
|
||||
in, out := &in.Interval, &out.Interval
|
||||
*out = new(metav1.Duration)
|
||||
**out = **in
|
||||
}
|
||||
if in.Timeout != nil {
|
||||
in, out := &in.Timeout, &out.Timeout
|
||||
*out = new(metav1.Duration)
|
||||
**out = **in
|
||||
}
|
||||
if in.ProxySecretRef != nil {
|
||||
in, out := &in.ProxySecretRef, &out.ProxySecretRef
|
||||
*out = new(meta.LocalObjectReference)
|
||||
**out = **in
|
||||
}
|
||||
if in.SecretRef != nil {
|
||||
in, out := &in.SecretRef, &out.SecretRef
|
||||
*out = new(meta.LocalObjectReference)
|
||||
**out = **in
|
||||
}
|
||||
if in.CertSecretRef != nil {
|
||||
in, out := &in.CertSecretRef, &out.CertSecretRef
|
||||
*out = new(meta.LocalObjectReference)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderSpec.
|
||||
func (in *ProviderSpec) DeepCopy() *ProviderSpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ProviderSpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
|
@ -3,8 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
|
|||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.11.1
|
||||
creationTimestamp: null
|
||||
controller-gen.kubebuilder.io/version: v0.16.1
|
||||
name: alerts.notification.toolkit.fluxcd.io
|
||||
spec:
|
||||
group: notification.toolkit.fluxcd.io
|
||||
|
@ -25,20 +24,27 @@ spec:
|
|||
- jsonPath: .status.conditions[?(@.type=="Ready")].message
|
||||
name: Status
|
||||
type: string
|
||||
deprecated: true
|
||||
deprecationWarning: v1beta1 Alert is deprecated, upgrade to v1beta3
|
||||
name: v1beta1
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: Alert is the Schema for the alerts API
|
||||
properties:
|
||||
apiVersion:
|
||||
description: 'APIVersion defines the versioned schema of this representation
|
||||
of an object. Servers should convert recognized schemas to the latest
|
||||
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
||||
description: |-
|
||||
APIVersion defines the versioned schema of this representation of an object.
|
||||
Servers should convert recognized schemas to the latest internal value, and
|
||||
may reject unrecognized values.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
|
||||
type: string
|
||||
kind:
|
||||
description: 'Kind is a string value representing the REST resource this
|
||||
object represents. Servers may infer this from the endpoint the client
|
||||
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||
description: |-
|
||||
Kind is a string value representing the REST resource this object represents.
|
||||
Servers may infer this from the endpoint the client submits requests to.
|
||||
Cannot be updated.
|
||||
In CamelCase.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
|
@ -48,7 +54,8 @@ spec:
|
|||
properties:
|
||||
eventSeverity:
|
||||
default: info
|
||||
description: Filter events based on severity, defaults to ('info').
|
||||
description: |-
|
||||
Filter events based on severity, defaults to ('info').
|
||||
If set to 'info' no events will be filtered.
|
||||
enum:
|
||||
- info
|
||||
|
@ -57,8 +64,9 @@ spec:
|
|||
eventSources:
|
||||
description: Filter events based on the involved objects.
|
||||
items:
|
||||
description: CrossNamespaceObjectReference contains enough information
|
||||
to let you locate the typed referenced object at cluster level
|
||||
description: |-
|
||||
CrossNamespaceObjectReference contains enough information to let you locate the
|
||||
typed referenced object at cluster level
|
||||
properties:
|
||||
apiVersion:
|
||||
description: API version of the referent
|
||||
|
@ -80,11 +88,10 @@ spec:
|
|||
matchLabels:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: MatchLabels is a map of {key,value} pairs. A single
|
||||
{key,value} in the matchLabels map is equivalent to an element
|
||||
of matchExpressions, whose key field is "key", the operator
|
||||
is "In", and the values array contains only "value". The requirements
|
||||
are ANDed.
|
||||
description: |-
|
||||
MatchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
|
||||
map is equivalent to an element of matchExpressions, whose key field is "key", the
|
||||
operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||
type: object
|
||||
name:
|
||||
description: Name of the referent
|
||||
|
@ -97,6 +104,7 @@ spec:
|
|||
minLength: 1
|
||||
type: string
|
||||
required:
|
||||
- kind
|
||||
- name
|
||||
type: object
|
||||
type: array
|
||||
|
@ -119,8 +127,9 @@ spec:
|
|||
description: Short description of the impact and affected cluster.
|
||||
type: string
|
||||
suspend:
|
||||
description: This flag tells the controller to suspend subsequent
|
||||
events dispatching. Defaults to false.
|
||||
description: |-
|
||||
This flag tells the controller to suspend subsequent events dispatching.
|
||||
Defaults to false.
|
||||
type: boolean
|
||||
required:
|
||||
- eventSources
|
||||
|
@ -133,43 +142,35 @@ spec:
|
|||
properties:
|
||||
conditions:
|
||||
items:
|
||||
description: "Condition contains details for one aspect of the current
|
||||
state of this API Resource. --- This struct is intended for direct
|
||||
use as an array at the field path .status.conditions. For example,
|
||||
\n type FooStatus struct{ // Represents the observations of a
|
||||
foo's current state. // Known .status.conditions.type are: \"Available\",
|
||||
\"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge
|
||||
// +listType=map // +listMapKey=type Conditions []metav1.Condition
|
||||
`json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\"
|
||||
protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }"
|
||||
description: Condition contains details for one aspect of the current
|
||||
state of this API Resource.
|
||||
properties:
|
||||
lastTransitionTime:
|
||||
description: lastTransitionTime is the last time the condition
|
||||
transitioned from one status to another. This should be when
|
||||
the underlying condition changed. If that is not known, then
|
||||
using the time when the API field changed is acceptable.
|
||||
description: |-
|
||||
lastTransitionTime is the last time the condition transitioned from one status to another.
|
||||
This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.
|
||||
format: date-time
|
||||
type: string
|
||||
message:
|
||||
description: message is a human readable message indicating
|
||||
details about the transition. This may be an empty string.
|
||||
description: |-
|
||||
message is a human readable message indicating details about the transition.
|
||||
This may be an empty string.
|
||||
maxLength: 32768
|
||||
type: string
|
||||
observedGeneration:
|
||||
description: observedGeneration represents the .metadata.generation
|
||||
that the condition was set based upon. For instance, if .metadata.generation
|
||||
is currently 12, but the .status.conditions[x].observedGeneration
|
||||
is 9, the condition is out of date with respect to the current
|
||||
state of the instance.
|
||||
description: |-
|
||||
observedGeneration represents the .metadata.generation that the condition was set based upon.
|
||||
For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
|
||||
with respect to the current state of the instance.
|
||||
format: int64
|
||||
minimum: 0
|
||||
type: integer
|
||||
reason:
|
||||
description: reason contains a programmatic identifier indicating
|
||||
the reason for the condition's last transition. Producers
|
||||
of specific condition types may define expected values and
|
||||
meanings for this field, and whether the values are considered
|
||||
a guaranteed API. The value should be a CamelCase string.
|
||||
description: |-
|
||||
reason contains a programmatic identifier indicating the reason for the condition's last transition.
|
||||
Producers of specific condition types may define expected values and meanings for this field,
|
||||
and whether the values are considered a guaranteed API.
|
||||
The value should be a CamelCase string.
|
||||
This field may not be empty.
|
||||
maxLength: 1024
|
||||
minLength: 1
|
||||
|
@ -184,10 +185,6 @@ spec:
|
|||
type: string
|
||||
type:
|
||||
description: type of condition in CamelCase or in foo.example.com/CamelCase.
|
||||
--- Many .condition.type values are consistent across resources
|
||||
like Available, but because arbitrary conditions can be useful
|
||||
(see .node.status.conditions), the ability to deconflict is
|
||||
important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
|
||||
maxLength: 316
|
||||
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
|
||||
type: string
|
||||
|
@ -219,20 +216,27 @@ spec:
|
|||
- jsonPath: .status.conditions[?(@.type=="Ready")].message
|
||||
name: Status
|
||||
type: string
|
||||
deprecated: true
|
||||
deprecationWarning: v1beta2 Alert is deprecated, upgrade to v1beta3
|
||||
name: v1beta2
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: Alert is the Schema for the alerts API
|
||||
properties:
|
||||
apiVersion:
|
||||
description: 'APIVersion defines the versioned schema of this representation
|
||||
of an object. Servers should convert recognized schemas to the latest
|
||||
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
||||
description: |-
|
||||
APIVersion defines the versioned schema of this representation of an object.
|
||||
Servers should convert recognized schemas to the latest internal value, and
|
||||
may reject unrecognized values.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
|
||||
type: string
|
||||
kind:
|
||||
description: 'Kind is a string value representing the REST resource this
|
||||
object represents. Servers may infer this from the endpoint the client
|
||||
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||
description: |-
|
||||
Kind is a string value representing the REST resource this object represents.
|
||||
Servers may infer this from the endpoint the client submits requests to.
|
||||
Cannot be updated.
|
||||
In CamelCase.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
|
@ -240,26 +244,39 @@ spec:
|
|||
description: AlertSpec defines an alerting rule for events involving a
|
||||
list of objects.
|
||||
properties:
|
||||
eventMetadata:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: |-
|
||||
EventMetadata is an optional field for adding metadata to events dispatched by the
|
||||
controller. This can be used for enhancing the context of the event. If a field
|
||||
would override one already present on the original event as generated by the emitter,
|
||||
then the override doesn't happen, i.e. the original value is preserved, and an info
|
||||
log is printed.
|
||||
type: object
|
||||
eventSeverity:
|
||||
default: info
|
||||
description: EventSeverity specifies how to filter events based on
|
||||
severity. If set to 'info' no events will be filtered.
|
||||
description: |-
|
||||
EventSeverity specifies how to filter events based on severity.
|
||||
If set to 'info' no events will be filtered.
|
||||
enum:
|
||||
- info
|
||||
- error
|
||||
type: string
|
||||
eventSources:
|
||||
description: EventSources specifies how to filter events based on
|
||||
the involved object kind, name and namespace.
|
||||
description: |-
|
||||
EventSources specifies how to filter events based
|
||||
on the involved object kind, name and namespace.
|
||||
items:
|
||||
description: CrossNamespaceObjectReference contains enough information
|
||||
to let you locate the typed referenced object at cluster level
|
||||
description: |-
|
||||
CrossNamespaceObjectReference contains enough information to let you locate the
|
||||
typed referenced object at cluster level
|
||||
properties:
|
||||
apiVersion:
|
||||
description: API version of the referent.
|
||||
description: API version of the referent
|
||||
type: string
|
||||
kind:
|
||||
description: Kind of the referent.
|
||||
description: Kind of the referent
|
||||
enum:
|
||||
- Bucket
|
||||
- GitRepository
|
||||
|
@ -275,32 +292,43 @@ spec:
|
|||
matchLabels:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: MatchLabels is a map of {key,value} pairs. A single
|
||||
{key,value} in the matchLabels map is equivalent to an element
|
||||
of matchExpressions, whose key field is "key", the operator
|
||||
is "In", and the values array contains only "value". The requirements
|
||||
are ANDed.
|
||||
description: |-
|
||||
MatchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
|
||||
map is equivalent to an element of matchExpressions, whose key field is "key", the
|
||||
operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||
MatchLabels requires the name to be set to `*`.
|
||||
type: object
|
||||
name:
|
||||
description: Name of the referent.
|
||||
maxLength: 53
|
||||
description: |-
|
||||
Name of the referent
|
||||
If multiple resources are targeted `*` may be set.
|
||||
maxLength: 253
|
||||
minLength: 1
|
||||
type: string
|
||||
namespace:
|
||||
description: Namespace of the referent.
|
||||
maxLength: 53
|
||||
description: Namespace of the referent
|
||||
maxLength: 253
|
||||
minLength: 1
|
||||
type: string
|
||||
required:
|
||||
- kind
|
||||
- name
|
||||
type: object
|
||||
type: array
|
||||
exclusionList:
|
||||
description: ExclusionList specifies a list of Golang regular expressions
|
||||
description: |-
|
||||
ExclusionList specifies a list of Golang regular expressions
|
||||
to be used for excluding messages.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
inclusionList:
|
||||
description: |-
|
||||
InclusionList specifies a list of Golang regular expressions
|
||||
to be used for including messages.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
providerRef:
|
||||
description: ProviderRef specifies which Provider this Alert should
|
||||
use.
|
||||
|
@ -317,8 +345,9 @@ spec:
|
|||
maxLength: 255
|
||||
type: string
|
||||
suspend:
|
||||
description: Suspend tells the controller to suspend subsequent events
|
||||
handling for this Alert.
|
||||
description: |-
|
||||
Suspend tells the controller to suspend subsequent
|
||||
events handling for this Alert.
|
||||
type: boolean
|
||||
required:
|
||||
- eventSources
|
||||
|
@ -332,43 +361,35 @@ spec:
|
|||
conditions:
|
||||
description: Conditions holds the conditions for the Alert.
|
||||
items:
|
||||
description: "Condition contains details for one aspect of the current
|
||||
state of this API Resource. --- This struct is intended for direct
|
||||
use as an array at the field path .status.conditions. For example,
|
||||
\n type FooStatus struct{ // Represents the observations of a
|
||||
foo's current state. // Known .status.conditions.type are: \"Available\",
|
||||
\"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge
|
||||
// +listType=map // +listMapKey=type Conditions []metav1.Condition
|
||||
`json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\"
|
||||
protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }"
|
||||
description: Condition contains details for one aspect of the current
|
||||
state of this API Resource.
|
||||
properties:
|
||||
lastTransitionTime:
|
||||
description: lastTransitionTime is the last time the condition
|
||||
transitioned from one status to another. This should be when
|
||||
the underlying condition changed. If that is not known, then
|
||||
using the time when the API field changed is acceptable.
|
||||
description: |-
|
||||
lastTransitionTime is the last time the condition transitioned from one status to another.
|
||||
This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.
|
||||
format: date-time
|
||||
type: string
|
||||
message:
|
||||
description: message is a human readable message indicating
|
||||
details about the transition. This may be an empty string.
|
||||
description: |-
|
||||
message is a human readable message indicating details about the transition.
|
||||
This may be an empty string.
|
||||
maxLength: 32768
|
||||
type: string
|
||||
observedGeneration:
|
||||
description: observedGeneration represents the .metadata.generation
|
||||
that the condition was set based upon. For instance, if .metadata.generation
|
||||
is currently 12, but the .status.conditions[x].observedGeneration
|
||||
is 9, the condition is out of date with respect to the current
|
||||
state of the instance.
|
||||
description: |-
|
||||
observedGeneration represents the .metadata.generation that the condition was set based upon.
|
||||
For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
|
||||
with respect to the current state of the instance.
|
||||
format: int64
|
||||
minimum: 0
|
||||
type: integer
|
||||
reason:
|
||||
description: reason contains a programmatic identifier indicating
|
||||
the reason for the condition's last transition. Producers
|
||||
of specific condition types may define expected values and
|
||||
meanings for this field, and whether the values are considered
|
||||
a guaranteed API. The value should be a CamelCase string.
|
||||
description: |-
|
||||
reason contains a programmatic identifier indicating the reason for the condition's last transition.
|
||||
Producers of specific condition types may define expected values and meanings for this field,
|
||||
and whether the values are considered a guaranteed API.
|
||||
The value should be a CamelCase string.
|
||||
This field may not be empty.
|
||||
maxLength: 1024
|
||||
minLength: 1
|
||||
|
@ -383,10 +404,6 @@ spec:
|
|||
type: string
|
||||
type:
|
||||
description: type of condition in CamelCase or in foo.example.com/CamelCase.
|
||||
--- Many .condition.type values are consistent across resources
|
||||
like Available, but because arbitrary conditions can be useful
|
||||
(see .node.status.conditions), the ability to deconflict is
|
||||
important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
|
||||
maxLength: 316
|
||||
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
|
||||
type: string
|
||||
|
@ -399,9 +416,10 @@ spec:
|
|||
type: object
|
||||
type: array
|
||||
lastHandledReconcileAt:
|
||||
description: LastHandledReconcileAt holds the value of the most recent
|
||||
reconcile request value, so a change of the annotation value can
|
||||
be detected.
|
||||
description: |-
|
||||
LastHandledReconcileAt holds the value of the most recent
|
||||
reconcile request value, so a change of the annotation value
|
||||
can be detected.
|
||||
type: string
|
||||
observedGeneration:
|
||||
description: ObservedGeneration is the last observed generation.
|
||||
|
@ -410,6 +428,150 @@ spec:
|
|||
type: object
|
||||
type: object
|
||||
served: true
|
||||
storage: true
|
||||
storage: false
|
||||
subresources:
|
||||
status: {}
|
||||
- additionalPrinterColumns:
|
||||
- jsonPath: .metadata.creationTimestamp
|
||||
name: Age
|
||||
type: date
|
||||
name: v1beta3
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: Alert is the Schema for the alerts API
|
||||
properties:
|
||||
apiVersion:
|
||||
description: |-
|
||||
APIVersion defines the versioned schema of this representation of an object.
|
||||
Servers should convert recognized schemas to the latest internal value, and
|
||||
may reject unrecognized values.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
|
||||
type: string
|
||||
kind:
|
||||
description: |-
|
||||
Kind is a string value representing the REST resource this object represents.
|
||||
Servers may infer this from the endpoint the client submits requests to.
|
||||
Cannot be updated.
|
||||
In CamelCase.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: AlertSpec defines an alerting rule for events involving a
|
||||
list of objects.
|
||||
properties:
|
||||
eventMetadata:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: |-
|
||||
EventMetadata is an optional field for adding metadata to events dispatched by the
|
||||
controller. This can be used for enhancing the context of the event. If a field
|
||||
would override one already present on the original event as generated by the emitter,
|
||||
then the override doesn't happen, i.e. the original value is preserved, and an info
|
||||
log is printed.
|
||||
type: object
|
||||
eventSeverity:
|
||||
default: info
|
||||
description: |-
|
||||
EventSeverity specifies how to filter events based on severity.
|
||||
If set to 'info' no events will be filtered.
|
||||
enum:
|
||||
- info
|
||||
- error
|
||||
type: string
|
||||
eventSources:
|
||||
description: |-
|
||||
EventSources specifies how to filter events based
|
||||
on the involved object kind, name and namespace.
|
||||
items:
|
||||
description: |-
|
||||
CrossNamespaceObjectReference contains enough information to let you locate the
|
||||
typed referenced object at cluster level
|
||||
properties:
|
||||
apiVersion:
|
||||
description: API version of the referent
|
||||
type: string
|
||||
kind:
|
||||
description: Kind of the referent
|
||||
enum:
|
||||
- Bucket
|
||||
- GitRepository
|
||||
- Kustomization
|
||||
- HelmRelease
|
||||
- HelmChart
|
||||
- HelmRepository
|
||||
- ImageRepository
|
||||
- ImagePolicy
|
||||
- ImageUpdateAutomation
|
||||
- OCIRepository
|
||||
type: string
|
||||
matchLabels:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: |-
|
||||
MatchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
|
||||
map is equivalent to an element of matchExpressions, whose key field is "key", the
|
||||
operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||
MatchLabels requires the name to be set to `*`.
|
||||
type: object
|
||||
name:
|
||||
description: |-
|
||||
Name of the referent
|
||||
If multiple resources are targeted `*` may be set.
|
||||
maxLength: 253
|
||||
minLength: 1
|
||||
type: string
|
||||
namespace:
|
||||
description: Namespace of the referent
|
||||
maxLength: 253
|
||||
minLength: 1
|
||||
type: string
|
||||
required:
|
||||
- kind
|
||||
- name
|
||||
type: object
|
||||
type: array
|
||||
exclusionList:
|
||||
description: |-
|
||||
ExclusionList specifies a list of Golang regular expressions
|
||||
to be used for excluding messages.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
inclusionList:
|
||||
description: |-
|
||||
InclusionList specifies a list of Golang regular expressions
|
||||
to be used for including messages.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
providerRef:
|
||||
description: ProviderRef specifies which Provider this Alert should
|
||||
use.
|
||||
properties:
|
||||
name:
|
||||
description: Name of the referent.
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
type: object
|
||||
summary:
|
||||
description: |-
|
||||
Summary holds a short description of the impact and affected cluster.
|
||||
Deprecated: Use EventMetadata instead.
|
||||
maxLength: 255
|
||||
type: string
|
||||
suspend:
|
||||
description: |-
|
||||
Suspend tells the controller to suspend subsequent
|
||||
events handling for this Alert.
|
||||
type: boolean
|
||||
required:
|
||||
- eventSources
|
||||
- providerRef
|
||||
type: object
|
||||
type: object
|
||||
served: true
|
||||
storage: true
|
||||
subresources: {}
|
||||
|
|
|
@ -3,8 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
|
|||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.11.1
|
||||
creationTimestamp: null
|
||||
controller-gen.kubebuilder.io/version: v0.16.1
|
||||
name: providers.notification.toolkit.fluxcd.io
|
||||
spec:
|
||||
group: notification.toolkit.fluxcd.io
|
||||
|
@ -25,20 +24,27 @@ spec:
|
|||
- jsonPath: .status.conditions[?(@.type=="Ready")].message
|
||||
name: Status
|
||||
type: string
|
||||
deprecated: true
|
||||
deprecationWarning: v1beta1 Provider is deprecated, upgrade to v1beta3
|
||||
name: v1beta1
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: Provider is the Schema for the providers API
|
||||
properties:
|
||||
apiVersion:
|
||||
description: 'APIVersion defines the versioned schema of this representation
|
||||
of an object. Servers should convert recognized schemas to the latest
|
||||
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
||||
description: |-
|
||||
APIVersion defines the versioned schema of this representation of an object.
|
||||
Servers should convert recognized schemas to the latest internal value, and
|
||||
may reject unrecognized values.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
|
||||
type: string
|
||||
kind:
|
||||
description: 'Kind is a string value representing the REST resource this
|
||||
object represents. Servers may infer this from the endpoint the client
|
||||
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||
description: |-
|
||||
Kind is a string value representing the REST resource this object represents.
|
||||
Servers may infer this from the endpoint the client submits requests to.
|
||||
Cannot be updated.
|
||||
In CamelCase.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
|
@ -50,7 +56,8 @@ spec:
|
|||
pattern: ^(http|https)://
|
||||
type: string
|
||||
certSecretRef:
|
||||
description: CertSecretRef can be given the name of a secret containing
|
||||
description: |-
|
||||
CertSecretRef can be given the name of a secret containing
|
||||
a PEM-encoded CA certificate (`caFile`)
|
||||
properties:
|
||||
name:
|
||||
|
@ -67,7 +74,8 @@ spec:
|
|||
pattern: ^(http|https)://
|
||||
type: string
|
||||
secretRef:
|
||||
description: Secret reference containing the provider webhook URL
|
||||
description: |-
|
||||
Secret reference containing the provider webhook URL
|
||||
using "address" as data key
|
||||
properties:
|
||||
name:
|
||||
|
@ -77,8 +85,9 @@ spec:
|
|||
- name
|
||||
type: object
|
||||
suspend:
|
||||
description: This flag tells the controller to suspend subsequent
|
||||
events handling. Defaults to false.
|
||||
description: |-
|
||||
This flag tells the controller to suspend subsequent events handling.
|
||||
Defaults to false.
|
||||
type: boolean
|
||||
timeout:
|
||||
description: Timeout for sending alerts to the provider.
|
||||
|
@ -122,43 +131,35 @@ spec:
|
|||
properties:
|
||||
conditions:
|
||||
items:
|
||||
description: "Condition contains details for one aspect of the current
|
||||
state of this API Resource. --- This struct is intended for direct
|
||||
use as an array at the field path .status.conditions. For example,
|
||||
\n type FooStatus struct{ // Represents the observations of a
|
||||
foo's current state. // Known .status.conditions.type are: \"Available\",
|
||||
\"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge
|
||||
// +listType=map // +listMapKey=type Conditions []metav1.Condition
|
||||
`json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\"
|
||||
protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }"
|
||||
description: Condition contains details for one aspect of the current
|
||||
state of this API Resource.
|
||||
properties:
|
||||
lastTransitionTime:
|
||||
description: lastTransitionTime is the last time the condition
|
||||
transitioned from one status to another. This should be when
|
||||
the underlying condition changed. If that is not known, then
|
||||
using the time when the API field changed is acceptable.
|
||||
description: |-
|
||||
lastTransitionTime is the last time the condition transitioned from one status to another.
|
||||
This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.
|
||||
format: date-time
|
||||
type: string
|
||||
message:
|
||||
description: message is a human readable message indicating
|
||||
details about the transition. This may be an empty string.
|
||||
description: |-
|
||||
message is a human readable message indicating details about the transition.
|
||||
This may be an empty string.
|
||||
maxLength: 32768
|
||||
type: string
|
||||
observedGeneration:
|
||||
description: observedGeneration represents the .metadata.generation
|
||||
that the condition was set based upon. For instance, if .metadata.generation
|
||||
is currently 12, but the .status.conditions[x].observedGeneration
|
||||
is 9, the condition is out of date with respect to the current
|
||||
state of the instance.
|
||||
description: |-
|
||||
observedGeneration represents the .metadata.generation that the condition was set based upon.
|
||||
For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
|
||||
with respect to the current state of the instance.
|
||||
format: int64
|
||||
minimum: 0
|
||||
type: integer
|
||||
reason:
|
||||
description: reason contains a programmatic identifier indicating
|
||||
the reason for the condition's last transition. Producers
|
||||
of specific condition types may define expected values and
|
||||
meanings for this field, and whether the values are considered
|
||||
a guaranteed API. The value should be a CamelCase string.
|
||||
description: |-
|
||||
reason contains a programmatic identifier indicating the reason for the condition's last transition.
|
||||
Producers of specific condition types may define expected values and meanings for this field,
|
||||
and whether the values are considered a guaranteed API.
|
||||
The value should be a CamelCase string.
|
||||
This field may not be empty.
|
||||
maxLength: 1024
|
||||
minLength: 1
|
||||
|
@ -173,10 +174,6 @@ spec:
|
|||
type: string
|
||||
type:
|
||||
description: type of condition in CamelCase or in foo.example.com/CamelCase.
|
||||
--- Many .condition.type values are consistent across resources
|
||||
like Available, but because arbitrary conditions can be useful
|
||||
(see .node.status.conditions), the ability to deconflict is
|
||||
important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
|
||||
maxLength: 316
|
||||
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
|
||||
type: string
|
||||
|
@ -208,20 +205,27 @@ spec:
|
|||
- jsonPath: .status.conditions[?(@.type=="Ready")].message
|
||||
name: Status
|
||||
type: string
|
||||
deprecated: true
|
||||
deprecationWarning: v1beta2 Provider is deprecated, upgrade to v1beta3
|
||||
name: v1beta2
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: Provider is the Schema for the providers API.
|
||||
properties:
|
||||
apiVersion:
|
||||
description: 'APIVersion defines the versioned schema of this representation
|
||||
of an object. Servers should convert recognized schemas to the latest
|
||||
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
||||
description: |-
|
||||
APIVersion defines the versioned schema of this representation of an object.
|
||||
Servers should convert recognized schemas to the latest internal value, and
|
||||
may reject unrecognized values.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
|
||||
type: string
|
||||
kind:
|
||||
description: 'Kind is a string value representing the REST resource this
|
||||
object represents. Servers may infer this from the endpoint the client
|
||||
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||
description: |-
|
||||
Kind is a string value representing the REST resource this object represents.
|
||||
Servers may infer this from the endpoint the client submits requests to.
|
||||
Cannot be updated.
|
||||
In CamelCase.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
|
@ -229,14 +233,20 @@ spec:
|
|||
description: ProviderSpec defines the desired state of the Provider.
|
||||
properties:
|
||||
address:
|
||||
description: Address specifies the HTTP/S incoming webhook address
|
||||
of this Provider.
|
||||
description: |-
|
||||
Address specifies the endpoint, in a generic sense, to where alerts are sent.
|
||||
What kind of endpoint depends on the specific Provider type being used.
|
||||
For the generic Provider, for example, this is an HTTP/S address.
|
||||
For other Provider types this could be a project ID or a namespace.
|
||||
maxLength: 2048
|
||||
pattern: ^(http|https)://.*$
|
||||
type: string
|
||||
certSecretRef:
|
||||
description: CertSecretRef specifies the Secret containing a PEM-encoded
|
||||
CA certificate (`caFile`).
|
||||
description: |-
|
||||
CertSecretRef specifies the Secret containing
|
||||
a PEM-encoded CA certificate (in the `ca.crt` key).
|
||||
|
||||
Note: Support for the `caFile` key has
|
||||
been deprecated.
|
||||
properties:
|
||||
name:
|
||||
description: Name of the referent.
|
||||
|
@ -260,7 +270,8 @@ spec:
|
|||
pattern: ^(http|https)://.*$
|
||||
type: string
|
||||
secretRef:
|
||||
description: SecretRef specifies the Secret containing the authentication
|
||||
description: |-
|
||||
SecretRef specifies the Secret containing the authentication
|
||||
credentials for this Provider.
|
||||
properties:
|
||||
name:
|
||||
|
@ -270,8 +281,9 @@ spec:
|
|||
- name
|
||||
type: object
|
||||
suspend:
|
||||
description: Suspend tells the controller to suspend subsequent events
|
||||
handling for this Provider.
|
||||
description: |-
|
||||
Suspend tells the controller to suspend subsequent
|
||||
events handling for this Provider.
|
||||
type: boolean
|
||||
timeout:
|
||||
description: Timeout for sending alerts to the Provider.
|
||||
|
@ -289,9 +301,11 @@ spec:
|
|||
- github
|
||||
- gitlab
|
||||
- gitea
|
||||
- bitbucketserver
|
||||
- bitbucket
|
||||
- azuredevops
|
||||
- googlechat
|
||||
- googlepubsub
|
||||
- webex
|
||||
- sentry
|
||||
- azureeventhub
|
||||
|
@ -302,6 +316,8 @@ spec:
|
|||
- alertmanager
|
||||
- grafana
|
||||
- githubdispatch
|
||||
- pagerduty
|
||||
- datadog
|
||||
type: string
|
||||
username:
|
||||
description: Username specifies the name under which events are posted.
|
||||
|
@ -318,43 +334,35 @@ spec:
|
|||
conditions:
|
||||
description: Conditions holds the conditions for the Provider.
|
||||
items:
|
||||
description: "Condition contains details for one aspect of the current
|
||||
state of this API Resource. --- This struct is intended for direct
|
||||
use as an array at the field path .status.conditions. For example,
|
||||
\n type FooStatus struct{ // Represents the observations of a
|
||||
foo's current state. // Known .status.conditions.type are: \"Available\",
|
||||
\"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge
|
||||
// +listType=map // +listMapKey=type Conditions []metav1.Condition
|
||||
`json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\"
|
||||
protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }"
|
||||
description: Condition contains details for one aspect of the current
|
||||
state of this API Resource.
|
||||
properties:
|
||||
lastTransitionTime:
|
||||
description: lastTransitionTime is the last time the condition
|
||||
transitioned from one status to another. This should be when
|
||||
the underlying condition changed. If that is not known, then
|
||||
using the time when the API field changed is acceptable.
|
||||
description: |-
|
||||
lastTransitionTime is the last time the condition transitioned from one status to another.
|
||||
This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.
|
||||
format: date-time
|
||||
type: string
|
||||
message:
|
||||
description: message is a human readable message indicating
|
||||
details about the transition. This may be an empty string.
|
||||
description: |-
|
||||
message is a human readable message indicating details about the transition.
|
||||
This may be an empty string.
|
||||
maxLength: 32768
|
||||
type: string
|
||||
observedGeneration:
|
||||
description: observedGeneration represents the .metadata.generation
|
||||
that the condition was set based upon. For instance, if .metadata.generation
|
||||
is currently 12, but the .status.conditions[x].observedGeneration
|
||||
is 9, the condition is out of date with respect to the current
|
||||
state of the instance.
|
||||
description: |-
|
||||
observedGeneration represents the .metadata.generation that the condition was set based upon.
|
||||
For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
|
||||
with respect to the current state of the instance.
|
||||
format: int64
|
||||
minimum: 0
|
||||
type: integer
|
||||
reason:
|
||||
description: reason contains a programmatic identifier indicating
|
||||
the reason for the condition's last transition. Producers
|
||||
of specific condition types may define expected values and
|
||||
meanings for this field, and whether the values are considered
|
||||
a guaranteed API. The value should be a CamelCase string.
|
||||
description: |-
|
||||
reason contains a programmatic identifier indicating the reason for the condition's last transition.
|
||||
Producers of specific condition types may define expected values and meanings for this field,
|
||||
and whether the values are considered a guaranteed API.
|
||||
The value should be a CamelCase string.
|
||||
This field may not be empty.
|
||||
maxLength: 1024
|
||||
minLength: 1
|
||||
|
@ -369,10 +377,6 @@ spec:
|
|||
type: string
|
||||
type:
|
||||
description: type of condition in CamelCase or in foo.example.com/CamelCase.
|
||||
--- Many .condition.type values are consistent across resources
|
||||
like Available, but because arbitrary conditions can be useful
|
||||
(see .node.status.conditions), the ability to deconflict is
|
||||
important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
|
||||
maxLength: 316
|
||||
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
|
||||
type: string
|
||||
|
@ -385,9 +389,10 @@ spec:
|
|||
type: object
|
||||
type: array
|
||||
lastHandledReconcileAt:
|
||||
description: LastHandledReconcileAt holds the value of the most recent
|
||||
reconcile request value, so a change of the annotation value can
|
||||
be detected.
|
||||
description: |-
|
||||
LastHandledReconcileAt holds the value of the most recent
|
||||
reconcile request value, so a change of the annotation value
|
||||
can be detected.
|
||||
type: string
|
||||
observedGeneration:
|
||||
description: ObservedGeneration is the last reconciled generation.
|
||||
|
@ -396,6 +401,175 @@ spec:
|
|||
type: object
|
||||
type: object
|
||||
served: true
|
||||
storage: true
|
||||
storage: false
|
||||
subresources:
|
||||
status: {}
|
||||
- additionalPrinterColumns:
|
||||
- jsonPath: .metadata.creationTimestamp
|
||||
name: Age
|
||||
type: date
|
||||
name: v1beta3
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: Provider is the Schema for the providers API
|
||||
properties:
|
||||
apiVersion:
|
||||
description: |-
|
||||
APIVersion defines the versioned schema of this representation of an object.
|
||||
Servers should convert recognized schemas to the latest internal value, and
|
||||
may reject unrecognized values.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
|
||||
type: string
|
||||
kind:
|
||||
description: |-
|
||||
Kind is a string value representing the REST resource this object represents.
|
||||
Servers may infer this from the endpoint the client submits requests to.
|
||||
Cannot be updated.
|
||||
In CamelCase.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: ProviderSpec defines the desired state of the Provider.
|
||||
properties:
|
||||
address:
|
||||
description: |-
|
||||
Address specifies the endpoint, in a generic sense, to where alerts are sent.
|
||||
What kind of endpoint depends on the specific Provider type being used.
|
||||
For the generic Provider, for example, this is an HTTP/S address.
|
||||
For other Provider types this could be a project ID or a namespace.
|
||||
maxLength: 2048
|
||||
type: string
|
||||
certSecretRef:
|
||||
description: |-
|
||||
CertSecretRef specifies the Secret containing TLS certificates
|
||||
for secure communication.
|
||||
|
||||
Supported configurations:
|
||||
- CA-only: Server authentication (provide ca.crt only)
|
||||
- mTLS: Mutual authentication (provide ca.crt + tls.crt + tls.key)
|
||||
- Client-only: Client authentication with system CA (provide tls.crt + tls.key only)
|
||||
|
||||
Legacy keys "caFile", "certFile", "keyFile" are supported but deprecated. Use "ca.crt", "tls.crt", "tls.key" instead.
|
||||
properties:
|
||||
name:
|
||||
description: Name of the referent.
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
type: object
|
||||
channel:
|
||||
description: Channel specifies the destination channel where events
|
||||
should be posted.
|
||||
maxLength: 2048
|
||||
type: string
|
||||
commitStatusExpr:
|
||||
description: |-
|
||||
CommitStatusExpr is a CEL expression that evaluates to a string value
|
||||
that can be used to generate a custom commit status message for use
|
||||
with eligible Provider types (github, gitlab, gitea, bitbucketserver,
|
||||
bitbucket, azuredevops). Supported variables are: event, provider,
|
||||
and alert.
|
||||
type: string
|
||||
interval:
|
||||
description: |-
|
||||
Interval at which to reconcile the Provider with its Secret references.
|
||||
Deprecated and not used in v1beta3.
|
||||
pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$
|
||||
type: string
|
||||
proxy:
|
||||
description: |-
|
||||
Proxy the HTTP/S address of the proxy server.
|
||||
Deprecated: Use ProxySecretRef instead. Will be removed in v1.
|
||||
maxLength: 2048
|
||||
pattern: ^(http|https)://.*$
|
||||
type: string
|
||||
proxySecretRef:
|
||||
description: |-
|
||||
ProxySecretRef specifies the Secret containing the proxy configuration
|
||||
for this Provider. The Secret should contain an 'address' key with the
|
||||
HTTP/S address of the proxy server. Optional 'username' and 'password'
|
||||
keys can be provided for proxy authentication.
|
||||
properties:
|
||||
name:
|
||||
description: Name of the referent.
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
type: object
|
||||
secretRef:
|
||||
description: |-
|
||||
SecretRef specifies the Secret containing the authentication
|
||||
credentials for this Provider.
|
||||
properties:
|
||||
name:
|
||||
description: Name of the referent.
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
type: object
|
||||
serviceAccountName:
|
||||
description: |-
|
||||
ServiceAccountName is the name of the service account used to
|
||||
authenticate with services from cloud providers. An error is thrown if a
|
||||
static credential is also defined inside the Secret referenced by the
|
||||
SecretRef.
|
||||
type: string
|
||||
suspend:
|
||||
description: |-
|
||||
Suspend tells the controller to suspend subsequent
|
||||
events handling for this Provider.
|
||||
type: boolean
|
||||
timeout:
|
||||
description: Timeout for sending alerts to the Provider.
|
||||
pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m))+$
|
||||
type: string
|
||||
type:
|
||||
description: Type specifies which Provider implementation to use.
|
||||
enum:
|
||||
- slack
|
||||
- discord
|
||||
- msteams
|
||||
- rocket
|
||||
- generic
|
||||
- generic-hmac
|
||||
- github
|
||||
- gitlab
|
||||
- gitea
|
||||
- bitbucketserver
|
||||
- bitbucket
|
||||
- azuredevops
|
||||
- googlechat
|
||||
- googlepubsub
|
||||
- webex
|
||||
- sentry
|
||||
- azureeventhub
|
||||
- telegram
|
||||
- lark
|
||||
- matrix
|
||||
- opsgenie
|
||||
- alertmanager
|
||||
- grafana
|
||||
- githubdispatch
|
||||
- pagerduty
|
||||
- datadog
|
||||
- nats
|
||||
type: string
|
||||
username:
|
||||
description: Username specifies the name under which events are posted.
|
||||
maxLength: 2048
|
||||
type: string
|
||||
required:
|
||||
- type
|
||||
type: object
|
||||
x-kubernetes-validations:
|
||||
- message: spec.commitStatusExpr is only supported for the 'github', 'gitlab',
|
||||
'gitea', 'bitbucketserver', 'bitbucket', 'azuredevops' provider types
|
||||
rule: self.type == 'github' || self.type == 'gitlab' || self.type ==
|
||||
'gitea' || self.type == 'bitbucketserver' || self.type == 'bitbucket'
|
||||
|| self.type == 'azuredevops' || !has(self.commitStatusExpr)
|
||||
type: object
|
||||
served: true
|
||||
storage: true
|
||||
subresources: {}
|
||||
|
|
|
@ -3,8 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
|
|||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.11.1
|
||||
creationTimestamp: null
|
||||
controller-gen.kubebuilder.io/version: v0.16.1
|
||||
name: receivers.notification.toolkit.fluxcd.io
|
||||
spec:
|
||||
group: notification.toolkit.fluxcd.io
|
||||
|
@ -25,37 +24,60 @@ spec:
|
|||
- jsonPath: .status.conditions[?(@.type=="Ready")].message
|
||||
name: Status
|
||||
type: string
|
||||
name: v1beta1
|
||||
name: v1
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: Receiver is the Schema for the receivers API
|
||||
description: Receiver is the Schema for the receivers API.
|
||||
properties:
|
||||
apiVersion:
|
||||
description: 'APIVersion defines the versioned schema of this representation
|
||||
of an object. Servers should convert recognized schemas to the latest
|
||||
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
||||
description: |-
|
||||
APIVersion defines the versioned schema of this representation of an object.
|
||||
Servers should convert recognized schemas to the latest internal value, and
|
||||
may reject unrecognized values.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
|
||||
type: string
|
||||
kind:
|
||||
description: 'Kind is a string value representing the REST resource this
|
||||
object represents. Servers may infer this from the endpoint the client
|
||||
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||
description: |-
|
||||
Kind is a string value representing the REST resource this object represents.
|
||||
Servers may infer this from the endpoint the client submits requests to.
|
||||
Cannot be updated.
|
||||
In CamelCase.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: ReceiverSpec defines the desired state of Receiver
|
||||
description: ReceiverSpec defines the desired state of the Receiver.
|
||||
properties:
|
||||
events:
|
||||
description: A list of events to handle, e.g. 'push' for GitHub or
|
||||
'Push Hook' for GitLab.
|
||||
description: |-
|
||||
Events specifies the list of event types to handle,
|
||||
e.g. 'push' for GitHub or 'Push Hook' for GitLab.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
interval:
|
||||
default: 10m
|
||||
description: Interval at which to reconcile the Receiver with its
|
||||
Secret references.
|
||||
pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$
|
||||
type: string
|
||||
resourceFilter:
|
||||
description: |-
|
||||
ResourceFilter is a CEL expression expected to return a boolean that is
|
||||
evaluated for each resource referenced in the Resources field when a
|
||||
webhook is received. If the expression returns false then the controller
|
||||
will not request a reconciliation for the resource.
|
||||
When the expression is specified the controller will parse it and mark
|
||||
the object as terminally failed if the expression is invalid or does not
|
||||
return a boolean.
|
||||
type: string
|
||||
resources:
|
||||
description: A list of resources to be notified about changes.
|
||||
items:
|
||||
description: CrossNamespaceObjectReference contains enough information
|
||||
to let you locate the typed referenced object at cluster level
|
||||
description: |-
|
||||
CrossNamespaceObjectReference contains enough information to let you locate the
|
||||
typed referenced object at cluster level
|
||||
properties:
|
||||
apiVersion:
|
||||
description: API version of the referent
|
||||
|
@ -77,11 +99,227 @@ spec:
|
|||
matchLabels:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: MatchLabels is a map of {key,value} pairs. A single
|
||||
{key,value} in the matchLabels map is equivalent to an element
|
||||
of matchExpressions, whose key field is "key", the operator
|
||||
is "In", and the values array contains only "value". The requirements
|
||||
are ANDed.
|
||||
description: |-
|
||||
MatchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
|
||||
map is equivalent to an element of matchExpressions, whose key field is "key", the
|
||||
operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||
MatchLabels requires the name to be set to `*`.
|
||||
type: object
|
||||
name:
|
||||
description: |-
|
||||
Name of the referent
|
||||
If multiple resources are targeted `*` may be set.
|
||||
maxLength: 253
|
||||
minLength: 1
|
||||
type: string
|
||||
namespace:
|
||||
description: Namespace of the referent
|
||||
maxLength: 253
|
||||
minLength: 1
|
||||
type: string
|
||||
required:
|
||||
- kind
|
||||
- name
|
||||
type: object
|
||||
type: array
|
||||
secretRef:
|
||||
description: |-
|
||||
SecretRef specifies the Secret containing the token used
|
||||
to validate the payload authenticity.
|
||||
properties:
|
||||
name:
|
||||
description: Name of the referent.
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
type: object
|
||||
suspend:
|
||||
description: |-
|
||||
Suspend tells the controller to suspend subsequent
|
||||
events handling for this receiver.
|
||||
type: boolean
|
||||
type:
|
||||
description: |-
|
||||
Type of webhook sender, used to determine
|
||||
the validation procedure and payload deserialization.
|
||||
enum:
|
||||
- generic
|
||||
- generic-hmac
|
||||
- github
|
||||
- gitlab
|
||||
- bitbucket
|
||||
- harbor
|
||||
- dockerhub
|
||||
- quay
|
||||
- gcr
|
||||
- nexus
|
||||
- acr
|
||||
- cdevents
|
||||
type: string
|
||||
required:
|
||||
- resources
|
||||
- secretRef
|
||||
- type
|
||||
type: object
|
||||
status:
|
||||
default:
|
||||
observedGeneration: -1
|
||||
description: ReceiverStatus defines the observed state of the Receiver.
|
||||
properties:
|
||||
conditions:
|
||||
description: Conditions holds the conditions for the Receiver.
|
||||
items:
|
||||
description: Condition contains details for one aspect of the current
|
||||
state of this API Resource.
|
||||
properties:
|
||||
lastTransitionTime:
|
||||
description: |-
|
||||
lastTransitionTime is the last time the condition transitioned from one status to another.
|
||||
This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.
|
||||
format: date-time
|
||||
type: string
|
||||
message:
|
||||
description: |-
|
||||
message is a human readable message indicating details about the transition.
|
||||
This may be an empty string.
|
||||
maxLength: 32768
|
||||
type: string
|
||||
observedGeneration:
|
||||
description: |-
|
||||
observedGeneration represents the .metadata.generation that the condition was set based upon.
|
||||
For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
|
||||
with respect to the current state of the instance.
|
||||
format: int64
|
||||
minimum: 0
|
||||
type: integer
|
||||
reason:
|
||||
description: |-
|
||||
reason contains a programmatic identifier indicating the reason for the condition's last transition.
|
||||
Producers of specific condition types may define expected values and meanings for this field,
|
||||
and whether the values are considered a guaranteed API.
|
||||
The value should be a CamelCase string.
|
||||
This field may not be empty.
|
||||
maxLength: 1024
|
||||
minLength: 1
|
||||
pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
|
||||
type: string
|
||||
status:
|
||||
description: status of the condition, one of True, False, Unknown.
|
||||
enum:
|
||||
- "True"
|
||||
- "False"
|
||||
- Unknown
|
||||
type: string
|
||||
type:
|
||||
description: type of condition in CamelCase or in foo.example.com/CamelCase.
|
||||
maxLength: 316
|
||||
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
|
||||
type: string
|
||||
required:
|
||||
- lastTransitionTime
|
||||
- message
|
||||
- reason
|
||||
- status
|
||||
- type
|
||||
type: object
|
||||
type: array
|
||||
lastHandledReconcileAt:
|
||||
description: |-
|
||||
LastHandledReconcileAt holds the value of the most recent
|
||||
reconcile request value, so a change of the annotation value
|
||||
can be detected.
|
||||
type: string
|
||||
observedGeneration:
|
||||
description: ObservedGeneration is the last observed generation of
|
||||
the Receiver object.
|
||||
format: int64
|
||||
type: integer
|
||||
webhookPath:
|
||||
description: |-
|
||||
WebhookPath is the generated incoming webhook address in the format
|
||||
of '/hook/sha256sum(token+name+namespace)'.
|
||||
type: string
|
||||
type: object
|
||||
type: object
|
||||
served: true
|
||||
storage: true
|
||||
subresources:
|
||||
status: {}
|
||||
- additionalPrinterColumns:
|
||||
- jsonPath: .metadata.creationTimestamp
|
||||
name: Age
|
||||
type: date
|
||||
- jsonPath: .status.conditions[?(@.type=="Ready")].status
|
||||
name: Ready
|
||||
type: string
|
||||
- jsonPath: .status.conditions[?(@.type=="Ready")].message
|
||||
name: Status
|
||||
type: string
|
||||
deprecated: true
|
||||
deprecationWarning: v1beta1 Receiver is deprecated, upgrade to v1
|
||||
name: v1beta1
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: Receiver is the Schema for the receivers API
|
||||
properties:
|
||||
apiVersion:
|
||||
description: |-
|
||||
APIVersion defines the versioned schema of this representation of an object.
|
||||
Servers should convert recognized schemas to the latest internal value, and
|
||||
may reject unrecognized values.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
|
||||
type: string
|
||||
kind:
|
||||
description: |-
|
||||
Kind is a string value representing the REST resource this object represents.
|
||||
Servers may infer this from the endpoint the client submits requests to.
|
||||
Cannot be updated.
|
||||
In CamelCase.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: ReceiverSpec defines the desired state of Receiver
|
||||
properties:
|
||||
events:
|
||||
description: |-
|
||||
A list of events to handle,
|
||||
e.g. 'push' for GitHub or 'Push Hook' for GitLab.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
resources:
|
||||
description: A list of resources to be notified about changes.
|
||||
items:
|
||||
description: |-
|
||||
CrossNamespaceObjectReference contains enough information to let you locate the
|
||||
typed referenced object at cluster level
|
||||
properties:
|
||||
apiVersion:
|
||||
description: API version of the referent
|
||||
type: string
|
||||
kind:
|
||||
description: Kind of the referent
|
||||
enum:
|
||||
- Bucket
|
||||
- GitRepository
|
||||
- Kustomization
|
||||
- HelmRelease
|
||||
- HelmChart
|
||||
- HelmRepository
|
||||
- ImageRepository
|
||||
- ImagePolicy
|
||||
- ImageUpdateAutomation
|
||||
- OCIRepository
|
||||
type: string
|
||||
matchLabels:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: |-
|
||||
MatchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
|
||||
map is equivalent to an element of matchExpressions, whose key field is "key", the
|
||||
operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||
type: object
|
||||
name:
|
||||
description: Name of the referent
|
||||
|
@ -94,12 +332,14 @@ spec:
|
|||
minLength: 1
|
||||
type: string
|
||||
required:
|
||||
- kind
|
||||
- name
|
||||
type: object
|
||||
type: array
|
||||
secretRef:
|
||||
description: Secret reference containing the token used to validate
|
||||
the payload authenticity
|
||||
description: |-
|
||||
Secret reference containing the token used
|
||||
to validate the payload authenticity
|
||||
properties:
|
||||
name:
|
||||
description: Name of the referent.
|
||||
|
@ -108,12 +348,14 @@ spec:
|
|||
- name
|
||||
type: object
|
||||
suspend:
|
||||
description: This flag tells the controller to suspend subsequent
|
||||
events handling. Defaults to false.
|
||||
description: |-
|
||||
This flag tells the controller to suspend subsequent events handling.
|
||||
Defaults to false.
|
||||
type: boolean
|
||||
type:
|
||||
description: Type of webhook sender, used to determine the validation
|
||||
procedure and payload deserialization.
|
||||
description: |-
|
||||
Type of webhook sender, used to determine
|
||||
the validation procedure and payload deserialization.
|
||||
enum:
|
||||
- generic
|
||||
- generic-hmac
|
||||
|
@ -129,6 +371,7 @@ spec:
|
|||
type: string
|
||||
required:
|
||||
- resources
|
||||
- secretRef
|
||||
- type
|
||||
type: object
|
||||
status:
|
||||
|
@ -138,43 +381,35 @@ spec:
|
|||
properties:
|
||||
conditions:
|
||||
items:
|
||||
description: "Condition contains details for one aspect of the current
|
||||
state of this API Resource. --- This struct is intended for direct
|
||||
use as an array at the field path .status.conditions. For example,
|
||||
\n type FooStatus struct{ // Represents the observations of a
|
||||
foo's current state. // Known .status.conditions.type are: \"Available\",
|
||||
\"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge
|
||||
// +listType=map // +listMapKey=type Conditions []metav1.Condition
|
||||
`json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\"
|
||||
protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }"
|
||||
description: Condition contains details for one aspect of the current
|
||||
state of this API Resource.
|
||||
properties:
|
||||
lastTransitionTime:
|
||||
description: lastTransitionTime is the last time the condition
|
||||
transitioned from one status to another. This should be when
|
||||
the underlying condition changed. If that is not known, then
|
||||
using the time when the API field changed is acceptable.
|
||||
description: |-
|
||||
lastTransitionTime is the last time the condition transitioned from one status to another.
|
||||
This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.
|
||||
format: date-time
|
||||
type: string
|
||||
message:
|
||||
description: message is a human readable message indicating
|
||||
details about the transition. This may be an empty string.
|
||||
description: |-
|
||||
message is a human readable message indicating details about the transition.
|
||||
This may be an empty string.
|
||||
maxLength: 32768
|
||||
type: string
|
||||
observedGeneration:
|
||||
description: observedGeneration represents the .metadata.generation
|
||||
that the condition was set based upon. For instance, if .metadata.generation
|
||||
is currently 12, but the .status.conditions[x].observedGeneration
|
||||
is 9, the condition is out of date with respect to the current
|
||||
state of the instance.
|
||||
description: |-
|
||||
observedGeneration represents the .metadata.generation that the condition was set based upon.
|
||||
For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
|
||||
with respect to the current state of the instance.
|
||||
format: int64
|
||||
minimum: 0
|
||||
type: integer
|
||||
reason:
|
||||
description: reason contains a programmatic identifier indicating
|
||||
the reason for the condition's last transition. Producers
|
||||
of specific condition types may define expected values and
|
||||
meanings for this field, and whether the values are considered
|
||||
a guaranteed API. The value should be a CamelCase string.
|
||||
description: |-
|
||||
reason contains a programmatic identifier indicating the reason for the condition's last transition.
|
||||
Producers of specific condition types may define expected values and meanings for this field,
|
||||
and whether the values are considered a guaranteed API.
|
||||
The value should be a CamelCase string.
|
||||
This field may not be empty.
|
||||
maxLength: 1024
|
||||
minLength: 1
|
||||
|
@ -189,10 +424,6 @@ spec:
|
|||
type: string
|
||||
type:
|
||||
description: type of condition in CamelCase or in foo.example.com/CamelCase.
|
||||
--- Many .condition.type values are consistent across resources
|
||||
like Available, but because arbitrary conditions can be useful
|
||||
(see .node.status.conditions), the ability to deconflict is
|
||||
important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
|
||||
maxLength: 316
|
||||
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
|
||||
type: string
|
||||
|
@ -209,7 +440,9 @@ spec:
|
|||
format: int64
|
||||
type: integer
|
||||
url:
|
||||
description: Generated webhook URL in the format of '/hook/sha256sum(token+name+namespace)'.
|
||||
description: |-
|
||||
Generated webhook URL in the format
|
||||
of '/hook/sha256sum(token+name+namespace)'.
|
||||
type: string
|
||||
type: object
|
||||
type: object
|
||||
|
@ -227,20 +460,27 @@ spec:
|
|||
- jsonPath: .status.conditions[?(@.type=="Ready")].message
|
||||
name: Status
|
||||
type: string
|
||||
deprecated: true
|
||||
deprecationWarning: v1beta2 Receiver is deprecated, upgrade to v1
|
||||
name: v1beta2
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: Receiver is the Schema for the receivers API.
|
||||
properties:
|
||||
apiVersion:
|
||||
description: 'APIVersion defines the versioned schema of this representation
|
||||
of an object. Servers should convert recognized schemas to the latest
|
||||
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
||||
description: |-
|
||||
APIVersion defines the versioned schema of this representation of an object.
|
||||
Servers should convert recognized schemas to the latest internal value, and
|
||||
may reject unrecognized values.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
|
||||
type: string
|
||||
kind:
|
||||
description: 'Kind is a string value representing the REST resource this
|
||||
object represents. Servers may infer this from the endpoint the client
|
||||
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||
description: |-
|
||||
Kind is a string value representing the REST resource this object represents.
|
||||
Servers may infer this from the endpoint the client submits requests to.
|
||||
Cannot be updated.
|
||||
In CamelCase.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
|
@ -248,8 +488,9 @@ spec:
|
|||
description: ReceiverSpec defines the desired state of the Receiver.
|
||||
properties:
|
||||
events:
|
||||
description: Events specifies the list of event types to handle, e.g.
|
||||
'push' for GitHub or 'Push Hook' for GitLab.
|
||||
description: |-
|
||||
Events specifies the list of event types to handle,
|
||||
e.g. 'push' for GitHub or 'Push Hook' for GitLab.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
|
@ -261,14 +502,15 @@ spec:
|
|||
resources:
|
||||
description: A list of resources to be notified about changes.
|
||||
items:
|
||||
description: CrossNamespaceObjectReference contains enough information
|
||||
to let you locate the typed referenced object at cluster level
|
||||
description: |-
|
||||
CrossNamespaceObjectReference contains enough information to let you locate the
|
||||
typed referenced object at cluster level
|
||||
properties:
|
||||
apiVersion:
|
||||
description: API version of the referent.
|
||||
description: API version of the referent
|
||||
type: string
|
||||
kind:
|
||||
description: Kind of the referent.
|
||||
description: Kind of the referent
|
||||
enum:
|
||||
- Bucket
|
||||
- GitRepository
|
||||
|
@ -284,28 +526,32 @@ spec:
|
|||
matchLabels:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: MatchLabels is a map of {key,value} pairs. A single
|
||||
{key,value} in the matchLabels map is equivalent to an element
|
||||
of matchExpressions, whose key field is "key", the operator
|
||||
is "In", and the values array contains only "value". The requirements
|
||||
are ANDed.
|
||||
description: |-
|
||||
MatchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
|
||||
map is equivalent to an element of matchExpressions, whose key field is "key", the
|
||||
operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||
MatchLabels requires the name to be set to `*`.
|
||||
type: object
|
||||
name:
|
||||
description: Name of the referent.
|
||||
maxLength: 53
|
||||
description: |-
|
||||
Name of the referent
|
||||
If multiple resources are targeted `*` may be set.
|
||||
maxLength: 253
|
||||
minLength: 1
|
||||
type: string
|
||||
namespace:
|
||||
description: Namespace of the referent.
|
||||
maxLength: 53
|
||||
description: Namespace of the referent
|
||||
maxLength: 253
|
||||
minLength: 1
|
||||
type: string
|
||||
required:
|
||||
- kind
|
||||
- name
|
||||
type: object
|
||||
type: array
|
||||
secretRef:
|
||||
description: SecretRef specifies the Secret containing the token used
|
||||
description: |-
|
||||
SecretRef specifies the Secret containing the token used
|
||||
to validate the payload authenticity.
|
||||
properties:
|
||||
name:
|
||||
|
@ -315,12 +561,14 @@ spec:
|
|||
- name
|
||||
type: object
|
||||
suspend:
|
||||
description: Suspend tells the controller to suspend subsequent events
|
||||
handling for this receiver.
|
||||
description: |-
|
||||
Suspend tells the controller to suspend subsequent
|
||||
events handling for this receiver.
|
||||
type: boolean
|
||||
type:
|
||||
description: Type of webhook sender, used to determine the validation
|
||||
procedure and payload deserialization.
|
||||
description: |-
|
||||
Type of webhook sender, used to determine
|
||||
the validation procedure and payload deserialization.
|
||||
enum:
|
||||
- generic
|
||||
- generic-hmac
|
||||
|
@ -336,6 +584,7 @@ spec:
|
|||
type: string
|
||||
required:
|
||||
- resources
|
||||
- secretRef
|
||||
- type
|
||||
type: object
|
||||
status:
|
||||
|
@ -346,43 +595,35 @@ spec:
|
|||
conditions:
|
||||
description: Conditions holds the conditions for the Receiver.
|
||||
items:
|
||||
description: "Condition contains details for one aspect of the current
|
||||
state of this API Resource. --- This struct is intended for direct
|
||||
use as an array at the field path .status.conditions. For example,
|
||||
\n type FooStatus struct{ // Represents the observations of a
|
||||
foo's current state. // Known .status.conditions.type are: \"Available\",
|
||||
\"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge
|
||||
// +listType=map // +listMapKey=type Conditions []metav1.Condition
|
||||
`json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\"
|
||||
protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }"
|
||||
description: Condition contains details for one aspect of the current
|
||||
state of this API Resource.
|
||||
properties:
|
||||
lastTransitionTime:
|
||||
description: lastTransitionTime is the last time the condition
|
||||
transitioned from one status to another. This should be when
|
||||
the underlying condition changed. If that is not known, then
|
||||
using the time when the API field changed is acceptable.
|
||||
description: |-
|
||||
lastTransitionTime is the last time the condition transitioned from one status to another.
|
||||
This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.
|
||||
format: date-time
|
||||
type: string
|
||||
message:
|
||||
description: message is a human readable message indicating
|
||||
details about the transition. This may be an empty string.
|
||||
description: |-
|
||||
message is a human readable message indicating details about the transition.
|
||||
This may be an empty string.
|
||||
maxLength: 32768
|
||||
type: string
|
||||
observedGeneration:
|
||||
description: observedGeneration represents the .metadata.generation
|
||||
that the condition was set based upon. For instance, if .metadata.generation
|
||||
is currently 12, but the .status.conditions[x].observedGeneration
|
||||
is 9, the condition is out of date with respect to the current
|
||||
state of the instance.
|
||||
description: |-
|
||||
observedGeneration represents the .metadata.generation that the condition was set based upon.
|
||||
For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
|
||||
with respect to the current state of the instance.
|
||||
format: int64
|
||||
minimum: 0
|
||||
type: integer
|
||||
reason:
|
||||
description: reason contains a programmatic identifier indicating
|
||||
the reason for the condition's last transition. Producers
|
||||
of specific condition types may define expected values and
|
||||
meanings for this field, and whether the values are considered
|
||||
a guaranteed API. The value should be a CamelCase string.
|
||||
description: |-
|
||||
reason contains a programmatic identifier indicating the reason for the condition's last transition.
|
||||
Producers of specific condition types may define expected values and meanings for this field,
|
||||
and whether the values are considered a guaranteed API.
|
||||
The value should be a CamelCase string.
|
||||
This field may not be empty.
|
||||
maxLength: 1024
|
||||
minLength: 1
|
||||
|
@ -397,10 +638,6 @@ spec:
|
|||
type: string
|
||||
type:
|
||||
description: type of condition in CamelCase or in foo.example.com/CamelCase.
|
||||
--- Many .condition.type values are consistent across resources
|
||||
like Available, but because arbitrary conditions can be useful
|
||||
(see .node.status.conditions), the ability to deconflict is
|
||||
important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
|
||||
maxLength: 316
|
||||
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
|
||||
type: string
|
||||
|
@ -413,9 +650,10 @@ spec:
|
|||
type: object
|
||||
type: array
|
||||
lastHandledReconcileAt:
|
||||
description: LastHandledReconcileAt holds the value of the most recent
|
||||
reconcile request value, so a change of the annotation value can
|
||||
be detected.
|
||||
description: |-
|
||||
LastHandledReconcileAt holds the value of the most recent
|
||||
reconcile request value, so a change of the annotation value
|
||||
can be detected.
|
||||
type: string
|
||||
observedGeneration:
|
||||
description: ObservedGeneration is the last observed generation of
|
||||
|
@ -423,17 +661,19 @@ spec:
|
|||
format: int64
|
||||
type: integer
|
||||
url:
|
||||
description: 'URL is the generated incoming webhook address in the
|
||||
format of ''/hook/sha256sum(token+name+namespace)''. Deprecated:
|
||||
Replaced by WebhookPath.'
|
||||
description: |-
|
||||
URL is the generated incoming webhook address in the format
|
||||
of '/hook/sha256sum(token+name+namespace)'.
|
||||
Deprecated: Replaced by WebhookPath.
|
||||
type: string
|
||||
webhookPath:
|
||||
description: WebhookPath is the generated incoming webhook address
|
||||
in the format of '/hook/sha256sum(token+name+namespace)'.
|
||||
description: |-
|
||||
WebhookPath is the generated incoming webhook address in the format
|
||||
of '/hook/sha256sum(token+name+namespace)'.
|
||||
type: string
|
||||
type: object
|
||||
type: object
|
||||
served: true
|
||||
storage: true
|
||||
storage: false
|
||||
subresources:
|
||||
status: {}
|
||||
|
|
|
@ -6,4 +6,4 @@ resources:
|
|||
images:
|
||||
- name: fluxcd/notification-controller
|
||||
newName: fluxcd/notification-controller
|
||||
newTag: v0.32.1
|
||||
newTag: v1.6.0
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
name: manager-role
|
||||
rules:
|
||||
- apiGroups:
|
||||
|
@ -20,6 +19,12 @@ rules:
|
|||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- serviceaccounts/token
|
||||
verbs:
|
||||
- create
|
||||
- apiGroups:
|
||||
- image.fluxcd.io
|
||||
resources:
|
||||
|
@ -40,45 +45,7 @@ rules:
|
|||
- notification.toolkit.fluxcd.io
|
||||
resources:
|
||||
- alerts
|
||||
verbs:
|
||||
- create
|
||||
- delete
|
||||
- get
|
||||
- list
|
||||
- patch
|
||||
- update
|
||||
- watch
|
||||
- apiGroups:
|
||||
- notification.toolkit.fluxcd.io
|
||||
resources:
|
||||
- alerts/status
|
||||
verbs:
|
||||
- get
|
||||
- patch
|
||||
- update
|
||||
- apiGroups:
|
||||
- notification.toolkit.fluxcd.io
|
||||
resources:
|
||||
- providers
|
||||
verbs:
|
||||
- create
|
||||
- delete
|
||||
- get
|
||||
- list
|
||||
- patch
|
||||
- update
|
||||
- watch
|
||||
- apiGroups:
|
||||
- notification.toolkit.fluxcd.io
|
||||
resources:
|
||||
- providers/status
|
||||
verbs:
|
||||
- get
|
||||
- patch
|
||||
- update
|
||||
- apiGroups:
|
||||
- notification.toolkit.fluxcd.io
|
||||
resources:
|
||||
- receivers
|
||||
verbs:
|
||||
- create
|
||||
|
@ -100,53 +67,8 @@ rules:
|
|||
- source.fluxcd.io
|
||||
resources:
|
||||
- buckets
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- patch
|
||||
- update
|
||||
- watch
|
||||
- apiGroups:
|
||||
- source.fluxcd.io
|
||||
resources:
|
||||
- buckets/status
|
||||
verbs:
|
||||
- get
|
||||
- apiGroups:
|
||||
- source.fluxcd.io
|
||||
resources:
|
||||
- gitrepositories
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- patch
|
||||
- update
|
||||
- watch
|
||||
- apiGroups:
|
||||
- source.fluxcd.io
|
||||
resources:
|
||||
- gitrepositories/status
|
||||
verbs:
|
||||
- get
|
||||
- apiGroups:
|
||||
- source.fluxcd.io
|
||||
resources:
|
||||
- helmrepositories
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- patch
|
||||
- update
|
||||
- watch
|
||||
- apiGroups:
|
||||
- source.fluxcd.io
|
||||
resources:
|
||||
- helmrepositories/status
|
||||
verbs:
|
||||
- get
|
||||
- apiGroups:
|
||||
- source.fluxcd.io
|
||||
resources:
|
||||
- ocirepositories
|
||||
verbs:
|
||||
- get
|
||||
|
@ -157,6 +79,9 @@ rules:
|
|||
- apiGroups:
|
||||
- source.fluxcd.io
|
||||
resources:
|
||||
- buckets/status
|
||||
- gitrepositories/status
|
||||
- helmrepositories/status
|
||||
- ocirepositories/status
|
||||
verbs:
|
||||
- get
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
apiVersion: notification.toolkit.fluxcd.io/v1beta2
|
||||
apiVersion: notification.toolkit.fluxcd.io/v1
|
||||
kind: Receiver
|
||||
metadata:
|
||||
name: receiver-sample
|
|
@ -0,0 +1,13 @@
|
|||
apiVersion: notification.toolkit.fluxcd.io/v1beta3
|
||||
kind: Alert
|
||||
metadata:
|
||||
name: alert-sample
|
||||
spec:
|
||||
providerRef:
|
||||
name: slack-provider-sample
|
||||
eventSeverity: info
|
||||
eventSources:
|
||||
- kind: GitRepository
|
||||
name: '*'
|
||||
- kind: Kustomization
|
||||
name: '*'
|
|
@ -0,0 +1,34 @@
|
|||
apiVersion: notification.toolkit.fluxcd.io/v1beta3
|
||||
kind: Provider
|
||||
metadata:
|
||||
name: slack-provider-sample
|
||||
spec:
|
||||
type: slack
|
||||
channel: general
|
||||
secretRef:
|
||||
name: slack-url
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: slack-url
|
||||
data:
|
||||
address: aHR0cHM6Ly9ob29rcy5zbGFjay5jb20vc2VydmljZXMv
|
||||
---
|
||||
apiVersion: notification.toolkit.fluxcd.io/v1beta3
|
||||
kind: Provider
|
||||
metadata:
|
||||
name: generic-provider-sample
|
||||
spec:
|
||||
type: generic
|
||||
address: https://api.github.com/repos/fluxcd/notification-controller/dispatches
|
||||
secretRef:
|
||||
name: generic-secret
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: generic-secret
|
||||
stringData:
|
||||
headers: |
|
||||
Authorization: token
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
apiVersion: notification.toolkit.fluxcd.io/v1beta1
|
||||
kind: Provider
|
||||
metadata:
|
||||
name: status-defaults
|
||||
spec:
|
||||
type: generic
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
apiVersion: notification.toolkit.fluxcd.io/v1beta1
|
||||
kind: Alert
|
||||
metadata:
|
||||
name: status-defaults
|
|
@ -1,4 +0,0 @@
|
|||
apiVersion: notification.toolkit.fluxcd.io/v1beta1
|
||||
kind: Provider
|
||||
metadata:
|
||||
name: status-defaults
|
|
@ -1,4 +1,4 @@
|
|||
apiVersion: notification.toolkit.fluxcd.io/v1beta1
|
||||
apiVersion: notification.toolkit.fluxcd.io/v1
|
||||
kind: Receiver
|
||||
metadata:
|
||||
name: status-defaults
|
||||
|
|
|
@ -1,262 +0,0 @@
|
|||
/*
|
||||
Copyright 2022 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
kerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/builder"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||
"sigs.k8s.io/controller-runtime/pkg/handler"
|
||||
"sigs.k8s.io/controller-runtime/pkg/predicate"
|
||||
"sigs.k8s.io/controller-runtime/pkg/ratelimiter"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
"sigs.k8s.io/controller-runtime/pkg/source"
|
||||
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
"github.com/fluxcd/pkg/runtime/conditions"
|
||||
helper "github.com/fluxcd/pkg/runtime/controller"
|
||||
"github.com/fluxcd/pkg/runtime/patch"
|
||||
"github.com/fluxcd/pkg/runtime/predicates"
|
||||
kuberecorder "k8s.io/client-go/tools/record"
|
||||
|
||||
apiv1 "github.com/fluxcd/notification-controller/api/v1beta2"
|
||||
)
|
||||
|
||||
var (
|
||||
ProviderIndexKey = ".metadata.provider"
|
||||
)
|
||||
|
||||
// AlertReconciler reconciles a Alert object
|
||||
type AlertReconciler struct {
|
||||
client.Client
|
||||
helper.Metrics
|
||||
kuberecorder.EventRecorder
|
||||
|
||||
ControllerName string
|
||||
}
|
||||
|
||||
type AlertReconcilerOptions struct {
|
||||
MaxConcurrentReconciles int
|
||||
RateLimiter ratelimiter.RateLimiter
|
||||
}
|
||||
|
||||
func (r *AlertReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
||||
return r.SetupWithManagerAndOptions(mgr, AlertReconcilerOptions{})
|
||||
}
|
||||
|
||||
func (r *AlertReconciler) SetupWithManagerAndOptions(mgr ctrl.Manager, opts AlertReconcilerOptions) error {
|
||||
if err := mgr.GetFieldIndexer().IndexField(context.TODO(), &apiv1.Alert{}, ProviderIndexKey,
|
||||
func(o client.Object) []string {
|
||||
alert := o.(*apiv1.Alert)
|
||||
return []string{
|
||||
fmt.Sprintf("%s/%s", alert.GetNamespace(), alert.Spec.ProviderRef.Name),
|
||||
}
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
recoverPanic := true
|
||||
return ctrl.NewControllerManagedBy(mgr).
|
||||
For(&apiv1.Alert{}, builder.WithPredicates(
|
||||
predicate.Or(predicate.GenerationChangedPredicate{}, predicates.ReconcileRequestedPredicate{}),
|
||||
)).
|
||||
Watches(
|
||||
&source.Kind{Type: &apiv1.Provider{}},
|
||||
handler.EnqueueRequestsFromMapFunc(r.requestsForProviderChange),
|
||||
builder.WithPredicates(predicate.GenerationChangedPredicate{}),
|
||||
).
|
||||
WithOptions(controller.Options{
|
||||
MaxConcurrentReconciles: opts.MaxConcurrentReconciles,
|
||||
RateLimiter: opts.RateLimiter,
|
||||
RecoverPanic: &recoverPanic,
|
||||
}).
|
||||
Complete(r)
|
||||
}
|
||||
|
||||
// +kubebuilder:rbac:groups=notification.toolkit.fluxcd.io,resources=alerts,verbs=get;list;watch;create;update;patch;delete
|
||||
// +kubebuilder:rbac:groups=notification.toolkit.fluxcd.io,resources=alerts/status,verbs=get;update;patch
|
||||
// +kubebuilder:rbac:groups="",resources=events,verbs=create;patch
|
||||
|
||||
func (r *AlertReconciler) Reconcile(ctx context.Context, req ctrl.Request) (result ctrl.Result, retErr error) {
|
||||
reconcileStart := time.Now()
|
||||
log := ctrl.LoggerFrom(ctx)
|
||||
|
||||
obj := &apiv1.Alert{}
|
||||
if err := r.Get(ctx, req.NamespacedName, obj); err != nil {
|
||||
return ctrl.Result{}, client.IgnoreNotFound(err)
|
||||
}
|
||||
|
||||
// Initialize the runtime patcher with the current version of the object.
|
||||
patcher := patch.NewSerialPatcher(obj, r.Client)
|
||||
|
||||
defer func() {
|
||||
// Patch finalizers, status and conditions.
|
||||
if err := r.patch(ctx, obj, patcher); err != nil {
|
||||
retErr = kerrors.NewAggregate([]error{retErr, err})
|
||||
}
|
||||
|
||||
// Record Prometheus metrics.
|
||||
r.Metrics.RecordReadiness(ctx, obj)
|
||||
r.Metrics.RecordDuration(ctx, obj, reconcileStart)
|
||||
r.Metrics.RecordSuspend(ctx, obj, obj.Spec.Suspend)
|
||||
|
||||
// Emit warning event if the reconciliation failed.
|
||||
if retErr != nil {
|
||||
r.Event(obj, corev1.EventTypeWarning, meta.FailedReason, retErr.Error())
|
||||
}
|
||||
|
||||
// Log and emit success event.
|
||||
if retErr == nil && conditions.IsReady(obj) {
|
||||
msg := "Reconciliation finished"
|
||||
log.Info(msg)
|
||||
r.Event(obj, corev1.EventTypeNormal, meta.SucceededReason, msg)
|
||||
}
|
||||
}()
|
||||
|
||||
if !controllerutil.ContainsFinalizer(obj, apiv1.NotificationFinalizer) {
|
||||
controllerutil.AddFinalizer(obj, apiv1.NotificationFinalizer)
|
||||
result = ctrl.Result{Requeue: true}
|
||||
return
|
||||
}
|
||||
|
||||
if !obj.ObjectMeta.DeletionTimestamp.IsZero() {
|
||||
controllerutil.RemoveFinalizer(obj, apiv1.NotificationFinalizer)
|
||||
result = ctrl.Result{}
|
||||
return
|
||||
}
|
||||
|
||||
// Return early if the object is suspended.
|
||||
if obj.Spec.Suspend {
|
||||
log.Info("Reconciliation is suspended for this object")
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
return r.reconcile(ctx, obj)
|
||||
}
|
||||
|
||||
func (r *AlertReconciler) reconcile(ctx context.Context, alert *apiv1.Alert) (ctrl.Result, error) {
|
||||
// Mark the resource as under reconciliation.
|
||||
conditions.MarkReconciling(alert, meta.ProgressingReason, "Reconciliation in progress")
|
||||
|
||||
// Check if the provider exist and is ready.
|
||||
if err := r.isProviderReady(ctx, alert); err != nil {
|
||||
conditions.MarkFalse(alert, meta.ReadyCondition, meta.FailedReason, err.Error())
|
||||
return ctrl.Result{Requeue: true}, client.IgnoreNotFound(err)
|
||||
}
|
||||
|
||||
conditions.MarkTrue(alert, meta.ReadyCondition, meta.SucceededReason, apiv1.InitializedReason)
|
||||
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
func (r *AlertReconciler) isProviderReady(ctx context.Context, alert *apiv1.Alert) error {
|
||||
provider := &apiv1.Provider{}
|
||||
providerName := types.NamespacedName{Namespace: alert.Namespace, Name: alert.Spec.ProviderRef.Name}
|
||||
if err := r.Get(ctx, providerName, provider); err != nil {
|
||||
// log not found errors since they get filtered out
|
||||
ctrl.LoggerFrom(ctx).Error(err, "failed to get provider %s", providerName.String())
|
||||
return fmt.Errorf("failed to get provider '%s': %w", providerName.String(), err)
|
||||
}
|
||||
|
||||
if !conditions.IsReady(provider) {
|
||||
return fmt.Errorf("provider %s is not ready", providerName.String())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *AlertReconciler) requestsForProviderChange(o client.Object) []reconcile.Request {
|
||||
provider, ok := o.(*apiv1.Provider)
|
||||
if !ok {
|
||||
panic(fmt.Errorf("expected a provider, got %T", o))
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
var list apiv1.AlertList
|
||||
if err := r.List(ctx, &list, client.MatchingFields{
|
||||
ProviderIndexKey: client.ObjectKeyFromObject(provider).String(),
|
||||
}); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var reqs []reconcile.Request
|
||||
for _, i := range list.Items {
|
||||
reqs = append(reqs, reconcile.Request{NamespacedName: client.ObjectKeyFromObject(&i)})
|
||||
}
|
||||
|
||||
return reqs
|
||||
}
|
||||
|
||||
// patch updates the object status, conditions and finalizers.
|
||||
func (r *AlertReconciler) patch(ctx context.Context, obj *apiv1.Alert, patcher *patch.SerialPatcher) (retErr error) {
|
||||
// Configure the runtime patcher.
|
||||
patchOpts := []patch.Option{}
|
||||
ownedConditions := []string{
|
||||
meta.ReadyCondition,
|
||||
meta.ReconcilingCondition,
|
||||
meta.StalledCondition,
|
||||
}
|
||||
patchOpts = append(patchOpts,
|
||||
patch.WithOwnedConditions{Conditions: ownedConditions},
|
||||
patch.WithForceOverwriteConditions{},
|
||||
patch.WithFieldOwner(r.ControllerName),
|
||||
)
|
||||
|
||||
// Set the value of the reconciliation request in status.
|
||||
if v, ok := meta.ReconcileAnnotationValue(obj.GetAnnotations()); ok {
|
||||
obj.Status.LastHandledReconcileAt = v
|
||||
}
|
||||
|
||||
// Remove the Reconciling condition and update the observed generation
|
||||
// if the reconciliation was successful.
|
||||
if conditions.IsTrue(obj, meta.ReadyCondition) {
|
||||
conditions.Delete(obj, meta.ReconcilingCondition)
|
||||
obj.Status.ObservedGeneration = obj.Generation
|
||||
}
|
||||
|
||||
// Set the Reconciling reason to ProgressingWithRetry if the
|
||||
// reconciliation has failed.
|
||||
if conditions.IsFalse(obj, meta.ReadyCondition) &&
|
||||
conditions.Has(obj, meta.ReconcilingCondition) {
|
||||
rc := conditions.Get(obj, meta.ReconcilingCondition)
|
||||
rc.Reason = meta.ProgressingWithRetryReason
|
||||
conditions.Set(obj, rc)
|
||||
}
|
||||
|
||||
// Patch the object status, conditions and finalizers.
|
||||
if err := patcher.Patch(ctx, obj, patchOpts...); err != nil {
|
||||
if !obj.GetDeletionTimestamp().IsZero() {
|
||||
err = kerrors.FilterOut(err, func(e error) bool { return apierrors.IsNotFound(e) })
|
||||
}
|
||||
retErr = kerrors.NewAggregate([]error{retErr, err})
|
||||
if retErr != nil {
|
||||
return retErr
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -1,426 +0,0 @@
|
|||
/*
|
||||
Copyright 2022 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/fluxcd/pkg/ssa"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/sethvargo/go-limiter/memorystore"
|
||||
prommetrics "github.com/slok/go-http-metrics/metrics/prometheus"
|
||||
"github.com/slok/go-http-metrics/middleware"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
apierrors "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/controller/controllerutil"
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
||||
|
||||
eventv1 "github.com/fluxcd/pkg/apis/event/v1beta1"
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
"github.com/fluxcd/pkg/runtime/conditions"
|
||||
|
||||
apiv1 "github.com/fluxcd/notification-controller/api/v1beta2"
|
||||
"github.com/fluxcd/notification-controller/internal/server"
|
||||
)
|
||||
|
||||
func TestAlertReconciler_Reconcile(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
timeout := 5 * time.Second
|
||||
resultA := &apiv1.Alert{}
|
||||
namespaceName := "alert-" + randStringRunes(5)
|
||||
providerName := "provider-" + randStringRunes(5)
|
||||
|
||||
g.Expect(createNamespace(namespaceName)).NotTo(HaveOccurred(), "failed to create test namespace")
|
||||
|
||||
provider := &apiv1.Provider{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: providerName,
|
||||
Namespace: namespaceName,
|
||||
},
|
||||
Spec: apiv1.ProviderSpec{
|
||||
Type: "generic",
|
||||
Address: "https://webhook.internal",
|
||||
},
|
||||
}
|
||||
|
||||
alert := &apiv1.Alert{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: fmt.Sprintf("alert-%s", randStringRunes(5)),
|
||||
Namespace: namespaceName,
|
||||
},
|
||||
Spec: apiv1.AlertSpec{
|
||||
ProviderRef: meta.LocalObjectReference{
|
||||
Name: providerName,
|
||||
},
|
||||
EventSeverity: "info",
|
||||
EventSources: []apiv1.CrossNamespaceObjectReference{
|
||||
{
|
||||
Kind: "Bucket",
|
||||
Name: "*",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
g.Expect(k8sClient.Create(context.Background(), alert)).To(Succeed())
|
||||
|
||||
t.Run("fails with provider not found error", func(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
|
||||
g.Eventually(func() bool {
|
||||
_ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(alert), resultA)
|
||||
return conditions.Has(resultA, meta.ReadyCondition)
|
||||
}, timeout, time.Second).Should(BeTrue())
|
||||
|
||||
g.Expect(conditions.IsReady(resultA)).To(BeFalse())
|
||||
g.Expect(conditions.GetReason(resultA, meta.ReadyCondition)).To(BeIdenticalTo(meta.FailedReason))
|
||||
g.Expect(conditions.GetMessage(resultA, meta.ReadyCondition)).To(ContainSubstring(providerName))
|
||||
|
||||
g.Expect(conditions.Has(resultA, meta.ReconcilingCondition)).To(BeTrue())
|
||||
g.Expect(conditions.GetReason(resultA, meta.ReconcilingCondition)).To(BeIdenticalTo(meta.ProgressingWithRetryReason))
|
||||
g.Expect(conditions.GetObservedGeneration(resultA, meta.ReconcilingCondition)).To(BeIdenticalTo(resultA.Generation))
|
||||
g.Expect(controllerutil.ContainsFinalizer(resultA, apiv1.NotificationFinalizer)).To(BeTrue())
|
||||
})
|
||||
|
||||
t.Run("recovers when provider exists", func(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
|
||||
g.Expect(k8sClient.Create(context.Background(), provider)).To(Succeed())
|
||||
|
||||
g.Eventually(func() bool {
|
||||
_ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(alert), resultA)
|
||||
return conditions.IsReady(resultA)
|
||||
}, timeout, time.Second).Should(BeTrue())
|
||||
|
||||
g.Expect(conditions.GetObservedGeneration(resultA, meta.ReadyCondition)).To(BeIdenticalTo(resultA.Generation))
|
||||
g.Expect(resultA.Status.ObservedGeneration).To(BeIdenticalTo(resultA.Generation))
|
||||
g.Expect(conditions.Has(resultA, meta.ReconcilingCondition)).To(BeFalse())
|
||||
})
|
||||
|
||||
t.Run("handles reconcileAt", func(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
|
||||
g.Expect(k8sClient.Get(context.Background(), client.ObjectKeyFromObject(alert), resultA)).To(Succeed())
|
||||
|
||||
reconcileRequestAt := metav1.Now().String()
|
||||
resultA.SetAnnotations(map[string]string{
|
||||
meta.ReconcileRequestAnnotation: reconcileRequestAt,
|
||||
})
|
||||
g.Expect(k8sClient.Update(context.Background(), resultA)).To(Succeed())
|
||||
|
||||
g.Eventually(func() bool {
|
||||
_ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(alert), resultA)
|
||||
return resultA.Status.LastHandledReconcileAt == reconcileRequestAt
|
||||
}, timeout, time.Second).Should(BeTrue())
|
||||
})
|
||||
|
||||
t.Run("finalizes suspended object", func(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
|
||||
g.Expect(k8sClient.Get(context.Background(), client.ObjectKeyFromObject(alert), resultA)).To(Succeed())
|
||||
|
||||
resultA.Spec.Suspend = true
|
||||
g.Expect(k8sClient.Update(context.Background(), resultA)).To(Succeed())
|
||||
|
||||
g.Eventually(func() bool {
|
||||
_ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(alert), resultA)
|
||||
return resultA.Spec.Suspend == true
|
||||
}, timeout, time.Second).Should(BeTrue())
|
||||
|
||||
g.Expect(k8sClient.Delete(context.Background(), resultA)).To(Succeed())
|
||||
|
||||
g.Eventually(func() bool {
|
||||
err := k8sClient.Get(context.Background(), client.ObjectKeyFromObject(alert), resultA)
|
||||
return apierrors.IsNotFound(err)
|
||||
}, timeout, time.Second).Should(BeTrue())
|
||||
})
|
||||
}
|
||||
|
||||
func TestAlertReconciler_EventHandler(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
var (
|
||||
namespace = "events-" + randStringRunes(5)
|
||||
req *http.Request
|
||||
provider *apiv1.Provider
|
||||
)
|
||||
g.Expect(createNamespace(namespace)).NotTo(HaveOccurred(), "failed to create test namespace")
|
||||
|
||||
eventMdlw := middleware.New(middleware.Config{
|
||||
Recorder: prommetrics.NewRecorder(prommetrics.Config{
|
||||
Prefix: "gotk_event",
|
||||
}),
|
||||
})
|
||||
|
||||
store, err := memorystore.New(&memorystore.Config{
|
||||
Interval: 5 * time.Minute,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create memory storage")
|
||||
}
|
||||
|
||||
eventServer := server.NewEventServer("127.0.0.1:56789", logf.Log, k8sClient, true)
|
||||
stopCh := make(chan struct{})
|
||||
go eventServer.ListenAndServe(stopCh, eventMdlw, store)
|
||||
|
||||
rcvServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
req = r
|
||||
w.WriteHeader(200)
|
||||
}))
|
||||
defer rcvServer.Close()
|
||||
defer close(stopCh)
|
||||
|
||||
providerKey := types.NamespacedName{
|
||||
Name: fmt.Sprintf("provider-%s", randStringRunes(5)),
|
||||
Namespace: namespace,
|
||||
}
|
||||
provider = &apiv1.Provider{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: providerKey.Name,
|
||||
Namespace: providerKey.Namespace,
|
||||
},
|
||||
Spec: apiv1.ProviderSpec{
|
||||
Type: "generic",
|
||||
Address: rcvServer.URL,
|
||||
},
|
||||
}
|
||||
g.Expect(k8sClient.Create(context.Background(), provider)).To(Succeed())
|
||||
g.Eventually(func() bool {
|
||||
var obj apiv1.Provider
|
||||
g.Expect(k8sClient.Get(context.Background(), client.ObjectKeyFromObject(provider), &obj))
|
||||
return conditions.IsReady(&obj)
|
||||
}, 30*time.Second, time.Second).Should(BeTrue())
|
||||
|
||||
repo, err := readManifest("./testdata/repo.yaml", namespace)
|
||||
g.Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
secondRepo, err := readManifest("./testdata/gitrepo2.yaml", namespace)
|
||||
g.Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
_, err = manager.Apply(context.Background(), repo, ssa.ApplyOptions{
|
||||
Force: true,
|
||||
})
|
||||
g.Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
_, err = manager.Apply(context.Background(), secondRepo, ssa.ApplyOptions{
|
||||
Force: true,
|
||||
})
|
||||
g.Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
alertKey := types.NamespacedName{
|
||||
Name: fmt.Sprintf("alert-%s", randStringRunes(5)),
|
||||
Namespace: namespace,
|
||||
}
|
||||
|
||||
alert := &apiv1.Alert{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: alertKey.Name,
|
||||
Namespace: alertKey.Namespace,
|
||||
},
|
||||
Spec: apiv1.AlertSpec{
|
||||
ProviderRef: meta.LocalObjectReference{
|
||||
Name: providerKey.Name,
|
||||
},
|
||||
EventSeverity: "info",
|
||||
EventSources: []apiv1.CrossNamespaceObjectReference{
|
||||
{
|
||||
Kind: "Bucket",
|
||||
Name: "hyacinth",
|
||||
Namespace: namespace,
|
||||
},
|
||||
{
|
||||
Kind: "Kustomization",
|
||||
Name: "*",
|
||||
},
|
||||
{
|
||||
Kind: "GitRepository",
|
||||
Name: "*",
|
||||
MatchLabels: map[string]string{
|
||||
"app": "podinfo",
|
||||
},
|
||||
},
|
||||
{
|
||||
Kind: "Kustomization",
|
||||
Name: "*",
|
||||
Namespace: "test",
|
||||
},
|
||||
},
|
||||
ExclusionList: []string{
|
||||
"doesnotoccur", // not intended to match
|
||||
"excluded",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
g.Expect(k8sClient.Create(context.Background(), alert)).To(Succeed())
|
||||
|
||||
// wait for controller to mark the alert as ready
|
||||
g.Eventually(func() bool {
|
||||
var obj apiv1.Alert
|
||||
g.Expect(k8sClient.Get(context.Background(), client.ObjectKeyFromObject(alert), &obj))
|
||||
return conditions.IsReady(&obj)
|
||||
}, 30*time.Second, time.Second).Should(BeTrue())
|
||||
|
||||
event := eventv1.Event{
|
||||
InvolvedObject: corev1.ObjectReference{
|
||||
Kind: "Bucket",
|
||||
Name: "hyacinth",
|
||||
Namespace: namespace,
|
||||
},
|
||||
Severity: "info",
|
||||
Timestamp: metav1.Now(),
|
||||
Message: "well that happened",
|
||||
Reason: "event-happened",
|
||||
ReportingController: "source-controller",
|
||||
}
|
||||
|
||||
testSent := func() {
|
||||
buf := &bytes.Buffer{}
|
||||
g.Expect(json.NewEncoder(buf).Encode(&event)).To(Succeed())
|
||||
res, err := http.Post("http://localhost:56789/", "application/json", buf)
|
||||
g.Expect(err).ToNot(HaveOccurred())
|
||||
g.Expect(res.StatusCode).To(Equal(202)) // event_server responds with 202 Accepted
|
||||
}
|
||||
|
||||
testForwarded := func() {
|
||||
g.Eventually(func() bool {
|
||||
return req == nil
|
||||
}, "2s", "0.1s").Should(BeFalse())
|
||||
}
|
||||
|
||||
testFiltered := func() {
|
||||
// The event_server does forwarding in a goroutine, after
|
||||
// responding to the POST of the event. This makes it
|
||||
// difficult to know whether the provider has filtered the
|
||||
// event, or just not run the goroutine yet. For now, I'll use
|
||||
// a timeout (and Consistently so it can fail early)
|
||||
g.Consistently(func() bool {
|
||||
return req == nil
|
||||
}, "1s", "0.1s").Should(BeTrue())
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
modifyEventFunc func(e eventv1.Event) eventv1.Event
|
||||
forwarded bool
|
||||
}{
|
||||
{
|
||||
name: "forwards when source is a match",
|
||||
modifyEventFunc: func(e eventv1.Event) eventv1.Event { return e },
|
||||
forwarded: true,
|
||||
},
|
||||
{
|
||||
name: "drops event when source Kind does not match",
|
||||
modifyEventFunc: func(e eventv1.Event) eventv1.Event {
|
||||
e.InvolvedObject.Kind = "GitRepository"
|
||||
return e
|
||||
},
|
||||
forwarded: false,
|
||||
},
|
||||
{
|
||||
name: "drops event when source name does not match",
|
||||
modifyEventFunc: func(e eventv1.Event) eventv1.Event {
|
||||
e.InvolvedObject.Name = "slop"
|
||||
return e
|
||||
},
|
||||
forwarded: false,
|
||||
},
|
||||
{
|
||||
name: "drops event when source namespace does not match",
|
||||
modifyEventFunc: func(e eventv1.Event) eventv1.Event {
|
||||
e.InvolvedObject.Namespace = "all-buckets"
|
||||
return e
|
||||
},
|
||||
forwarded: false,
|
||||
},
|
||||
{
|
||||
name: "drops event that is matched by exclusion",
|
||||
modifyEventFunc: func(e eventv1.Event) eventv1.Event {
|
||||
e.Message = "this is excluded"
|
||||
return e
|
||||
},
|
||||
forwarded: false,
|
||||
},
|
||||
{
|
||||
name: "forwards events when name wildcard is used",
|
||||
modifyEventFunc: func(e eventv1.Event) eventv1.Event {
|
||||
e.InvolvedObject.Kind = "Kustomization"
|
||||
e.InvolvedObject.Name = "test"
|
||||
e.InvolvedObject.Namespace = namespace
|
||||
e.Message = "test"
|
||||
return e
|
||||
},
|
||||
forwarded: true,
|
||||
},
|
||||
{
|
||||
name: "forwards events when the label matches",
|
||||
modifyEventFunc: func(e eventv1.Event) eventv1.Event {
|
||||
e.InvolvedObject.Kind = "GitRepository"
|
||||
e.InvolvedObject.Name = "podinfo"
|
||||
e.InvolvedObject.APIVersion = "source.toolkit.fluxcd.io/v1beta1"
|
||||
e.InvolvedObject.Namespace = namespace
|
||||
e.Message = "test"
|
||||
return e
|
||||
},
|
||||
forwarded: true,
|
||||
},
|
||||
{
|
||||
name: "drops events when the labels don't match",
|
||||
modifyEventFunc: func(e eventv1.Event) eventv1.Event {
|
||||
e.InvolvedObject.Kind = "GitRepository"
|
||||
e.InvolvedObject.Name = "podinfo-two"
|
||||
e.InvolvedObject.APIVersion = "source.toolkit.fluxcd.io/v1beta1"
|
||||
e.InvolvedObject.Namespace = namespace
|
||||
e.Message = "test"
|
||||
return e
|
||||
},
|
||||
forwarded: false,
|
||||
},
|
||||
{
|
||||
name: "drops events for cross-namespace sources",
|
||||
modifyEventFunc: func(e eventv1.Event) eventv1.Event {
|
||||
e.InvolvedObject.Kind = "Kustomization"
|
||||
e.InvolvedObject.Name = "test"
|
||||
e.InvolvedObject.Namespace = "test"
|
||||
e.Message = "test"
|
||||
return e
|
||||
},
|
||||
forwarded: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
event = tt.modifyEventFunc(event)
|
||||
testSent()
|
||||
if tt.forwarded {
|
||||
testForwarded()
|
||||
} else {
|
||||
testFiltered()
|
||||
}
|
||||
req = nil
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,321 +0,0 @@
|
|||
/*
|
||||
Copyright 2022 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
kerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||
kuberecorder "k8s.io/client-go/tools/record"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/builder"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||
"sigs.k8s.io/controller-runtime/pkg/predicate"
|
||||
"sigs.k8s.io/controller-runtime/pkg/ratelimiter"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
"github.com/fluxcd/pkg/runtime/conditions"
|
||||
helper "github.com/fluxcd/pkg/runtime/controller"
|
||||
"github.com/fluxcd/pkg/runtime/patch"
|
||||
"github.com/fluxcd/pkg/runtime/predicates"
|
||||
|
||||
apiv1 "github.com/fluxcd/notification-controller/api/v1beta2"
|
||||
"github.com/fluxcd/notification-controller/internal/notifier"
|
||||
)
|
||||
|
||||
// ProviderReconciler reconciles a Provider object
|
||||
type ProviderReconciler struct {
|
||||
client.Client
|
||||
helper.Metrics
|
||||
kuberecorder.EventRecorder
|
||||
|
||||
ControllerName string
|
||||
}
|
||||
|
||||
type ProviderReconcilerOptions struct {
|
||||
MaxConcurrentReconciles int
|
||||
RateLimiter ratelimiter.RateLimiter
|
||||
}
|
||||
|
||||
func (r *ProviderReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
||||
return r.SetupWithManagerAndOptions(mgr, ProviderReconcilerOptions{})
|
||||
}
|
||||
|
||||
func (r *ProviderReconciler) SetupWithManagerAndOptions(mgr ctrl.Manager, opts ProviderReconcilerOptions) error {
|
||||
recoverPanic := true
|
||||
return ctrl.NewControllerManagedBy(mgr).
|
||||
For(&apiv1.Provider{}, builder.WithPredicates(
|
||||
predicate.Or(predicate.GenerationChangedPredicate{}, predicates.ReconcileRequestedPredicate{}),
|
||||
)).
|
||||
WithOptions(controller.Options{
|
||||
MaxConcurrentReconciles: opts.MaxConcurrentReconciles,
|
||||
RateLimiter: opts.RateLimiter,
|
||||
RecoverPanic: &recoverPanic,
|
||||
}).
|
||||
Complete(r)
|
||||
}
|
||||
|
||||
// +kubebuilder:rbac:groups=notification.toolkit.fluxcd.io,resources=providers,verbs=get;list;watch;create;update;patch;delete
|
||||
// +kubebuilder:rbac:groups=notification.toolkit.fluxcd.io,resources=providers/status,verbs=get;update;patch
|
||||
// +kubebuilder:rbac:groups="",resources=secrets,verbs=get;list;watch
|
||||
// +kubebuilder:rbac:groups="",resources=events,verbs=create;patch
|
||||
|
||||
func (r *ProviderReconciler) Reconcile(ctx context.Context, req ctrl.Request) (result ctrl.Result, retErr error) {
|
||||
reconcileStart := time.Now()
|
||||
log := ctrl.LoggerFrom(ctx)
|
||||
|
||||
obj := &apiv1.Provider{}
|
||||
if err := r.Get(ctx, req.NamespacedName, obj); err != nil {
|
||||
return ctrl.Result{}, client.IgnoreNotFound(err)
|
||||
}
|
||||
|
||||
// Initialize the runtime patcher with the current version of the object.
|
||||
patcher := patch.NewSerialPatcher(obj, r.Client)
|
||||
|
||||
defer func() {
|
||||
// Patch finalizers, status and conditions.
|
||||
if err := r.patch(ctx, obj, patcher); err != nil {
|
||||
retErr = kerrors.NewAggregate([]error{retErr, err})
|
||||
}
|
||||
|
||||
// Record Prometheus metrics.
|
||||
r.Metrics.RecordReadiness(ctx, obj)
|
||||
r.Metrics.RecordDuration(ctx, obj, reconcileStart)
|
||||
r.Metrics.RecordSuspend(ctx, obj, obj.Spec.Suspend)
|
||||
|
||||
// Emit warning event if the reconciliation failed.
|
||||
if retErr != nil {
|
||||
r.Event(obj, corev1.EventTypeWarning, meta.FailedReason, retErr.Error())
|
||||
}
|
||||
|
||||
// Log the staleness error and pause reconciliation until spec changes.
|
||||
if conditions.IsStalled(obj) {
|
||||
result = ctrl.Result{Requeue: false}
|
||||
log.Error(retErr, "Reconciliation has stalled")
|
||||
retErr = nil
|
||||
return
|
||||
}
|
||||
|
||||
// Log and emit success event.
|
||||
if retErr == nil && conditions.IsReady(obj) {
|
||||
msg := fmt.Sprintf("Reconciliation finished, next run in %s",
|
||||
obj.GetInterval().String())
|
||||
log.Info(msg)
|
||||
r.Event(obj, corev1.EventTypeNormal, meta.SucceededReason, msg)
|
||||
}
|
||||
}()
|
||||
|
||||
if !controllerutil.ContainsFinalizer(obj, apiv1.NotificationFinalizer) {
|
||||
controllerutil.AddFinalizer(obj, apiv1.NotificationFinalizer)
|
||||
result = ctrl.Result{Requeue: true}
|
||||
return
|
||||
}
|
||||
|
||||
if !obj.ObjectMeta.DeletionTimestamp.IsZero() {
|
||||
controllerutil.RemoveFinalizer(obj, apiv1.NotificationFinalizer)
|
||||
result = ctrl.Result{}
|
||||
return
|
||||
}
|
||||
|
||||
// Return early if the object is suspended.
|
||||
if obj.Spec.Suspend {
|
||||
log.Info("Reconciliation is suspended for this object")
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
return r.reconcile(ctx, obj)
|
||||
}
|
||||
|
||||
func (r *ProviderReconciler) reconcile(ctx context.Context, obj *apiv1.Provider) (ctrl.Result, error) {
|
||||
// Mark the resource as under reconciliation.
|
||||
conditions.MarkReconciling(obj, meta.ProgressingReason, "Reconciliation in progress")
|
||||
conditions.Delete(obj, meta.StalledCondition)
|
||||
|
||||
// Mark the reconciliation as stalled if the inline URL and/or proxy are invalid.
|
||||
if err := r.validateURLs(obj); err != nil {
|
||||
conditions.MarkFalse(obj, meta.ReadyCondition, meta.InvalidURLReason, err.Error())
|
||||
conditions.MarkTrue(obj, meta.StalledCondition, meta.InvalidURLReason, err.Error())
|
||||
return ctrl.Result{Requeue: true}, err
|
||||
}
|
||||
|
||||
// Validate the provider credentials.
|
||||
if err := r.validateCredentials(ctx, obj); err != nil {
|
||||
conditions.MarkFalse(obj, meta.ReadyCondition, apiv1.ValidationFailedReason, err.Error())
|
||||
return ctrl.Result{Requeue: true}, err
|
||||
}
|
||||
|
||||
conditions.MarkTrue(obj, meta.ReadyCondition, meta.SucceededReason, apiv1.InitializedReason)
|
||||
|
||||
return ctrl.Result{RequeueAfter: obj.GetInterval()}, nil
|
||||
}
|
||||
|
||||
func (r *ProviderReconciler) validateURLs(provider *apiv1.Provider) error {
|
||||
address := provider.Spec.Address
|
||||
proxy := provider.Spec.Proxy
|
||||
|
||||
if provider.Spec.SecretRef == nil {
|
||||
if _, err := url.ParseRequestURI(address); err != nil {
|
||||
return fmt.Errorf("invalid address %s: %w", address, err)
|
||||
}
|
||||
if _, err := url.ParseRequestURI(proxy); proxy != "" && err != nil {
|
||||
return fmt.Errorf("invalid proxy %s: %w", proxy, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *ProviderReconciler) validateCredentials(ctx context.Context, provider *apiv1.Provider) error {
|
||||
address := provider.Spec.Address
|
||||
proxy := provider.Spec.Proxy
|
||||
username := provider.Spec.Username
|
||||
password := ""
|
||||
token := ""
|
||||
headers := make(map[string]string)
|
||||
if provider.Spec.SecretRef != nil {
|
||||
var secret corev1.Secret
|
||||
secretName := types.NamespacedName{Namespace: provider.Namespace, Name: provider.Spec.SecretRef.Name}
|
||||
|
||||
if err := r.Get(ctx, secretName, &secret); err != nil {
|
||||
return fmt.Errorf("failed to read secret, error: %w", err)
|
||||
}
|
||||
|
||||
if a, ok := secret.Data["address"]; ok {
|
||||
address = string(a)
|
||||
}
|
||||
|
||||
if p, ok := secret.Data["password"]; ok {
|
||||
password = string(p)
|
||||
}
|
||||
|
||||
if p, ok := secret.Data["proxy"]; ok {
|
||||
proxy = string(p)
|
||||
}
|
||||
|
||||
if t, ok := secret.Data["token"]; ok {
|
||||
token = string(t)
|
||||
}
|
||||
|
||||
if u, ok := secret.Data["username"]; ok {
|
||||
username = string(u)
|
||||
}
|
||||
|
||||
if h, ok := secret.Data["headers"]; ok {
|
||||
err := yaml.Unmarshal(h, headers)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read headers from secret, error: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if address == "" {
|
||||
return fmt.Errorf("no address found in 'spec.address' nor in `spec.secretRef`")
|
||||
}
|
||||
|
||||
var certPool *x509.CertPool
|
||||
if provider.Spec.CertSecretRef != nil {
|
||||
var secret corev1.Secret
|
||||
secretName := types.NamespacedName{Namespace: provider.Namespace, Name: provider.Spec.CertSecretRef.Name}
|
||||
|
||||
if err := r.Get(ctx, secretName, &secret); err != nil {
|
||||
return fmt.Errorf("failed to read secret, error: %w", err)
|
||||
}
|
||||
|
||||
caFile, ok := secret.Data["caFile"]
|
||||
if !ok {
|
||||
return fmt.Errorf("no caFile found in secret %s", provider.Spec.CertSecretRef.Name)
|
||||
}
|
||||
|
||||
certPool = x509.NewCertPool()
|
||||
ok = certPool.AppendCertsFromPEM(caFile)
|
||||
if !ok {
|
||||
return fmt.Errorf("could not append to cert pool: invalid CA found in %s", provider.Spec.CertSecretRef.Name)
|
||||
}
|
||||
}
|
||||
|
||||
factory := notifier.NewFactory(address, proxy, username, provider.Spec.Channel, token, headers, certPool, password, string(provider.UID))
|
||||
if _, err := factory.Notifier(provider.Spec.Type); err != nil {
|
||||
return fmt.Errorf("failed to initialize provider, error: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// patch updates the object status, conditions and finalizers.
|
||||
func (r *ProviderReconciler) patch(ctx context.Context, obj *apiv1.Provider, patcher *patch.SerialPatcher) (retErr error) {
|
||||
// Configure the runtime patcher.
|
||||
patchOpts := []patch.Option{}
|
||||
ownedConditions := []string{
|
||||
meta.ReadyCondition,
|
||||
meta.ReconcilingCondition,
|
||||
meta.StalledCondition,
|
||||
}
|
||||
patchOpts = append(patchOpts,
|
||||
patch.WithOwnedConditions{Conditions: ownedConditions},
|
||||
patch.WithForceOverwriteConditions{},
|
||||
patch.WithFieldOwner(r.ControllerName),
|
||||
)
|
||||
|
||||
// Set the value of the reconciliation request in status.
|
||||
if v, ok := meta.ReconcileAnnotationValue(obj.GetAnnotations()); ok {
|
||||
obj.Status.LastHandledReconcileAt = v
|
||||
}
|
||||
|
||||
// Remove the Reconciling/Stalled condition and update the observed generation
|
||||
// if the reconciliation was successful.
|
||||
if conditions.IsTrue(obj, meta.ReadyCondition) {
|
||||
conditions.Delete(obj, meta.ReconcilingCondition)
|
||||
conditions.Delete(obj, meta.StalledCondition)
|
||||
obj.Status.ObservedGeneration = obj.Generation
|
||||
}
|
||||
|
||||
// Set the Reconciling reason to ProgressingWithRetry if the
|
||||
// reconciliation has failed.
|
||||
if conditions.IsFalse(obj, meta.ReadyCondition) &&
|
||||
conditions.Has(obj, meta.ReconcilingCondition) {
|
||||
rc := conditions.Get(obj, meta.ReconcilingCondition)
|
||||
rc.Reason = meta.ProgressingWithRetryReason
|
||||
conditions.Set(obj, rc)
|
||||
}
|
||||
|
||||
// Remove the Reconciling condition if the reconciliation has stalled.
|
||||
if conditions.Has(obj, meta.StalledCondition) {
|
||||
conditions.Delete(obj, meta.ReconcilingCondition)
|
||||
}
|
||||
|
||||
// Patch the object status, conditions and finalizers.
|
||||
if err := patcher.Patch(ctx, obj, patchOpts...); err != nil {
|
||||
if !obj.GetDeletionTimestamp().IsZero() {
|
||||
err = kerrors.FilterOut(err, func(e error) bool { return apierrors.IsNotFound(e) })
|
||||
}
|
||||
retErr = kerrors.NewAggregate([]error{retErr, err})
|
||||
if retErr != nil {
|
||||
return retErr
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -1,202 +0,0 @@
|
|||
/*
|
||||
Copyright 2022 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
. "github.com/onsi/gomega"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
apierrors "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/controller/controllerutil"
|
||||
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
"github.com/fluxcd/pkg/runtime/conditions"
|
||||
|
||||
apiv1 "github.com/fluxcd/notification-controller/api/v1beta2"
|
||||
)
|
||||
|
||||
func TestProviderReconciler_Reconcile(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
timeout := 5 * time.Second
|
||||
resultP := &apiv1.Provider{}
|
||||
namespaceName := "provider-" + randStringRunes(5)
|
||||
secretName := "secret-" + randStringRunes(5)
|
||||
|
||||
g.Expect(createNamespace(namespaceName)).NotTo(HaveOccurred(), "failed to create test namespace")
|
||||
|
||||
providerKey := types.NamespacedName{
|
||||
Name: fmt.Sprintf("provider-%s", randStringRunes(5)),
|
||||
Namespace: namespaceName,
|
||||
}
|
||||
provider := &apiv1.Provider{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: providerKey.Name,
|
||||
Namespace: providerKey.Namespace,
|
||||
},
|
||||
Spec: apiv1.ProviderSpec{
|
||||
Type: "generic",
|
||||
Address: "https://webhook.internal",
|
||||
},
|
||||
}
|
||||
g.Expect(k8sClient.Create(context.Background(), provider)).To(Succeed())
|
||||
|
||||
t.Run("reports ready status", func(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
|
||||
g.Eventually(func() bool {
|
||||
_ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(provider), resultP)
|
||||
return resultP.Status.ObservedGeneration == resultP.Generation
|
||||
}, timeout, time.Second).Should(BeTrue())
|
||||
|
||||
g.Expect(conditions.IsReady(resultP)).To(BeTrue())
|
||||
g.Expect(conditions.GetReason(resultP, meta.ReadyCondition)).To(BeIdenticalTo(meta.SucceededReason))
|
||||
|
||||
g.Expect(conditions.Has(resultP, meta.ReconcilingCondition)).To(BeFalse())
|
||||
g.Expect(controllerutil.ContainsFinalizer(resultP, apiv1.NotificationFinalizer)).To(BeTrue())
|
||||
})
|
||||
|
||||
t.Run("fails with secret not found error", func(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
|
||||
g.Expect(k8sClient.Get(context.Background(), client.ObjectKeyFromObject(provider), resultP)).To(Succeed())
|
||||
|
||||
resultP.Spec.SecretRef = &meta.LocalObjectReference{
|
||||
Name: secretName,
|
||||
}
|
||||
g.Expect(k8sClient.Update(context.Background(), resultP)).To(Succeed())
|
||||
|
||||
g.Eventually(func() bool {
|
||||
_ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(provider), resultP)
|
||||
return !conditions.IsReady(resultP)
|
||||
}, timeout, time.Second).Should(BeTrue())
|
||||
|
||||
g.Expect(conditions.GetReason(resultP, meta.ReadyCondition)).To(BeIdenticalTo(apiv1.ValidationFailedReason))
|
||||
g.Expect(conditions.GetMessage(resultP, meta.ReadyCondition)).To(ContainSubstring(secretName))
|
||||
|
||||
g.Expect(conditions.Has(resultP, meta.ReconcilingCondition)).To(BeTrue())
|
||||
g.Expect(conditions.GetReason(resultP, meta.ReconcilingCondition)).To(BeIdenticalTo(meta.ProgressingWithRetryReason))
|
||||
g.Expect(conditions.GetObservedGeneration(resultP, meta.ReconcilingCondition)).To(BeIdenticalTo(resultP.Generation))
|
||||
g.Expect(resultP.Status.ObservedGeneration).To(BeIdenticalTo(resultP.Generation - 1))
|
||||
})
|
||||
|
||||
t.Run("recovers when secret exists", func(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
|
||||
secret := &corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: secretName,
|
||||
Namespace: namespaceName,
|
||||
},
|
||||
StringData: map[string]string{
|
||||
"token": "test",
|
||||
},
|
||||
}
|
||||
g.Expect(k8sClient.Create(context.Background(), secret)).To(Succeed())
|
||||
|
||||
g.Eventually(func() bool {
|
||||
_ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(provider), resultP)
|
||||
return conditions.IsReady(resultP)
|
||||
}, timeout, time.Second).Should(BeTrue())
|
||||
|
||||
g.Expect(conditions.GetObservedGeneration(resultP, meta.ReadyCondition)).To(BeIdenticalTo(resultP.Generation))
|
||||
g.Expect(resultP.Status.ObservedGeneration).To(BeIdenticalTo(resultP.Generation))
|
||||
g.Expect(conditions.Has(resultP, meta.ReconcilingCondition)).To(BeFalse())
|
||||
})
|
||||
|
||||
t.Run("handles reconcileAt", func(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
|
||||
g.Expect(k8sClient.Get(context.Background(), client.ObjectKeyFromObject(provider), resultP)).To(Succeed())
|
||||
|
||||
reconcileRequestAt := metav1.Now().String()
|
||||
resultP.SetAnnotations(map[string]string{
|
||||
meta.ReconcileRequestAnnotation: reconcileRequestAt,
|
||||
})
|
||||
g.Expect(k8sClient.Update(context.Background(), resultP)).To(Succeed())
|
||||
|
||||
g.Eventually(func() bool {
|
||||
_ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(provider), resultP)
|
||||
return resultP.Status.LastHandledReconcileAt == reconcileRequestAt
|
||||
}, timeout, time.Second).Should(BeTrue())
|
||||
})
|
||||
|
||||
t.Run("becomes stalled on invalid proxy", func(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
|
||||
g.Expect(k8sClient.Get(context.Background(), client.ObjectKeyFromObject(provider), resultP)).To(Succeed())
|
||||
|
||||
resultP.Spec.SecretRef = nil
|
||||
resultP.Spec.Proxy = "https://proxy.internal|"
|
||||
g.Expect(k8sClient.Update(context.Background(), resultP)).To(Succeed())
|
||||
|
||||
g.Eventually(func() bool {
|
||||
_ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(provider), resultP)
|
||||
return !conditions.IsReady(resultP)
|
||||
}, timeout, time.Second).Should(BeTrue())
|
||||
|
||||
g.Expect(conditions.Has(resultP, meta.ReconcilingCondition)).To(BeFalse())
|
||||
g.Expect(conditions.Has(resultP, meta.StalledCondition)).To(BeTrue())
|
||||
g.Expect(conditions.GetObservedGeneration(resultP, meta.StalledCondition)).To(BeIdenticalTo(resultP.Generation))
|
||||
g.Expect(conditions.GetReason(resultP, meta.StalledCondition)).To(BeIdenticalTo(meta.InvalidURLReason))
|
||||
g.Expect(conditions.GetReason(resultP, meta.ReadyCondition)).To(BeIdenticalTo(meta.InvalidURLReason))
|
||||
})
|
||||
|
||||
t.Run("recovers from staleness", func(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
|
||||
g.Expect(k8sClient.Get(context.Background(), client.ObjectKeyFromObject(provider), resultP)).To(Succeed())
|
||||
|
||||
resultP.Spec.Proxy = "https://proxy.internal"
|
||||
g.Expect(k8sClient.Update(context.Background(), resultP)).To(Succeed())
|
||||
|
||||
g.Eventually(func() bool {
|
||||
_ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(provider), resultP)
|
||||
return conditions.IsReady(resultP)
|
||||
}, timeout, time.Second).Should(BeTrue())
|
||||
|
||||
g.Expect(conditions.Has(resultP, meta.ReconcilingCondition)).To(BeFalse())
|
||||
g.Expect(conditions.Has(resultP, meta.StalledCondition)).To(BeFalse())
|
||||
})
|
||||
|
||||
t.Run("finalizes suspended object", func(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
|
||||
g.Expect(k8sClient.Get(context.Background(), client.ObjectKeyFromObject(provider), resultP)).To(Succeed())
|
||||
|
||||
resultP.Spec.Suspend = true
|
||||
g.Expect(k8sClient.Update(context.Background(), resultP)).To(Succeed())
|
||||
|
||||
g.Eventually(func() bool {
|
||||
_ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(provider), resultP)
|
||||
return resultP.Spec.Suspend == true
|
||||
}, timeout, time.Second).Should(BeTrue())
|
||||
|
||||
g.Expect(k8sClient.Delete(context.Background(), resultP)).To(Succeed())
|
||||
|
||||
g.Eventually(func() bool {
|
||||
err := k8sClient.Get(context.Background(), client.ObjectKeyFromObject(provider), resultP)
|
||||
return apierrors.IsNotFound(err)
|
||||
}, timeout, time.Second).Should(BeTrue())
|
||||
})
|
||||
}
|
|
@ -0,0 +1,466 @@
|
|||
<h1>Notification API reference v1</h1>
|
||||
<p>Packages:</p>
|
||||
<ul class="simple">
|
||||
<li>
|
||||
<a href="#notification.toolkit.fluxcd.io%2fv1">notification.toolkit.fluxcd.io/v1</a>
|
||||
</li>
|
||||
</ul>
|
||||
<h2 id="notification.toolkit.fluxcd.io/v1">notification.toolkit.fluxcd.io/v1</h2>
|
||||
<p>Package v1 contains API Schema definitions for the notification v1 API group.</p>
|
||||
Resource Types:
|
||||
<ul class="simple"><li>
|
||||
<a href="#notification.toolkit.fluxcd.io/v1.Receiver">Receiver</a>
|
||||
</li></ul>
|
||||
<h3 id="notification.toolkit.fluxcd.io/v1.Receiver">Receiver
|
||||
</h3>
|
||||
<p>Receiver is the Schema for the receivers API.</p>
|
||||
<div class="md-typeset__scrollwrap">
|
||||
<div class="md-typeset__table">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Field</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<code>apiVersion</code><br>
|
||||
string</td>
|
||||
<td>
|
||||
<code>notification.toolkit.fluxcd.io/v1</code>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>kind</code><br>
|
||||
string
|
||||
</td>
|
||||
<td>
|
||||
<code>Receiver</code>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>metadata</code><br>
|
||||
<em>
|
||||
<a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.18/#objectmeta-v1-meta">
|
||||
Kubernetes meta/v1.ObjectMeta
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
Refer to the Kubernetes API documentation for the fields of the
|
||||
<code>metadata</code> field.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>spec</code><br>
|
||||
<em>
|
||||
<a href="#notification.toolkit.fluxcd.io/v1.ReceiverSpec">
|
||||
ReceiverSpec
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<br/>
|
||||
<br/>
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<code>type</code><br>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<p>Type of webhook sender, used to determine
|
||||
the validation procedure and payload deserialization.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>interval</code><br>
|
||||
<em>
|
||||
<a href="https://pkg.go.dev/k8s.io/apimachinery/pkg/apis/meta/v1#Duration">
|
||||
Kubernetes meta/v1.Duration
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>Interval at which to reconcile the Receiver with its Secret references.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>events</code><br>
|
||||
<em>
|
||||
[]string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>Events specifies the list of event types to handle,
|
||||
e.g. ‘push’ for GitHub or ‘Push Hook’ for GitLab.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>resources</code><br>
|
||||
<em>
|
||||
<a href="#notification.toolkit.fluxcd.io/v1.CrossNamespaceObjectReference">
|
||||
[]CrossNamespaceObjectReference
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<p>A list of resources to be notified about changes.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>resourceFilter</code><br>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>ResourceFilter is a CEL expression expected to return a boolean that is
|
||||
evaluated for each resource referenced in the Resources field when a
|
||||
webhook is received. If the expression returns false then the controller
|
||||
will not request a reconciliation for the resource.
|
||||
When the expression is specified the controller will parse it and mark
|
||||
the object as terminally failed if the expression is invalid or does not
|
||||
return a boolean.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>secretRef</code><br>
|
||||
<em>
|
||||
<a href="https://pkg.go.dev/github.com/fluxcd/pkg/apis/meta#LocalObjectReference">
|
||||
github.com/fluxcd/pkg/apis/meta.LocalObjectReference
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<p>SecretRef specifies the Secret containing the token used
|
||||
to validate the payload authenticity.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>suspend</code><br>
|
||||
<em>
|
||||
bool
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>Suspend tells the controller to suspend subsequent
|
||||
events handling for this receiver.</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>status</code><br>
|
||||
<em>
|
||||
<a href="#notification.toolkit.fluxcd.io/v1.ReceiverStatus">
|
||||
ReceiverStatus
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<h3 id="notification.toolkit.fluxcd.io/v1.CrossNamespaceObjectReference">CrossNamespaceObjectReference
|
||||
</h3>
|
||||
<p>
|
||||
(<em>Appears on:</em>
|
||||
<a href="#notification.toolkit.fluxcd.io/v1.ReceiverSpec">ReceiverSpec</a>)
|
||||
</p>
|
||||
<p>CrossNamespaceObjectReference contains enough information to let you locate the
|
||||
typed referenced object at cluster level</p>
|
||||
<div class="md-typeset__scrollwrap">
|
||||
<div class="md-typeset__table">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Field</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<code>apiVersion</code><br>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>API version of the referent</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>kind</code><br>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<p>Kind of the referent</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>name</code><br>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<p>Name of the referent
|
||||
If multiple resources are targeted <code>*</code> may be set.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>namespace</code><br>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>Namespace of the referent</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>matchLabels</code><br>
|
||||
<em>
|
||||
map[string]string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>MatchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
|
||||
map is equivalent to an element of matchExpressions, whose key field is “key”, the
|
||||
operator is “In”, and the values array contains only “value”. The requirements are ANDed.
|
||||
MatchLabels requires the name to be set to <code>*</code>.</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<h3 id="notification.toolkit.fluxcd.io/v1.ReceiverSpec">ReceiverSpec
|
||||
</h3>
|
||||
<p>
|
||||
(<em>Appears on:</em>
|
||||
<a href="#notification.toolkit.fluxcd.io/v1.Receiver">Receiver</a>)
|
||||
</p>
|
||||
<p>ReceiverSpec defines the desired state of the Receiver.</p>
|
||||
<div class="md-typeset__scrollwrap">
|
||||
<div class="md-typeset__table">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Field</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<code>type</code><br>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<p>Type of webhook sender, used to determine
|
||||
the validation procedure and payload deserialization.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>interval</code><br>
|
||||
<em>
|
||||
<a href="https://pkg.go.dev/k8s.io/apimachinery/pkg/apis/meta/v1#Duration">
|
||||
Kubernetes meta/v1.Duration
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>Interval at which to reconcile the Receiver with its Secret references.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>events</code><br>
|
||||
<em>
|
||||
[]string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>Events specifies the list of event types to handle,
|
||||
e.g. ‘push’ for GitHub or ‘Push Hook’ for GitLab.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>resources</code><br>
|
||||
<em>
|
||||
<a href="#notification.toolkit.fluxcd.io/v1.CrossNamespaceObjectReference">
|
||||
[]CrossNamespaceObjectReference
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<p>A list of resources to be notified about changes.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>resourceFilter</code><br>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>ResourceFilter is a CEL expression expected to return a boolean that is
|
||||
evaluated for each resource referenced in the Resources field when a
|
||||
webhook is received. If the expression returns false then the controller
|
||||
will not request a reconciliation for the resource.
|
||||
When the expression is specified the controller will parse it and mark
|
||||
the object as terminally failed if the expression is invalid or does not
|
||||
return a boolean.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>secretRef</code><br>
|
||||
<em>
|
||||
<a href="https://pkg.go.dev/github.com/fluxcd/pkg/apis/meta#LocalObjectReference">
|
||||
github.com/fluxcd/pkg/apis/meta.LocalObjectReference
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<p>SecretRef specifies the Secret containing the token used
|
||||
to validate the payload authenticity.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>suspend</code><br>
|
||||
<em>
|
||||
bool
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>Suspend tells the controller to suspend subsequent
|
||||
events handling for this receiver.</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<h3 id="notification.toolkit.fluxcd.io/v1.ReceiverStatus">ReceiverStatus
|
||||
</h3>
|
||||
<p>
|
||||
(<em>Appears on:</em>
|
||||
<a href="#notification.toolkit.fluxcd.io/v1.Receiver">Receiver</a>)
|
||||
</p>
|
||||
<p>ReceiverStatus defines the observed state of the Receiver.</p>
|
||||
<div class="md-typeset__scrollwrap">
|
||||
<div class="md-typeset__table">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Field</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<code>ReconcileRequestStatus</code><br>
|
||||
<em>
|
||||
<a href="https://pkg.go.dev/github.com/fluxcd/pkg/apis/meta#ReconcileRequestStatus">
|
||||
github.com/fluxcd/pkg/apis/meta.ReconcileRequestStatus
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<p>
|
||||
(Members of <code>ReconcileRequestStatus</code> are embedded into this type.)
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>conditions</code><br>
|
||||
<em>
|
||||
<a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.18/#condition-v1-meta">
|
||||
[]Kubernetes meta/v1.Condition
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>Conditions holds the conditions for the Receiver.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>webhookPath</code><br>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>WebhookPath is the generated incoming webhook address in the format
|
||||
of ‘/hook/sha256sum(token+name+namespace)’.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>observedGeneration</code><br>
|
||||
<em>
|
||||
int64
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>ObservedGeneration is the last observed generation of the Receiver object.</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="admonition note">
|
||||
<p class="last">This page was automatically generated with <code>gen-crd-api-reference-docs</code></p>
|
||||
</div>
|
|
@ -1,4 +1,4 @@
|
|||
<h1>Notification API reference</h1>
|
||||
<h1>Notification API reference v1beta2</h1>
|
||||
<p>Packages:</p>
|
||||
<ul class="simple">
|
||||
<li>
|
||||
|
@ -76,7 +76,7 @@ AlertSpec
|
|||
<td>
|
||||
<code>providerRef</code><br>
|
||||
<em>
|
||||
<a href="https://godoc.org/github.com/fluxcd/pkg/apis/meta#LocalObjectReference">
|
||||
<a href="https://pkg.go.dev/github.com/fluxcd/pkg/apis/meta#LocalObjectReference">
|
||||
github.com/fluxcd/pkg/apis/meta.LocalObjectReference
|
||||
</a>
|
||||
</em>
|
||||
|
@ -102,8 +102,8 @@ If set to ‘info’ no events will be filtered.</p>
|
|||
<td>
|
||||
<code>eventSources</code><br>
|
||||
<em>
|
||||
<a href="#notification.toolkit.fluxcd.io/v1beta2.CrossNamespaceObjectReference">
|
||||
[]CrossNamespaceObjectReference
|
||||
<a href="https://pkg.go.dev/github.com/fluxcd/notification-controller/api/v1#CrossNamespaceObjectReference">
|
||||
[]github.com/fluxcd/notification-controller/api/v1.CrossNamespaceObjectReference
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
|
@ -114,6 +114,35 @@ on the involved object kind, name and namespace.</p>
|
|||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>inclusionList</code><br>
|
||||
<em>
|
||||
[]string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>InclusionList specifies a list of Golang regular expressions
|
||||
to be used for including messages.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>eventMetadata</code><br>
|
||||
<em>
|
||||
map[string]string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>EventMetadata is an optional field for adding metadata to events dispatched by the
|
||||
controller. This can be used for enhancing the context of the event. If a field
|
||||
would override one already present on the original event as generated by the emitter,
|
||||
then the override doesn’t happen, i.e. the original value is preserved, and an info
|
||||
log is printed.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>exclusionList</code><br>
|
||||
<em>
|
||||
[]string
|
||||
|
@ -241,7 +270,7 @@ string
|
|||
<td>
|
||||
<code>interval</code><br>
|
||||
<em>
|
||||
<a href="https://godoc.org/k8s.io/apimachinery/pkg/apis/meta/v1#Duration">
|
||||
<a href="https://pkg.go.dev/k8s.io/apimachinery/pkg/apis/meta/v1#Duration">
|
||||
Kubernetes meta/v1.Duration
|
||||
</a>
|
||||
</em>
|
||||
|
@ -284,14 +313,17 @@ string
|
|||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>Address specifies the HTTP/S incoming webhook address of this Provider.</p>
|
||||
<p>Address specifies the endpoint, in a generic sense, to where alerts are sent.
|
||||
What kind of endpoint depends on the specific Provider type being used.
|
||||
For the generic Provider, for example, this is an HTTP/S address.
|
||||
For other Provider types this could be a project ID or a namespace.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>timeout</code><br>
|
||||
<em>
|
||||
<a href="https://godoc.org/k8s.io/apimachinery/pkg/apis/meta/v1#Duration">
|
||||
<a href="https://pkg.go.dev/k8s.io/apimachinery/pkg/apis/meta/v1#Duration">
|
||||
Kubernetes meta/v1.Duration
|
||||
</a>
|
||||
</em>
|
||||
|
@ -317,7 +349,7 @@ string
|
|||
<td>
|
||||
<code>secretRef</code><br>
|
||||
<em>
|
||||
<a href="https://godoc.org/github.com/fluxcd/pkg/apis/meta#LocalObjectReference">
|
||||
<a href="https://pkg.go.dev/github.com/fluxcd/pkg/apis/meta#LocalObjectReference">
|
||||
github.com/fluxcd/pkg/apis/meta.LocalObjectReference
|
||||
</a>
|
||||
</em>
|
||||
|
@ -332,7 +364,7 @@ credentials for this Provider.</p>
|
|||
<td>
|
||||
<code>certSecretRef</code><br>
|
||||
<em>
|
||||
<a href="https://godoc.org/github.com/fluxcd/pkg/apis/meta#LocalObjectReference">
|
||||
<a href="https://pkg.go.dev/github.com/fluxcd/pkg/apis/meta#LocalObjectReference">
|
||||
github.com/fluxcd/pkg/apis/meta.LocalObjectReference
|
||||
</a>
|
||||
</em>
|
||||
|
@ -340,7 +372,9 @@ github.com/fluxcd/pkg/apis/meta.LocalObjectReference
|
|||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>CertSecretRef specifies the Secret containing
|
||||
a PEM-encoded CA certificate (<code>caFile</code>).</p>
|
||||
a PEM-encoded CA certificate (in the <code>ca.crt</code> key).</p>
|
||||
<p>Note: Support for the <code>caFile</code> key has
|
||||
been deprecated.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
@ -448,7 +482,7 @@ the validation procedure and payload deserialization.</p>
|
|||
<td>
|
||||
<code>interval</code><br>
|
||||
<em>
|
||||
<a href="https://godoc.org/k8s.io/apimachinery/pkg/apis/meta/v1#Duration">
|
||||
<a href="https://pkg.go.dev/k8s.io/apimachinery/pkg/apis/meta/v1#Duration">
|
||||
Kubernetes meta/v1.Duration
|
||||
</a>
|
||||
</em>
|
||||
|
@ -475,8 +509,8 @@ e.g. ‘push’ for GitHub or ‘Push Hook’ for GitLab.</p>
|
|||
<td>
|
||||
<code>resources</code><br>
|
||||
<em>
|
||||
<a href="#notification.toolkit.fluxcd.io/v1beta2.CrossNamespaceObjectReference">
|
||||
[]CrossNamespaceObjectReference
|
||||
<a href="https://pkg.go.dev/github.com/fluxcd/notification-controller/api/v1#CrossNamespaceObjectReference">
|
||||
[]github.com/fluxcd/notification-controller/api/v1.CrossNamespaceObjectReference
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
|
@ -488,7 +522,7 @@ e.g. ‘push’ for GitHub or ‘Push Hook’ for GitLab.</p>
|
|||
<td>
|
||||
<code>secretRef</code><br>
|
||||
<em>
|
||||
<a href="https://godoc.org/github.com/fluxcd/pkg/apis/meta#LocalObjectReference">
|
||||
<a href="https://pkg.go.dev/github.com/fluxcd/pkg/apis/meta#LocalObjectReference">
|
||||
github.com/fluxcd/pkg/apis/meta.LocalObjectReference
|
||||
</a>
|
||||
</em>
|
||||
|
@ -551,7 +585,7 @@ ReceiverStatus
|
|||
<td>
|
||||
<code>providerRef</code><br>
|
||||
<em>
|
||||
<a href="https://godoc.org/github.com/fluxcd/pkg/apis/meta#LocalObjectReference">
|
||||
<a href="https://pkg.go.dev/github.com/fluxcd/pkg/apis/meta#LocalObjectReference">
|
||||
github.com/fluxcd/pkg/apis/meta.LocalObjectReference
|
||||
</a>
|
||||
</em>
|
||||
|
@ -577,8 +611,8 @@ If set to ‘info’ no events will be filtered.</p>
|
|||
<td>
|
||||
<code>eventSources</code><br>
|
||||
<em>
|
||||
<a href="#notification.toolkit.fluxcd.io/v1beta2.CrossNamespaceObjectReference">
|
||||
[]CrossNamespaceObjectReference
|
||||
<a href="https://pkg.go.dev/github.com/fluxcd/notification-controller/api/v1#CrossNamespaceObjectReference">
|
||||
[]github.com/fluxcd/notification-controller/api/v1.CrossNamespaceObjectReference
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
|
@ -589,6 +623,35 @@ on the involved object kind, name and namespace.</p>
|
|||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>inclusionList</code><br>
|
||||
<em>
|
||||
[]string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>InclusionList specifies a list of Golang regular expressions
|
||||
to be used for including messages.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>eventMetadata</code><br>
|
||||
<em>
|
||||
map[string]string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>EventMetadata is an optional field for adding metadata to events dispatched by the
|
||||
controller. This can be used for enhancing the context of the event. If a field
|
||||
would override one already present on the original event as generated by the emitter,
|
||||
then the override doesn’t happen, i.e. the original value is preserved, and an info
|
||||
log is printed.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>exclusionList</code><br>
|
||||
<em>
|
||||
[]string
|
||||
|
@ -650,7 +713,7 @@ events handling for this Alert.</p>
|
|||
<td>
|
||||
<code>ReconcileRequestStatus</code><br>
|
||||
<em>
|
||||
<a href="https://godoc.org/github.com/fluxcd/pkg/apis/meta#ReconcileRequestStatus">
|
||||
<a href="https://pkg.go.dev/github.com/fluxcd/pkg/apis/meta#ReconcileRequestStatus">
|
||||
github.com/fluxcd/pkg/apis/meta.ReconcileRequestStatus
|
||||
</a>
|
||||
</em>
|
||||
|
@ -693,11 +756,6 @@ int64
|
|||
</div>
|
||||
<h3 id="notification.toolkit.fluxcd.io/v1beta2.CrossNamespaceObjectReference">CrossNamespaceObjectReference
|
||||
</h3>
|
||||
<p>
|
||||
(<em>Appears on:</em>
|
||||
<a href="#notification.toolkit.fluxcd.io/v1beta2.AlertSpec">AlertSpec</a>,
|
||||
<a href="#notification.toolkit.fluxcd.io/v1beta2.ReceiverSpec">ReceiverSpec</a>)
|
||||
</p>
|
||||
<p>CrossNamespaceObjectReference contains enough information to let you locate the
|
||||
typed referenced object at cluster level</p>
|
||||
<div class="md-typeset__scrollwrap">
|
||||
|
@ -806,7 +864,7 @@ string
|
|||
<td>
|
||||
<code>interval</code><br>
|
||||
<em>
|
||||
<a href="https://godoc.org/k8s.io/apimachinery/pkg/apis/meta/v1#Duration">
|
||||
<a href="https://pkg.go.dev/k8s.io/apimachinery/pkg/apis/meta/v1#Duration">
|
||||
Kubernetes meta/v1.Duration
|
||||
</a>
|
||||
</em>
|
||||
|
@ -849,14 +907,17 @@ string
|
|||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>Address specifies the HTTP/S incoming webhook address of this Provider.</p>
|
||||
<p>Address specifies the endpoint, in a generic sense, to where alerts are sent.
|
||||
What kind of endpoint depends on the specific Provider type being used.
|
||||
For the generic Provider, for example, this is an HTTP/S address.
|
||||
For other Provider types this could be a project ID or a namespace.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>timeout</code><br>
|
||||
<em>
|
||||
<a href="https://godoc.org/k8s.io/apimachinery/pkg/apis/meta/v1#Duration">
|
||||
<a href="https://pkg.go.dev/k8s.io/apimachinery/pkg/apis/meta/v1#Duration">
|
||||
Kubernetes meta/v1.Duration
|
||||
</a>
|
||||
</em>
|
||||
|
@ -882,7 +943,7 @@ string
|
|||
<td>
|
||||
<code>secretRef</code><br>
|
||||
<em>
|
||||
<a href="https://godoc.org/github.com/fluxcd/pkg/apis/meta#LocalObjectReference">
|
||||
<a href="https://pkg.go.dev/github.com/fluxcd/pkg/apis/meta#LocalObjectReference">
|
||||
github.com/fluxcd/pkg/apis/meta.LocalObjectReference
|
||||
</a>
|
||||
</em>
|
||||
|
@ -897,7 +958,7 @@ credentials for this Provider.</p>
|
|||
<td>
|
||||
<code>certSecretRef</code><br>
|
||||
<em>
|
||||
<a href="https://godoc.org/github.com/fluxcd/pkg/apis/meta#LocalObjectReference">
|
||||
<a href="https://pkg.go.dev/github.com/fluxcd/pkg/apis/meta#LocalObjectReference">
|
||||
github.com/fluxcd/pkg/apis/meta.LocalObjectReference
|
||||
</a>
|
||||
</em>
|
||||
|
@ -905,7 +966,9 @@ github.com/fluxcd/pkg/apis/meta.LocalObjectReference
|
|||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>CertSecretRef specifies the Secret containing
|
||||
a PEM-encoded CA certificate (<code>caFile</code>).</p>
|
||||
a PEM-encoded CA certificate (in the <code>ca.crt</code> key).</p>
|
||||
<p>Note: Support for the <code>caFile</code> key has
|
||||
been deprecated.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
@ -946,7 +1009,7 @@ events handling for this Provider.</p>
|
|||
<td>
|
||||
<code>ReconcileRequestStatus</code><br>
|
||||
<em>
|
||||
<a href="https://godoc.org/github.com/fluxcd/pkg/apis/meta#ReconcileRequestStatus">
|
||||
<a href="https://pkg.go.dev/github.com/fluxcd/pkg/apis/meta#ReconcileRequestStatus">
|
||||
github.com/fluxcd/pkg/apis/meta.ReconcileRequestStatus
|
||||
</a>
|
||||
</em>
|
||||
|
@ -1020,7 +1083,7 @@ the validation procedure and payload deserialization.</p>
|
|||
<td>
|
||||
<code>interval</code><br>
|
||||
<em>
|
||||
<a href="https://godoc.org/k8s.io/apimachinery/pkg/apis/meta/v1#Duration">
|
||||
<a href="https://pkg.go.dev/k8s.io/apimachinery/pkg/apis/meta/v1#Duration">
|
||||
Kubernetes meta/v1.Duration
|
||||
</a>
|
||||
</em>
|
||||
|
@ -1047,8 +1110,8 @@ e.g. ‘push’ for GitHub or ‘Push Hook’ for GitLab.</p>
|
|||
<td>
|
||||
<code>resources</code><br>
|
||||
<em>
|
||||
<a href="#notification.toolkit.fluxcd.io/v1beta2.CrossNamespaceObjectReference">
|
||||
[]CrossNamespaceObjectReference
|
||||
<a href="https://pkg.go.dev/github.com/fluxcd/notification-controller/api/v1#CrossNamespaceObjectReference">
|
||||
[]github.com/fluxcd/notification-controller/api/v1.CrossNamespaceObjectReference
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
|
@ -1060,7 +1123,7 @@ e.g. ‘push’ for GitHub or ‘Push Hook’ for GitLab.</p>
|
|||
<td>
|
||||
<code>secretRef</code><br>
|
||||
<em>
|
||||
<a href="https://godoc.org/github.com/fluxcd/pkg/apis/meta#LocalObjectReference">
|
||||
<a href="https://pkg.go.dev/github.com/fluxcd/pkg/apis/meta#LocalObjectReference">
|
||||
github.com/fluxcd/pkg/apis/meta.LocalObjectReference
|
||||
</a>
|
||||
</em>
|
||||
|
@ -1108,7 +1171,7 @@ events handling for this receiver.</p>
|
|||
<td>
|
||||
<code>ReconcileRequestStatus</code><br>
|
||||
<em>
|
||||
<a href="https://godoc.org/github.com/fluxcd/pkg/apis/meta#ReconcileRequestStatus">
|
||||
<a href="https://pkg.go.dev/github.com/fluxcd/pkg/apis/meta#ReconcileRequestStatus">
|
||||
github.com/fluxcd/pkg/apis/meta.ReconcileRequestStatus
|
||||
</a>
|
||||
</em>
|
|
@ -0,0 +1,780 @@
|
|||
<h1>Notification API reference v1beta3</h1>
|
||||
<p>Packages:</p>
|
||||
<ul class="simple">
|
||||
<li>
|
||||
<a href="#notification.toolkit.fluxcd.io%2fv1beta3">notification.toolkit.fluxcd.io/v1beta3</a>
|
||||
</li>
|
||||
</ul>
|
||||
<h2 id="notification.toolkit.fluxcd.io/v1beta3">notification.toolkit.fluxcd.io/v1beta3</h2>
|
||||
<p>Package v1beta3 contains API Schema definitions for the notification v1beta3 API group.</p>
|
||||
Resource Types:
|
||||
<ul class="simple"><li>
|
||||
<a href="#notification.toolkit.fluxcd.io/v1beta3.Alert">Alert</a>
|
||||
</li><li>
|
||||
<a href="#notification.toolkit.fluxcd.io/v1beta3.Provider">Provider</a>
|
||||
</li></ul>
|
||||
<h3 id="notification.toolkit.fluxcd.io/v1beta3.Alert">Alert
|
||||
</h3>
|
||||
<p>Alert is the Schema for the alerts API</p>
|
||||
<div class="md-typeset__scrollwrap">
|
||||
<div class="md-typeset__table">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Field</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<code>apiVersion</code><br>
|
||||
string</td>
|
||||
<td>
|
||||
<code>notification.toolkit.fluxcd.io/v1beta3</code>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>kind</code><br>
|
||||
string
|
||||
</td>
|
||||
<td>
|
||||
<code>Alert</code>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>metadata</code><br>
|
||||
<em>
|
||||
<a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.18/#objectmeta-v1-meta">
|
||||
Kubernetes meta/v1.ObjectMeta
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
Refer to the Kubernetes API documentation for the fields of the
|
||||
<code>metadata</code> field.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>spec</code><br>
|
||||
<em>
|
||||
<a href="#notification.toolkit.fluxcd.io/v1beta3.AlertSpec">
|
||||
AlertSpec
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<br/>
|
||||
<br/>
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<code>providerRef</code><br>
|
||||
<em>
|
||||
<a href="https://pkg.go.dev/github.com/fluxcd/pkg/apis/meta#LocalObjectReference">
|
||||
github.com/fluxcd/pkg/apis/meta.LocalObjectReference
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<p>ProviderRef specifies which Provider this Alert should use.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>eventSeverity</code><br>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>EventSeverity specifies how to filter events based on severity.
|
||||
If set to ‘info’ no events will be filtered.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>eventSources</code><br>
|
||||
<em>
|
||||
<a href="https://pkg.go.dev/github.com/fluxcd/notification-controller/api/v1#CrossNamespaceObjectReference">
|
||||
[]github.com/fluxcd/notification-controller/api/v1.CrossNamespaceObjectReference
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<p>EventSources specifies how to filter events based
|
||||
on the involved object kind, name and namespace.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>inclusionList</code><br>
|
||||
<em>
|
||||
[]string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>InclusionList specifies a list of Golang regular expressions
|
||||
to be used for including messages.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>eventMetadata</code><br>
|
||||
<em>
|
||||
map[string]string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>EventMetadata is an optional field for adding metadata to events dispatched by the
|
||||
controller. This can be used for enhancing the context of the event. If a field
|
||||
would override one already present on the original event as generated by the emitter,
|
||||
then the override doesn’t happen, i.e. the original value is preserved, and an info
|
||||
log is printed.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>exclusionList</code><br>
|
||||
<em>
|
||||
[]string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>ExclusionList specifies a list of Golang regular expressions
|
||||
to be used for excluding messages.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>summary</code><br>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>Summary holds a short description of the impact and affected cluster.
|
||||
Deprecated: Use EventMetadata instead.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>suspend</code><br>
|
||||
<em>
|
||||
bool
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>Suspend tells the controller to suspend subsequent
|
||||
events handling for this Alert.</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<h3 id="notification.toolkit.fluxcd.io/v1beta3.Provider">Provider
|
||||
</h3>
|
||||
<p>Provider is the Schema for the providers API</p>
|
||||
<div class="md-typeset__scrollwrap">
|
||||
<div class="md-typeset__table">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Field</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<code>apiVersion</code><br>
|
||||
string</td>
|
||||
<td>
|
||||
<code>notification.toolkit.fluxcd.io/v1beta3</code>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>kind</code><br>
|
||||
string
|
||||
</td>
|
||||
<td>
|
||||
<code>Provider</code>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>metadata</code><br>
|
||||
<em>
|
||||
<a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.18/#objectmeta-v1-meta">
|
||||
Kubernetes meta/v1.ObjectMeta
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
Refer to the Kubernetes API documentation for the fields of the
|
||||
<code>metadata</code> field.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>spec</code><br>
|
||||
<em>
|
||||
<a href="#notification.toolkit.fluxcd.io/v1beta3.ProviderSpec">
|
||||
ProviderSpec
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<br/>
|
||||
<br/>
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<code>type</code><br>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<p>Type specifies which Provider implementation to use.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>interval</code><br>
|
||||
<em>
|
||||
<a href="https://pkg.go.dev/k8s.io/apimachinery/pkg/apis/meta/v1#Duration">
|
||||
Kubernetes meta/v1.Duration
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>Interval at which to reconcile the Provider with its Secret references.
|
||||
Deprecated and not used in v1beta3.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>channel</code><br>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>Channel specifies the destination channel where events should be posted.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>username</code><br>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>Username specifies the name under which events are posted.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>address</code><br>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>Address specifies the endpoint, in a generic sense, to where alerts are sent.
|
||||
What kind of endpoint depends on the specific Provider type being used.
|
||||
For the generic Provider, for example, this is an HTTP/S address.
|
||||
For other Provider types this could be a project ID or a namespace.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>timeout</code><br>
|
||||
<em>
|
||||
<a href="https://pkg.go.dev/k8s.io/apimachinery/pkg/apis/meta/v1#Duration">
|
||||
Kubernetes meta/v1.Duration
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>Timeout for sending alerts to the Provider.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>proxy</code><br>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>Proxy the HTTP/S address of the proxy server.
|
||||
Deprecated: Use ProxySecretRef instead. Will be removed in v1.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>proxySecretRef</code><br>
|
||||
<em>
|
||||
<a href="https://pkg.go.dev/github.com/fluxcd/pkg/apis/meta#LocalObjectReference">
|
||||
github.com/fluxcd/pkg/apis/meta.LocalObjectReference
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>ProxySecretRef specifies the Secret containing the proxy configuration
|
||||
for this Provider. The Secret should contain an ‘address’ key with the
|
||||
HTTP/S address of the proxy server. Optional ‘username’ and ‘password’
|
||||
keys can be provided for proxy authentication.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>secretRef</code><br>
|
||||
<em>
|
||||
<a href="https://pkg.go.dev/github.com/fluxcd/pkg/apis/meta#LocalObjectReference">
|
||||
github.com/fluxcd/pkg/apis/meta.LocalObjectReference
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>SecretRef specifies the Secret containing the authentication
|
||||
credentials for this Provider.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>serviceAccountName</code><br>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>ServiceAccountName is the name of the service account used to
|
||||
authenticate with services from cloud providers. An error is thrown if a
|
||||
static credential is also defined inside the Secret referenced by the
|
||||
SecretRef.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>certSecretRef</code><br>
|
||||
<em>
|
||||
<a href="https://pkg.go.dev/github.com/fluxcd/pkg/apis/meta#LocalObjectReference">
|
||||
github.com/fluxcd/pkg/apis/meta.LocalObjectReference
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>CertSecretRef specifies the Secret containing TLS certificates
|
||||
for secure communication.</p>
|
||||
<p>Supported configurations:
|
||||
- CA-only: Server authentication (provide ca.crt only)
|
||||
- mTLS: Mutual authentication (provide ca.crt + tls.crt + tls.key)
|
||||
- Client-only: Client authentication with system CA (provide tls.crt + tls.key only)</p>
|
||||
<p>Legacy keys “caFile”, “certFile”, “keyFile” are supported but deprecated. Use “ca.crt”, “tls.crt”, “tls.key” instead.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>suspend</code><br>
|
||||
<em>
|
||||
bool
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>Suspend tells the controller to suspend subsequent
|
||||
events handling for this Provider.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>commitStatusExpr</code><br>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>CommitStatusExpr is a CEL expression that evaluates to a string value
|
||||
that can be used to generate a custom commit status message for use
|
||||
with eligible Provider types (github, gitlab, gitea, bitbucketserver,
|
||||
bitbucket, azuredevops). Supported variables are: event, provider,
|
||||
and alert.</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<h3 id="notification.toolkit.fluxcd.io/v1beta3.AlertSpec">AlertSpec
|
||||
</h3>
|
||||
<p>
|
||||
(<em>Appears on:</em>
|
||||
<a href="#notification.toolkit.fluxcd.io/v1beta3.Alert">Alert</a>)
|
||||
</p>
|
||||
<p>AlertSpec defines an alerting rule for events involving a list of objects.</p>
|
||||
<div class="md-typeset__scrollwrap">
|
||||
<div class="md-typeset__table">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Field</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<code>providerRef</code><br>
|
||||
<em>
|
||||
<a href="https://pkg.go.dev/github.com/fluxcd/pkg/apis/meta#LocalObjectReference">
|
||||
github.com/fluxcd/pkg/apis/meta.LocalObjectReference
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<p>ProviderRef specifies which Provider this Alert should use.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>eventSeverity</code><br>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>EventSeverity specifies how to filter events based on severity.
|
||||
If set to ‘info’ no events will be filtered.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>eventSources</code><br>
|
||||
<em>
|
||||
<a href="https://pkg.go.dev/github.com/fluxcd/notification-controller/api/v1#CrossNamespaceObjectReference">
|
||||
[]github.com/fluxcd/notification-controller/api/v1.CrossNamespaceObjectReference
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<p>EventSources specifies how to filter events based
|
||||
on the involved object kind, name and namespace.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>inclusionList</code><br>
|
||||
<em>
|
||||
[]string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>InclusionList specifies a list of Golang regular expressions
|
||||
to be used for including messages.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>eventMetadata</code><br>
|
||||
<em>
|
||||
map[string]string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>EventMetadata is an optional field for adding metadata to events dispatched by the
|
||||
controller. This can be used for enhancing the context of the event. If a field
|
||||
would override one already present on the original event as generated by the emitter,
|
||||
then the override doesn’t happen, i.e. the original value is preserved, and an info
|
||||
log is printed.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>exclusionList</code><br>
|
||||
<em>
|
||||
[]string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>ExclusionList specifies a list of Golang regular expressions
|
||||
to be used for excluding messages.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>summary</code><br>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>Summary holds a short description of the impact and affected cluster.
|
||||
Deprecated: Use EventMetadata instead.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>suspend</code><br>
|
||||
<em>
|
||||
bool
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>Suspend tells the controller to suspend subsequent
|
||||
events handling for this Alert.</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<h3 id="notification.toolkit.fluxcd.io/v1beta3.ProviderSpec">ProviderSpec
|
||||
</h3>
|
||||
<p>
|
||||
(<em>Appears on:</em>
|
||||
<a href="#notification.toolkit.fluxcd.io/v1beta3.Provider">Provider</a>)
|
||||
</p>
|
||||
<p>ProviderSpec defines the desired state of the Provider.</p>
|
||||
<div class="md-typeset__scrollwrap">
|
||||
<div class="md-typeset__table">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Field</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<code>type</code><br>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<p>Type specifies which Provider implementation to use.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>interval</code><br>
|
||||
<em>
|
||||
<a href="https://pkg.go.dev/k8s.io/apimachinery/pkg/apis/meta/v1#Duration">
|
||||
Kubernetes meta/v1.Duration
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>Interval at which to reconcile the Provider with its Secret references.
|
||||
Deprecated and not used in v1beta3.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>channel</code><br>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>Channel specifies the destination channel where events should be posted.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>username</code><br>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>Username specifies the name under which events are posted.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>address</code><br>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>Address specifies the endpoint, in a generic sense, to where alerts are sent.
|
||||
What kind of endpoint depends on the specific Provider type being used.
|
||||
For the generic Provider, for example, this is an HTTP/S address.
|
||||
For other Provider types this could be a project ID or a namespace.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>timeout</code><br>
|
||||
<em>
|
||||
<a href="https://pkg.go.dev/k8s.io/apimachinery/pkg/apis/meta/v1#Duration">
|
||||
Kubernetes meta/v1.Duration
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>Timeout for sending alerts to the Provider.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>proxy</code><br>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>Proxy the HTTP/S address of the proxy server.
|
||||
Deprecated: Use ProxySecretRef instead. Will be removed in v1.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>proxySecretRef</code><br>
|
||||
<em>
|
||||
<a href="https://pkg.go.dev/github.com/fluxcd/pkg/apis/meta#LocalObjectReference">
|
||||
github.com/fluxcd/pkg/apis/meta.LocalObjectReference
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>ProxySecretRef specifies the Secret containing the proxy configuration
|
||||
for this Provider. The Secret should contain an ‘address’ key with the
|
||||
HTTP/S address of the proxy server. Optional ‘username’ and ‘password’
|
||||
keys can be provided for proxy authentication.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>secretRef</code><br>
|
||||
<em>
|
||||
<a href="https://pkg.go.dev/github.com/fluxcd/pkg/apis/meta#LocalObjectReference">
|
||||
github.com/fluxcd/pkg/apis/meta.LocalObjectReference
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>SecretRef specifies the Secret containing the authentication
|
||||
credentials for this Provider.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>serviceAccountName</code><br>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>ServiceAccountName is the name of the service account used to
|
||||
authenticate with services from cloud providers. An error is thrown if a
|
||||
static credential is also defined inside the Secret referenced by the
|
||||
SecretRef.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>certSecretRef</code><br>
|
||||
<em>
|
||||
<a href="https://pkg.go.dev/github.com/fluxcd/pkg/apis/meta#LocalObjectReference">
|
||||
github.com/fluxcd/pkg/apis/meta.LocalObjectReference
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>CertSecretRef specifies the Secret containing TLS certificates
|
||||
for secure communication.</p>
|
||||
<p>Supported configurations:
|
||||
- CA-only: Server authentication (provide ca.crt only)
|
||||
- mTLS: Mutual authentication (provide ca.crt + tls.crt + tls.key)
|
||||
- Client-only: Client authentication with system CA (provide tls.crt + tls.key only)</p>
|
||||
<p>Legacy keys “caFile”, “certFile”, “keyFile” are supported but deprecated. Use “ca.crt”, “tls.crt”, “tls.key” instead.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>suspend</code><br>
|
||||
<em>
|
||||
bool
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>Suspend tells the controller to suspend subsequent
|
||||
events handling for this Provider.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>commitStatusExpr</code><br>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>CommitStatusExpr is a CEL expression that evaluates to a string value
|
||||
that can be used to generate a custom commit status message for use
|
||||
with eligible Provider types (github, gitlab, gitea, bitbucketserver,
|
||||
bitbucket, azuredevops). Supported variables are: event, provider,
|
||||
and alert.</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="admonition note">
|
||||
<p class="last">This page was automatically generated with <code>gen-crd-api-reference-docs</code></p>
|
||||
</div>
|
|
@ -1,66 +1,9 @@
|
|||
# Notification Controller
|
||||
|
||||
The Notification Controller is a Kubernetes operator, specialized in handling inbound and outbound events.
|
||||
## API Specification
|
||||
|
||||
## Motivation
|
||||
|
||||
### Events dispatching
|
||||
|
||||
The main goal is to provide a notification service that can
|
||||
receive events via HTTP and dispatch them to external systems
|
||||
based on event severity and involved objects.
|
||||
|
||||
When operating a cluster, different teams may wish to receive notification about the status
|
||||
of their CD pipelines. For example, the on-call team would receive alerts about all
|
||||
failures in the cluster, while the dev team may wish to be alerted when a new version
|
||||
of an app was deployed and if the deployment is healthy.
|
||||
|
||||
### Webhook receivers
|
||||
|
||||
GitOps controllers are by nature pull based, in order to notify the controllers about
|
||||
changes in Git or Helm repositories, one may wish to setup webhooks and trigger
|
||||
a cluster reconciliation every time a source changes.
|
||||
|
||||
## Design
|
||||
|
||||
### Events dispatching
|
||||
|
||||
The controller exposes an HTTP endpoint for receiving events from other controllers.
|
||||
An event must contain information about the involved object such as kind, name, namespace,
|
||||
a human-readable description of the event and the severity type e.g. info or error.
|
||||
|
||||
The controller can be configured with Kubernetes custom resources that define how
|
||||
events are processed and where to dispatch them.
|
||||
|
||||
Notification API:
|
||||
|
||||
* [Alerts](v1beta2/alerts.md)
|
||||
* [Providers](v1beta2/providers.md)
|
||||
* [Events](v1beta2/events.md)
|
||||
|
||||
The alert delivery method is **at-most once** with a timeout of 15 seconds.
|
||||
The controller performs automatic retries for connection errors and 500-range response code.
|
||||
If the webhook receiver returns an error, the controller will retry sending an alert for four times
|
||||
with an exponential backoff of maximum 30 seconds.
|
||||
|
||||
### Webhook receivers
|
||||
|
||||
The notification controller handles webhook requests on a dedicated port.
|
||||
This port can be used to create a Kubernetes LoadBalancer Service or
|
||||
Ingress to expose the receiver endpoint outside the cluster
|
||||
to be accessed by GitHub, GitLab, Bitbucket, Harbor, DockerHub, Jenkins, Quay, etc.
|
||||
|
||||
Receiver API:
|
||||
|
||||
* [Receivers](v1beta2/receivers.md)
|
||||
|
||||
When a `Receiver` is created, the controller sets the `Receiver`
|
||||
status to Ready and generates a URL in the format `/hook/sha256sum(token+name+namespace)`.
|
||||
|
||||
When the controller receives a POST request:
|
||||
* extract the SHA265 digest from the URL
|
||||
* loads the `Receiver` using the digest field selector
|
||||
* extracts the signature from HTTP headers based on `spec.type`
|
||||
* validates the signature using the `token` secret
|
||||
* extract the event type from the payload
|
||||
* triggers a reconciliation for `spec.resources` if the event type matches one of the `spec.events` items
|
||||
* [v1](v1/README.md)
|
||||
* [v1beta3](v1beta3/README.md)
|
||||
* [v1beta2](v1beta2/README.md)
|
||||
* [v1beta1](v1beta1/README.md)
|
||||
* [v1alpha1](v1alpha1/README.md)
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
# notification.toolkit.fluxcd.io/v1
|
||||
|
||||
This is the v1 API specification for defining events handling and dispatching.
|
||||
|
||||
## Specification
|
||||
|
||||
* [Receivers](receivers.md)
|
File diff suppressed because it is too large
Load Diff
|
@ -4,11 +4,11 @@ This is the v1alpha1 API specification for defining events handling and dispatch
|
|||
|
||||
## Specification
|
||||
|
||||
* [Alert](alert.md)
|
||||
* [Event](event.md)
|
||||
* [Provider](provider.md)
|
||||
* [Receiver](receiver.md)
|
||||
* [Alert](alerts.md)
|
||||
* [Event](events.md)
|
||||
* [Provider](providers.md)
|
||||
* [Receiver](receivers.md)
|
||||
|
||||
## Go Client
|
||||
|
||||
* [github.com/fluxcd/pkg/recorder](https://github.com/fluxcd/pkg/tree/main/recorder)
|
||||
* [github.com/fluxcd/pkg/runtime/events/recorder.go](https://github.com/fluxcd/pkg/blob/main/runtime/events/recorder.go#L60)
|
||||
|
|
|
@ -368,7 +368,8 @@ and use `https://api.telegram.org/` as the api url.
|
|||
--from-literal=address=https://api.telegram.org
|
||||
```
|
||||
|
||||
Also note that `spec.channel` can be a unique identifier for the target chat
|
||||
Also note that `spec.channel` can be a unique identifier for the target chat,
|
||||
a unique identifier with the topic identifier for the forum chat
|
||||
or username of the target channel (in the format @channelusername)
|
||||
|
||||
```yaml
|
||||
|
@ -379,7 +380,7 @@ metadata:
|
|||
namespace: flux-system
|
||||
spec:
|
||||
type: telegram
|
||||
channel: "@fluxtest" # or "-1557265138" (channel id)
|
||||
channel: "@fluxtest" # or "-1557265138" (channel id) or "-1552289257:1" (forum chat id with topic id)
|
||||
secretRef:
|
||||
name: telegram-token
|
||||
```
|
|
@ -11,4 +11,4 @@ This is the v1beta2 API specification for defining events handling and dispatchi
|
|||
|
||||
## Go Client
|
||||
|
||||
* [github.com/fluxcd/pkg/recorder](https://github.com/fluxcd/pkg/tree/main/recorder)
|
||||
* [github.com/fluxcd/pkg/runtime/events](https://pkg.go.dev/github.com/fluxcd/pkg/runtime/events)
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
# Alerts
|
||||
|
||||
<!-- menuweight:10 -->
|
||||
|
||||
The `Alert` API defines how events are filtered by severity and involved object, and what provider to use for dispatching.
|
||||
|
||||
## Example
|
||||
|
@ -160,6 +162,36 @@ starting the controller with the `--no-cross-namespace-refs=true` flag.
|
|||
When this flag is set, alerts can only refer to event sources in the same namespace as the alert object,
|
||||
preventing tenants from subscribing to another tenant's events.
|
||||
|
||||
### Event metadata
|
||||
|
||||
`.spec.eventMetadata` is an optional field for adding metadata to events dispatched by
|
||||
the controller. This can be used for enhancing the context of the event. If a field
|
||||
would override one already present on the original event as generated by the emitter,
|
||||
then the override doesn't happen, i.e. the original value is preserved, and an info
|
||||
log is printed.
|
||||
|
||||
#### Example
|
||||
|
||||
Add metadata fields to successful `HelmRelease` events:
|
||||
|
||||
```yaml
|
||||
---
|
||||
apiVersion: notification.toolkit.fluxcd.io/v1beta2
|
||||
kind: Alert
|
||||
metadata:
|
||||
name: <name>
|
||||
spec:
|
||||
eventSources:
|
||||
- kind: HelmRelease
|
||||
name: '*'
|
||||
inclusionList:
|
||||
- ".*succeeded.*"
|
||||
eventMetadata:
|
||||
app.kubernetes.io/env: "production"
|
||||
app.kubernetes.io/cluster: "my-cluster"
|
||||
app.kubernetes.io/region: "us-east-1"
|
||||
```
|
||||
|
||||
### Event severity
|
||||
|
||||
`.spec.eventSeverity` is an optional field to filter events based on severity. When not specified, or
|
||||
|
@ -169,7 +201,8 @@ To receive alerts only on errors, set the field value to `error`.
|
|||
### Event exclusion
|
||||
|
||||
`.spec.exclusionList` is an optional field to specify a list of regex expressions to filter
|
||||
events based on message content.
|
||||
events based on message content. The event will be excluded if the message matches at least
|
||||
one of the expressions in the list.
|
||||
|
||||
#### Example
|
||||
|
||||
|
@ -196,6 +229,39 @@ The above definition will not send alerts for transient Git clone errors like:
|
|||
unable to clone 'ssh://git@ssh.dev.azure.com/v3/...', error: SSH could not read data: Error waiting on socket
|
||||
```
|
||||
|
||||
### Event inclusion
|
||||
|
||||
`.spec.inclusionList` is an optional field to specify a list of regex expressions to filter
|
||||
events based on message content. The event will be sent if the message matches at least one
|
||||
of the expressions in the list, and discarded otherwise. If the message matches one of the
|
||||
expressions in the inclusion list but also matches one of the expressions in the exclusion
|
||||
list, then the event is still discarded (exclusion is stronger than inclusion).
|
||||
|
||||
#### Example
|
||||
|
||||
Alert if the message matches a [Go regex](https://golang.org/pkg/regexp/syntax)
|
||||
from the inclusion list:
|
||||
|
||||
```yaml
|
||||
---
|
||||
apiVersion: notification.toolkit.fluxcd.io/v1beta2
|
||||
kind: Alert
|
||||
metadata:
|
||||
name: <name>
|
||||
spec:
|
||||
eventSources:
|
||||
- kind: HelmRelease
|
||||
name: '*'
|
||||
inclusionList:
|
||||
- ".*succeeded.*"
|
||||
exclusionList:
|
||||
- ".*uninstall.*"
|
||||
- ".*test.*"
|
||||
```
|
||||
|
||||
The above definition will send alerts for successful Helm installs, upgrades and rollbacks,
|
||||
but not uninstalls and tests.
|
||||
|
||||
### Suspend
|
||||
|
||||
`.spec.suspend` is an optional field to suspend the altering.
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
# Events
|
||||
|
||||
<!-- menuweight:20 -->
|
||||
|
||||
The `Event` API defines the structure of the events issued by Flux controllers.
|
||||
|
||||
Flux controllers use the [fluxcd/pkg/runtime/events](https://github.com/fluxcd/pkg/tree/main/runtime/events)
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
# Providers
|
||||
|
||||
<!-- menuweight:40 -->
|
||||
|
||||
The `Provider` API defines how events are encoded and where to send them.
|
||||
|
||||
## Example
|
||||
|
@ -107,14 +109,17 @@ The supported alerting providers are:
|
|||
| [Generic webhook](#generic-webhook) | `generic` |
|
||||
| [Generic webhook with HMAC](#generic-webhook-with-hmac) | `generic-hmac` |
|
||||
| [Azure Event Hub](#azure-event-hub) | `azureeventhub` |
|
||||
| [DataDog](#datadog) | `datadog` |
|
||||
| [Discord](#discord) | `discord` |
|
||||
| [GitHub dispatch](#github-dispatch) | `githubdispatch` |
|
||||
| [Google Chat](#google-chat) | `googlechat` |
|
||||
| [Google Pub/Sub](#google-pubsub) | `googlepubsub` |
|
||||
| [Grafana](#grafana) | `grafana` |
|
||||
| [Lark](#lark) | `lark` |
|
||||
| [Matrix](#matrix) | `matrix` |
|
||||
| [Microsoft Teams](#microsoft-teams) | `msteams` |
|
||||
| [Opsgenie](#opsgenie) | `opsgenie` |
|
||||
| [PagerDuty](#pagerduty) | `pagerduty` |
|
||||
| [Prometheus Alertmanager](#prometheus-alertmanager) | `alertmanager` |
|
||||
| [Rocket](#rocket) | `rocket` |
|
||||
| [Sentry](#sentry) | `sentry` |
|
||||
|
@ -124,13 +129,14 @@ The supported alerting providers are:
|
|||
|
||||
The supported providers for [Git commit status updates](#git-commit-status-updates) are:
|
||||
|
||||
| Provider | Type |
|
||||
|-------------------------------|---------------|
|
||||
| [Azure DevOps](#azure-devops) | `azuredevops` |
|
||||
| [Bitbucket](#bitbucket) | `bitbucket` |
|
||||
| [GitHub](#github) | `github` |
|
||||
| [GitLab](#gitlab) | `gitlab` |
|
||||
| [Gitea](#gitea) | `gitea` |
|
||||
| Provider | Type |
|
||||
| ------------------------------------------------| ----------------- |
|
||||
| [Azure DevOps](#azure-devops) | `azuredevops` |
|
||||
| [Bitbucket](#bitbucket) | `bitbucket` |
|
||||
| [BitbucketServer](#bitbucket-serverdata-center) | `bitbucketserver` |
|
||||
| [GitHub](#github) | `github` |
|
||||
| [GitLab](#gitlab) | `gitlab` |
|
||||
| [Gitea](#gitea) | `gitea` |
|
||||
|
||||
#### Alerting
|
||||
|
||||
|
@ -232,7 +238,7 @@ func verifySignature(signature string, payload, key []byte) error {
|
|||
case "sha512":
|
||||
newF = sha512.New
|
||||
default:
|
||||
return fmt.Errorf("unsupported signature algorithm %q", sigHdr[0])
|
||||
return fmt.Errorf("unsupported signature algorithm %q", sig[0])
|
||||
}
|
||||
|
||||
mac := hmac.New(newF, key)
|
||||
|
@ -241,22 +247,22 @@ func verifySignature(signature string, payload, key []byte) error {
|
|||
}
|
||||
|
||||
sum := fmt.Sprintf("%x", mac.Sum(nil))
|
||||
if sum != sig[0] {
|
||||
return fmt.Errorf("HMACs do not match: %#v != %#v", sum, sigHdr[0])
|
||||
if sum != sig[1] {
|
||||
return fmt.Errorf("HMACs do not match: %#v != %#v", sum, sig[1])
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func handleRequest(w http.ResponseWriter, r *http.Request) {
|
||||
// Require a X-Signature header
|
||||
if len(r.Header["X-Signature"])) == 0 {
|
||||
if len(r.Header["X-Signature"]) == 0 {
|
||||
http.Error(w, "missing X-Signature header", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Read the request body with a limit of 1MB
|
||||
lr := io.LimitReader(r.Body, 1<<20)
|
||||
body, err := ioutil.ReadAll(lr)
|
||||
body, err := io.ReadAll(lr)
|
||||
if err != nil {
|
||||
http.Error(w, "failed to read request body", http.StatusBadRequest)
|
||||
return
|
||||
|
@ -264,9 +270,9 @@ func handleRequest(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
// Verify signature using the same token as the Secret referenced in
|
||||
// Provider
|
||||
key := "<token>"
|
||||
key := []byte("<token>")
|
||||
if err := verifySignature(r.Header.Get("X-Signature"), body, key); err != nil {
|
||||
http.Error(w, fmt.Sprintf("failed to verify HMAC signature: %s", err.String()), http.StatusBadRequest)
|
||||
http.Error(w, fmt.Sprintf("failed to verify HMAC signature: %s", err.Error()), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -401,6 +407,62 @@ stringData:
|
|||
address: "https://xxx.webhook.office.com/..."
|
||||
```
|
||||
|
||||
##### DataDog
|
||||
|
||||
When `.spec.type` is set to `datadog`, the controller will send a payload for
|
||||
an [Event](events.md#event-structure) to the provided DataDog API [Address](#address).
|
||||
|
||||
The Event will be formatted into a [DataDog Event](https://docs.datadoghq.com/api/latest/events/#post-an-event) and sent to the
|
||||
API endpoint of the provided DataDog [Address](#address).
|
||||
|
||||
This Provider type supports the configuration of a [proxy URL](#https-proxy)
|
||||
and/or [TLS certificates](#tls-certificates).
|
||||
|
||||
The metadata of the Event is included in the DataDog event as extra tags.
|
||||
|
||||
###### DataDog example
|
||||
|
||||
To configure a Provider for DataDog, create a Secret with [the `token`](#token-example)
|
||||
set to a [DataDog API key](https://docs.datadoghq.com/account_management/api-app-keys/#api-keys)
|
||||
(not an application key!) and a `datadog` Provider with a [Secret reference](#secret-reference).
|
||||
|
||||
```yaml
|
||||
---
|
||||
apiVersion: notification.toolkit.fluxcd.io/v1beta2
|
||||
kind: Provider
|
||||
metadata:
|
||||
name: datadog
|
||||
namespace: default
|
||||
spec:
|
||||
type: datadog
|
||||
address: https://api.datadoghq.com # DataDog Site US1
|
||||
secretRef:
|
||||
name: datadog-secret
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: datadog-secret
|
||||
namespace: default
|
||||
stringData:
|
||||
token: <DataDog API Key>
|
||||
---
|
||||
apiVersion: notification.toolkit.fluxcd.io/v1beta2
|
||||
kind: Alert
|
||||
metadata:
|
||||
name: datadog-info
|
||||
namespace: default
|
||||
spec:
|
||||
eventSeverity: info
|
||||
eventSources:
|
||||
- kind: HelmRelease
|
||||
name: "*"
|
||||
providerRef:
|
||||
name: datadog
|
||||
eventMetadata:
|
||||
env: my-k8s-cluster # example of adding a custom `env` tag to the event
|
||||
```
|
||||
|
||||
##### Discord
|
||||
|
||||
When `.spec.type` is set to `discord`, the controller will send a payload for
|
||||
|
@ -501,8 +563,9 @@ The Event will be formatted into a message string, with the metadata attached
|
|||
as a list of key-value pairs.
|
||||
|
||||
The Provider's [Channel](#channel) is used to set the receiver of the message.
|
||||
This can be a unique identifier (`-1234567890`) for the target chat, or
|
||||
the username (`@username`) of the target channel.
|
||||
This can be a unique identifier (`-1234567890`) for the target chat,
|
||||
a unique identifier with the topic identifier (`-1234567890:1`) for the forum chat,
|
||||
or the username (`@username`) of the target channel.
|
||||
|
||||
This Provider type does not support the configuration of a [proxy URL](#https-proxy)
|
||||
or [TLS certificates](#tls-certificates).
|
||||
|
@ -524,7 +587,7 @@ metadata:
|
|||
spec:
|
||||
type: telegram
|
||||
address: https://api.telegram.org
|
||||
channel: "@fluxcd" # or "-1557265138" (channel id)
|
||||
channel: "@fluxcd" # or "-1557265138" (channel id) or "-1552289257:1" (forum chat id with topic id)
|
||||
secretRef:
|
||||
name: telegram-token
|
||||
```
|
||||
|
@ -669,6 +732,65 @@ stringData:
|
|||
address: https://chat.googleapis.com/v1/spaces/...
|
||||
```
|
||||
|
||||
##### Google Pub/Sub
|
||||
|
||||
When `.spec.type` is set to `googlepubsub`, the controller will publish the payload of
|
||||
an [Event](events.md#event-structure) on the Google Pub/Sub Topic ID provided in the
|
||||
[Channel](#channel) field, which must exist in the GCP Project ID provided in the
|
||||
[Address](#address) field.
|
||||
|
||||
This Provider type can optionally use the [Secret reference](#secret-reference) to
|
||||
authenticate on the Google Pub/Sub API by using [JSON credentials](https://cloud.google.com/iam/docs/service-account-creds#key-types).
|
||||
The credentials must be specified on [the `token`](#token-example) field of the Secret.
|
||||
|
||||
If no JSON credentials are specified, then the automatic authentication methods of
|
||||
the Google libraries will take place, and therefore methods like Workload Identity
|
||||
will be automatically attempted.
|
||||
|
||||
The Google identity effectively used for publishing messages must have
|
||||
[the required permissions](https://cloud.google.com/iam/docs/understanding-roles#pubsub.publisher)
|
||||
on the Pub/Sub Topic.
|
||||
|
||||
You can optionally add [attributes](https://cloud.google.com/pubsub/docs/samples/pubsub-publish-custom-attributes#pubsub_publish_custom_attributes-go)
|
||||
to the Pub/Sub message using a [`headers` key in the referenced Secret](#http-headers-example).
|
||||
|
||||
This Provider type does not support the configuration of a [proxy URL](#https-proxy)
|
||||
or [TLS certificates](#tls-certificates).
|
||||
|
||||
###### Google Pub/Sub with JSON Credentials and Custom Headers Example
|
||||
|
||||
To configure a Provider for Google Pub/Sub authenticating with JSON credentials and
|
||||
custom headers, create a Secret with [the `token`](#token-example) set to the
|
||||
necessary JSON credentials, [the `headers`](#http-headers-example) field set to a
|
||||
YAML string-to-string dictionary, and a `googlepubsub` Provider with the associated
|
||||
[Secret reference](#secret-reference).
|
||||
|
||||
```yaml
|
||||
---
|
||||
apiVersion: notification.toolkit.fluxcd.io/v1beta2
|
||||
kind: Provider
|
||||
metadata:
|
||||
name: googlepubsub-provider
|
||||
namespace: desired-namespace
|
||||
spec:
|
||||
type: googlepubsub
|
||||
address: <GCP Project ID>
|
||||
channel: <Pub/Sub Topic ID>
|
||||
secretRef:
|
||||
name: googlepubsub-provider-creds
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: googlepubsub-provider-creds
|
||||
namespace: desired-namespace
|
||||
stringData:
|
||||
token: <GCP JSON credentials>
|
||||
headers: |
|
||||
attr1-name: attr1-value
|
||||
attr2-name: attr2-value
|
||||
```
|
||||
|
||||
##### Opsgenie
|
||||
|
||||
When `.spec.type` is set to `opsgenie`, the controller will send a payload for
|
||||
|
@ -710,6 +832,64 @@ stringData:
|
|||
token: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
```
|
||||
|
||||
##### PagerDuty
|
||||
|
||||
When `.spec.type` is set to `pagerduty`, the controller will send a payload for
|
||||
an [Event](events.md#event-structure) to the provided PagerDuty [Address](#address).
|
||||
|
||||
The Event will be formatted into an [Event API v2](https://developer.pagerduty.com/api-reference/368ae3d938c9e-send-an-event-to-pager-duty) payload,
|
||||
triggering or resolving an incident depending on the event's `Severity`.
|
||||
|
||||
The provider will also send [Change Events](https://developer.pagerduty.com/api-reference/95db350959c37-send-change-events-to-the-pager-duty-events-api)
|
||||
for `info` level `Severity`, which will be displayed in the PagerDuty service's timeline to track changes.
|
||||
|
||||
This Provider type supports the configuration of a [proxy URL](#https-proxy)
|
||||
and [TLS certificates](#tls-certificates).
|
||||
|
||||
The [Channel](#channel) is used to set the routing key to send the event to the appropriate integration.
|
||||
|
||||
###### PagerDuty example
|
||||
|
||||
To configure a Provider for Pagerduty, create a `pagerduty` Provider,
|
||||
set `address` to the integration URL and `channel` set to
|
||||
the integration key (also known as a routing key) for your [service](https://support.pagerduty.com/docs/services-and-integrations#create-a-generic-events-api-integration)
|
||||
or [event orchestration](https://support.pagerduty.com/docs/event-orchestration).
|
||||
|
||||
When adding an integration for a service on PagerDuty, it is recommended to use `Events API v2` integration.
|
||||
|
||||
**Note**: PagerDuty does not support Change Events when sent to global integrations, such as event orchestration.
|
||||
|
||||
```yaml
|
||||
---
|
||||
apiVersion: notification.toolkit.fluxcd.io/v1beta2
|
||||
kind: Provider
|
||||
metadata:
|
||||
name: pagerduty
|
||||
namespace: default
|
||||
spec:
|
||||
type: pagerduty
|
||||
address: https://events.pagerduty.com
|
||||
channel: <integrationKey>
|
||||
```
|
||||
If you are sending to a service integration, it is recommended to set your Alert to filter to
|
||||
only those sources you want to trigger an incident for that service. For example:
|
||||
|
||||
```yaml
|
||||
---
|
||||
apiVersion: notification.toolkit.fluxcd.io/v1beta2
|
||||
kind: Alert
|
||||
metadata:
|
||||
name: my-service-pagerduty
|
||||
namespace: default
|
||||
spec:
|
||||
providerRef:
|
||||
name: pagerduty
|
||||
eventSources:
|
||||
- kind: HelmRelease
|
||||
name: my-service
|
||||
namespace: default
|
||||
```
|
||||
|
||||
##### Prometheus Alertmanager
|
||||
|
||||
When `.spec.type` is set to `alertmanager`, the controller will send a payload for
|
||||
|
@ -815,7 +995,10 @@ stringData:
|
|||
|
||||
### Address
|
||||
|
||||
`.spec.address` is an optional field that specifies the URL where the events are posted.
|
||||
`.spec.address` is an optional field that specifies the endpoint where the events are posted.
|
||||
The meaning of endpoint here depends on the specific Provider type being used.
|
||||
For the `generic` Provider for example this is an HTTP/S address.
|
||||
For other Provider types this could be a project ID or a namespace.
|
||||
|
||||
If the address contains sensitive information such as tokens or passwords, it is
|
||||
recommended to store the address in the Kubernetes secret referenced by `.spec.secretRef.name`.
|
||||
|
@ -890,8 +1073,8 @@ metadata:
|
|||
namespace: default
|
||||
stringData:
|
||||
headers: |
|
||||
Authorization: my-api-token
|
||||
X-Forwarded-Proto: https
|
||||
Authorization: my-api-token
|
||||
X-Forwarded-Proto: https
|
||||
```
|
||||
|
||||
#### Proxy auth example
|
||||
|
@ -914,11 +1097,12 @@ stringData:
|
|||
|
||||
`.spec.certSecretRef` is an optional field to specify a name reference to a
|
||||
Secret in the same namespace as the Provider, containing the TLS CA certificate.
|
||||
The secret must be of type `kubernetes.io/tls` or `Opaque`.
|
||||
|
||||
#### Example
|
||||
|
||||
To enable notification-controller to communicate with a provider API over HTTPS
|
||||
using a self-signed TLS certificate, set the `caFile` like so:
|
||||
using a self-signed TLS certificate, set the `ca.crt` like so:
|
||||
|
||||
```yaml
|
||||
---
|
||||
|
@ -938,11 +1122,16 @@ kind: Secret
|
|||
metadata:
|
||||
name: my-ca-crt
|
||||
namespace: default
|
||||
type: kubernetes.io/tls # or Opaque
|
||||
stringData:
|
||||
caFile: |
|
||||
ca.crt: |
|
||||
<--- CA Key --->
|
||||
```
|
||||
|
||||
**Warning:** Support for the `caFile` key has been
|
||||
deprecated. If you have any Secrets using this key,
|
||||
the controller will log a deprecation warning.
|
||||
|
||||
### HTTP/S proxy
|
||||
|
||||
`.spec.proxy` is an optional field to specify an HTTP/S proxy address.
|
||||
|
@ -1297,7 +1486,13 @@ kubectl create secret generic gitlab-token --from-literal=token=<GITLAB-TOKEN>
|
|||
When `.spec.type` is set to `gitea`, the referenced secret must contain a key called `token` with the value set to a
|
||||
[Gitea token](https://docs.gitea.io/en-us/api-usage/#generating-and-listing-api-tokens).
|
||||
|
||||
The token owner must have permissions to update the commit status for the Gitea repository specified in `.spec.address`.
|
||||
The token must have at least the `write:repository` permission for the provider to
|
||||
update the commit status for the Gitea repository specified in `.spec.address`.
|
||||
|
||||
{{% alert color="info" title="Gitea 1.20.0 & 1.20.1" %}}
|
||||
Due to a bug in Gitea 1.20.0 and 1.20.1, these versions require the additional
|
||||
`read:misc` scope to be applied to the token.
|
||||
{{% /alert %}}
|
||||
|
||||
You can create the secret with `kubectl` like this:
|
||||
|
||||
|
@ -1321,6 +1516,32 @@ You can create the secret with `kubectl` like this:
|
|||
kubectl create secret generic bitbucket-token --from-literal=token=<username>:<app-password>
|
||||
```
|
||||
|
||||
#### BitBucket Server/Data Center
|
||||
|
||||
When `.spec.type` is set to `bitbucketserver`, the following auth methods are available:
|
||||
|
||||
- Basic Authentication (username/password)
|
||||
- [HTTP access tokens](https://confluence.atlassian.com/bitbucketserver/http-access-tokens-939515499.html)
|
||||
|
||||
For Basic Authentication, the referenced secret must contain a `password` field. The `username` field can either come from the [`.spec.username` field of the Provider](https://fluxcd.io/flux/components/notification/providers/#username) or can be defined in the referenced secret.
|
||||
|
||||
You can create the secret with `kubectl` like this:
|
||||
|
||||
```shell
|
||||
kubectl create secret generic bb-server-username-password --from-literal=username=<username> --from-literal=password=<password>
|
||||
```
|
||||
|
||||
For HTTP access tokens, the secret can be created with `kubectl` like this:
|
||||
|
||||
```shell
|
||||
kubectl create secret generic bb-server-token --from-literal=token=<token>
|
||||
```
|
||||
|
||||
The HTTP access token must have `Repositories (Read/Write)` permission for
|
||||
the repository specified in `.spec.address`.
|
||||
|
||||
**NOTE:** Please provide HTTPS clone URL in the `address` field of this provider. SSH URLs are not supported by this provider type.
|
||||
|
||||
#### Azure DevOps
|
||||
|
||||
When `.spec.type` is set to `azuredevops`, the referenced secret must contain a key called `token` with the value set to a
|
||||
|
|
|
@ -613,7 +613,7 @@ spec:
|
|||
|
||||
### Events
|
||||
|
||||
`.spec.events` in an optional field to specify a list of webhook payload event
|
||||
`.spec.events` is an optional field to specify a list of webhook payload event
|
||||
types this Receiver should act on. If left empty, no filtering is applied and
|
||||
any (valid) payload is handled.
|
||||
|
||||
|
@ -629,7 +629,7 @@ called.
|
|||
|
||||
A resource entry contains the following fields:
|
||||
|
||||
- `apiVersion`: The Flux Custom Resource API group and version, such as
|
||||
- `apiVersion` (Optional): The Flux Custom Resource API group and version, such as
|
||||
`source.toolkit.fluxcd.io/v1beta2`.
|
||||
- `kind`: The Flux Custom Resource kind, supported values are `Bucket`,
|
||||
`GitRepository`, `Kustomization`, `HelmRelease`, `HelmChart`,
|
||||
|
@ -639,7 +639,6 @@ A resource entry contains the following fields:
|
|||
- `namespace` (Optional): The Flux Custom Resource `.metadata.namespace`.
|
||||
When not specified, the Receiver's `.metadata.namespace` is used instead.
|
||||
|
||||
|
||||
**Note:** Cross-namespace references [can be disabled for security
|
||||
reasons](#disabling-cross-namespace-selectors).
|
||||
|
||||
|
@ -669,7 +668,7 @@ stringData:
|
|||
|
||||
### Interval
|
||||
|
||||
`.spec.interval` is a required field with a default of ten minutes that specifies
|
||||
`.spec.interval` is an optional field with a default of ten minutes that specifies
|
||||
the time interval at which the controller reconciles the provider with its Secret
|
||||
reference.
|
||||
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
# notification.toolkit.fluxcd.io/v1beta3
|
||||
|
||||
This is the v1beta3 API specification for defining events handling.
|
||||
|
||||
## Specification
|
||||
|
||||
* [Alerts](alerts.md)
|
||||
* [Events](events.md)
|
||||
* [Providers](providers.md)
|
||||
|
||||
## Go Client
|
||||
|
||||
* [github.com/fluxcd/pkg/runtime/events](https://pkg.go.dev/github.com/fluxcd/pkg/runtime/events)
|
|
@ -0,0 +1,319 @@
|
|||
# Alerts
|
||||
|
||||
<!-- menuweight:10 -->
|
||||
|
||||
The `Alert` API defines how events are filtered by severity and involved object, and what provider to use for dispatching.
|
||||
|
||||
## Example
|
||||
|
||||
The following is an example of how to send alerts to Slack when Flux fails to reconcile the `flux-system` namespace.
|
||||
|
||||
```yaml
|
||||
---
|
||||
apiVersion: notification.toolkit.fluxcd.io/v1beta3
|
||||
kind: Provider
|
||||
metadata:
|
||||
name: slack-bot
|
||||
namespace: flux-system
|
||||
spec:
|
||||
type: slack
|
||||
channel: general
|
||||
address: https://slack.com/api/chat.postMessage
|
||||
secretRef:
|
||||
name: slack-bot-token
|
||||
---
|
||||
apiVersion: notification.toolkit.fluxcd.io/v1beta3
|
||||
kind: Alert
|
||||
metadata:
|
||||
name: slack
|
||||
namespace: flux-system
|
||||
spec:
|
||||
providerRef:
|
||||
name: slack-bot
|
||||
eventMetadata:
|
||||
summary: Cluster addons impacted
|
||||
env: prod
|
||||
cluster: my-cluster
|
||||
region: us-east-2
|
||||
eventSeverity: error
|
||||
eventSources:
|
||||
- kind: GitRepository
|
||||
name: '*'
|
||||
- kind: Kustomization
|
||||
name: '*'
|
||||
```
|
||||
|
||||
In the above example:
|
||||
|
||||
- A Provider named `slack-bot` is created, indicated by the
|
||||
`Provider.metadata.name` field.
|
||||
- An Alert named `slack` is created, indicated by the
|
||||
`Alert.metadata.name` field.
|
||||
- The Alert references the `slack-bot` provider, indicated by the
|
||||
`Alert.spec.providerRef` field.
|
||||
- The notification-controller starts listening for events sent for
|
||||
all GitRepositories and Kustomizations in the `flux-system` namespace.
|
||||
- When an event with severity `error` is received, the controller posts
|
||||
a message on Slack channel from `.spec.channel`,
|
||||
containing the metadata and the reconciliation error.
|
||||
|
||||
You can run this example by saving the manifests into `slack-alerts.yaml`.
|
||||
|
||||
1. First create a secret with the Slack bot token:
|
||||
|
||||
```sh
|
||||
kubectl -n flux-system create secret generic slack-bot-token --from-literal=token=xoxb-YOUR-TOKEN
|
||||
```
|
||||
|
||||
2. Apply the resources on the cluster:
|
||||
|
||||
```sh
|
||||
kubectl -n flux-system apply --server-side -f slack-alerts.yaml
|
||||
```
|
||||
|
||||
## Writing an Alert spec
|
||||
|
||||
As with all other Kubernetes config, an Alert needs `apiVersion`,
|
||||
`kind`, and `metadata` fields. The name of an Alert object must be a
|
||||
valid [DNS subdomain name](https://kubernetes.io/docs/concepts/overview/working-with-objects/names#dns-subdomain-names).
|
||||
|
||||
An Alert also needs a
|
||||
[`.spec` section](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#spec-and-status).
|
||||
|
||||
### Summary
|
||||
|
||||
`.spec.summary` is an optional field to specify a short description of the impact.
|
||||
|
||||
The summary max length can't be greater than 255 characters.
|
||||
|
||||
**Warning:** Support for `.spec.summary` has been deprecated and will be removed in
|
||||
Alert API v1 GA. If you have any Alerts using this field, the controller will log a
|
||||
deprecation warning. Please use [`.spec.eventMetadata.summary`](#event-metadata) or
|
||||
[object annotations](#event-metadata-from-object-annotations) for defining alert
|
||||
summary instead.
|
||||
|
||||
### Provider reference
|
||||
|
||||
`.spec.providerRef.name` is a required field to specify a name reference to a
|
||||
[Provider](providers.md) in the same namespace as the Alert.
|
||||
|
||||
### Event sources
|
||||
|
||||
`.spec.eventSources` is a required field to specify a list of references to
|
||||
Flux objects for which events are forwarded to the alert provider API.
|
||||
|
||||
To select events issued by Flux objects, each entry in the `.spec.eventSources` list
|
||||
must contain the following fields:
|
||||
|
||||
- `kind` is the Flux Custom Resource Kind such as GitRepository, HelmRelease, Kustomization, etc.
|
||||
- `name` is the Flux Custom Resource `.metadata.name`, or it can be set to the `*` wildcard.
|
||||
- `namespace` is the Flux Custom Resource `.metadata.namespace`.
|
||||
When not specified, the Alert `.metadata.namespace` is used instead.
|
||||
|
||||
#### Select objects by name
|
||||
|
||||
To select events issued by a single Flux object, set the `kind`, `name` and `namespace`:
|
||||
|
||||
```yaml
|
||||
eventSources:
|
||||
- kind: GitRepository
|
||||
name: webapp
|
||||
namespace: apps
|
||||
```
|
||||
|
||||
#### Select all objects in a namespace
|
||||
|
||||
The `*` wildcard can be used to select events issued by all Flux objects of a particular `kind` in a `namespace`:
|
||||
|
||||
```yaml
|
||||
eventSources:
|
||||
- kind: HelmRelease
|
||||
name: '*'
|
||||
namespace: apps
|
||||
```
|
||||
|
||||
#### Select objects by label
|
||||
|
||||
To select events issued by all Flux objects of a particular `kind` with specific `labels`:
|
||||
|
||||
```yaml
|
||||
eventSources:
|
||||
- kind: HelmRelease
|
||||
name: '*'
|
||||
namespace: apps
|
||||
matchLabels:
|
||||
team: app-dev
|
||||
```
|
||||
|
||||
#### Disable cross-namespace selectors
|
||||
|
||||
**Note:** On multi-tenant clusters, platform admins can disable cross-namespace references by
|
||||
starting the controller with the `--no-cross-namespace-refs=true` flag.
|
||||
When this flag is set, alerts can only refer to event sources in the same namespace as the alert object,
|
||||
preventing tenants from subscribing to another tenant's events.
|
||||
|
||||
### Event metadata
|
||||
|
||||
`.spec.eventMetadata` is an optional field for adding metadata to events dispatched by
|
||||
the controller. This can be used for enhancing the context of the event, e.g. with
|
||||
cluster-level information.
|
||||
|
||||
For all the event metadata sources and their precedence order, please refer to
|
||||
[Event metadata from object annotations](#event-metadata-from-object-annotations).
|
||||
|
||||
#### Example
|
||||
|
||||
Add metadata fields to successful `HelmRelease` events:
|
||||
|
||||
```yaml
|
||||
---
|
||||
apiVersion: notification.toolkit.fluxcd.io/v1beta3
|
||||
kind: Alert
|
||||
metadata:
|
||||
name: <name>
|
||||
spec:
|
||||
eventSources:
|
||||
- kind: HelmRelease
|
||||
name: '*'
|
||||
inclusionList:
|
||||
- ".*succeeded.*"
|
||||
eventMetadata:
|
||||
env: production
|
||||
cluster: my-cluster
|
||||
region: us-east-1
|
||||
```
|
||||
|
||||
### Event metadata from object annotations
|
||||
|
||||
Event metadata has four sources. They are listed below in order of precedence,
|
||||
from lowest to highest:
|
||||
|
||||
1. User-defined metadata on Flux objects, set with the `event.toolkit.fluxcd.io/`
|
||||
prefix in the keys of the object's `.metadata.annotations`.
|
||||
2. User-defined metadata on the Alert object, set with [`.spec.eventMetadata`](#event-metadata).
|
||||
3. User-defined summary on the Alert object, set with [`.spec.summary`](#summary) (deprecated, see docs).
|
||||
4. Controller-defined metadata, set with the `<controller group>.toolkit.fluxcd.io/`
|
||||
prefix in the metadata keys of the event payload.
|
||||
|
||||
If there are any metadata key conflicts between the sources, the higher
|
||||
precedence source will override the lower precedence source, and a warning
|
||||
log and Kubernetes event will be emitted.
|
||||
|
||||
#### Example
|
||||
|
||||
```yaml
|
||||
---
|
||||
apiVersion: notification.toolkit.fluxcd.io/v1beta3
|
||||
kind: Alert
|
||||
metadata:
|
||||
name: <name>
|
||||
spec:
|
||||
eventSources:
|
||||
- kind: HelmRelease
|
||||
name: '*'
|
||||
eventMetadata:
|
||||
env: production
|
||||
cluster: my-cluster
|
||||
region: us-east-1
|
||||
---
|
||||
apiVersion: helm.toolkit.fluxcd.io/v2
|
||||
kind: HelmRelease
|
||||
metadata:
|
||||
name: my-webapp
|
||||
annotations:
|
||||
event.toolkit.fluxcd.io/summary: "my-webapp impacted. Playbook: <URL to playbook>"
|
||||
event.toolkit.fluxcd.io/deploymentID: e076e315-5a48-41c3-81c8-8d8bdee7d74d
|
||||
spec:
|
||||
... # fields omitted for brevity
|
||||
```
|
||||
|
||||
In the above example, the event payload dispatched by the controller will look like this
|
||||
(most fields omitted for highlighting the metadata):
|
||||
|
||||
```json
|
||||
{
|
||||
"metadata": {
|
||||
"env": "production",
|
||||
"cluster": "my-cluster",
|
||||
"region": "us-east-1",
|
||||
"summary": "my-webapp impacted. Playbook: <URL to playbook>",
|
||||
"deploymentID": "e076e315-5a48-41c3-81c8-8d8bdee7d74d"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Event severity
|
||||
|
||||
`.spec.eventSeverity` is an optional field to filter events based on severity. When not specified, or
|
||||
when the value is set to `info`, all events are forwarded to the alert provider API, including errors.
|
||||
To receive alerts only on errors, set the field value to `error`.
|
||||
|
||||
### Event exclusion
|
||||
|
||||
`.spec.exclusionList` is an optional field to specify a list of regex expressions to filter
|
||||
events based on message content. The event will be excluded if the message matches at least
|
||||
one of the expressions in the list.
|
||||
|
||||
#### Example
|
||||
|
||||
Skip alerting if the message matches a [Go regex](https://golang.org/pkg/regexp/syntax)
|
||||
from the exclusion list:
|
||||
|
||||
```yaml
|
||||
---
|
||||
apiVersion: notification.toolkit.fluxcd.io/v1beta3
|
||||
kind: Alert
|
||||
metadata:
|
||||
name: <name>
|
||||
spec:
|
||||
eventSources:
|
||||
- kind: GitRepository
|
||||
name: '*'
|
||||
exclusionList:
|
||||
- "waiting.*socket"
|
||||
```
|
||||
|
||||
The above definition will not send alerts for transient Git clone errors like:
|
||||
|
||||
```text
|
||||
unable to clone 'ssh://git@ssh.dev.azure.com/v3/...', error: SSH could not read data: Error waiting on socket
|
||||
```
|
||||
|
||||
### Event inclusion
|
||||
|
||||
`.spec.inclusionList` is an optional field to specify a list of regex expressions to filter
|
||||
events based on message content. The event will be sent if the message matches at least one
|
||||
of the expressions in the list, and discarded otherwise. If the message matches one of the
|
||||
expressions in the inclusion list but also matches one of the expressions in the exclusion
|
||||
list, then the event is still discarded (exclusion is stronger than inclusion).
|
||||
|
||||
#### Example
|
||||
|
||||
Alert if the message matches a [Go regex](https://golang.org/pkg/regexp/syntax)
|
||||
from the inclusion list:
|
||||
|
||||
```yaml
|
||||
---
|
||||
apiVersion: notification.toolkit.fluxcd.io/v1beta3
|
||||
kind: Alert
|
||||
metadata:
|
||||
name: <name>
|
||||
spec:
|
||||
eventSources:
|
||||
- kind: HelmRelease
|
||||
name: '*'
|
||||
inclusionList:
|
||||
- ".*succeeded.*"
|
||||
exclusionList:
|
||||
- ".*uninstall.*"
|
||||
- ".*test.*"
|
||||
```
|
||||
|
||||
The above definition will send alerts for successful Helm installs, upgrades and rollbacks,
|
||||
but not uninstalls and tests.
|
||||
|
||||
### Suspend
|
||||
|
||||
`.spec.suspend` is an optional field to suspend the altering.
|
||||
When set to `true`, the controller will stop processing events.
|
||||
When the field is set to `false` or removed, it will resume.
|
|
@ -0,0 +1,64 @@
|
|||
# Events
|
||||
|
||||
<!-- menuweight:20 -->
|
||||
|
||||
The `Event` API defines the structure of the events issued by Flux controllers.
|
||||
|
||||
Flux controllers use the [fluxcd/pkg/runtime/events](https://github.com/fluxcd/pkg/tree/main/runtime/events)
|
||||
package to push events to the notification-controller API.
|
||||
|
||||
## Example
|
||||
|
||||
The following is an example of an event sent by kustomize-controller to report a reconciliation error.
|
||||
|
||||
```json
|
||||
{
|
||||
"involvedObject": {
|
||||
"apiVersion": "kustomize.toolkit.fluxcd.io/v1",
|
||||
"kind": "Kustomization",
|
||||
"name": "webapp",
|
||||
"namespace": "apps",
|
||||
"uid": "7d0cdc51-ddcf-4743-b223-83ca5c699632"
|
||||
},
|
||||
"metadata": {
|
||||
"kustomize.toolkit.fluxcd.io/revision": "main/731f7eaddfb6af01cb2173e18f0f75b0ba780ef1"
|
||||
},
|
||||
"severity":"error",
|
||||
"reason": "ValidationFailed",
|
||||
"message":"service/apps/webapp validation error: spec.type: Unsupported value: Ingress",
|
||||
"reportingController":"kustomize-controller",
|
||||
"timestamp":"2022-10-28T07:26:19Z"
|
||||
}
|
||||
```
|
||||
|
||||
In the above example:
|
||||
|
||||
- An event is issued by kustomize-controller for a specific object, indicated in the
|
||||
`involvedObject` field.
|
||||
- The notification-controller receives the event and finds the [alerts](alerts.md)
|
||||
that match the `involvedObject` and `severity` values.
|
||||
- For all matching alerts, the controller posts the `message` and the source revision
|
||||
extracted from `metadata` to the alert provider API.
|
||||
|
||||
## Event structure
|
||||
|
||||
The Go type that defines the event structure can be found in the
|
||||
[fluxcd/pkg/apis/event/v1beta1](https://github.com/fluxcd/pkg/blob/main/apis/event/v1beta1/event.go)
|
||||
package.
|
||||
|
||||
## Rate limiting
|
||||
|
||||
Events received by notification-controller are subject to rate limiting to reduce the
|
||||
amount of duplicate alerts sent to external systems like Slack, Sentry, etc.
|
||||
|
||||
Events are rate limited based on `involvedObject.name`, `involvedObject.namespace`,
|
||||
`involvedObject.kind`, `message`, and `metadata`.
|
||||
The interval of the rate limit is set by default to `5m` but can be configured
|
||||
with the `--rate-limit-interval` controller flag.
|
||||
|
||||
The event server exposes HTTP request metrics to track the amount of rate limited events.
|
||||
The following promql will get the rate at which requests are rate limited:
|
||||
|
||||
```
|
||||
rate(gotk_event_http_request_duration_seconds_count{code="429"}[30s])
|
||||
```
|
File diff suppressed because it is too large
Load Diff
277
go.mod
277
go.mod
|
@ -1,54 +1,76 @@
|
|||
module github.com/fluxcd/notification-controller
|
||||
|
||||
go 1.18
|
||||
go 1.24.0
|
||||
|
||||
replace github.com/fluxcd/notification-controller/api => ./api
|
||||
|
||||
require (
|
||||
code.gitea.io/sdk/gitea v0.15.1
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1
|
||||
github.com/Azure/azure-amqp-common-go/v4 v4.0.0
|
||||
github.com/Azure/azure-event-hubs-go/v3 v3.4.0
|
||||
github.com/containrrr/shoutrrr v0.7.1
|
||||
github.com/fluxcd/notification-controller/api v0.32.1
|
||||
github.com/fluxcd/pkg/apis/event v0.4.0
|
||||
github.com/fluxcd/pkg/apis/meta v0.19.0
|
||||
github.com/fluxcd/pkg/git v0.10.0
|
||||
github.com/fluxcd/pkg/masktoken v0.2.0
|
||||
github.com/fluxcd/pkg/runtime v0.29.0
|
||||
github.com/fluxcd/pkg/ssa v0.24.1
|
||||
github.com/getsentry/sentry-go v0.18.0
|
||||
github.com/go-logr/logr v1.2.3
|
||||
github.com/google/go-github/v41 v41.0.0
|
||||
github.com/hashicorp/go-retryablehttp v0.7.2
|
||||
github.com/ktrysmt/go-bitbucket v0.9.55
|
||||
cloud.google.com/go/pubsub v1.49.0
|
||||
code.gitea.io/sdk/gitea v0.21.0
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6
|
||||
github.com/Azure/azure-amqp-common-go/v4 v4.2.0
|
||||
github.com/Azure/azure-event-hubs-go/v3 v3.6.2
|
||||
github.com/DataDog/datadog-api-client-go/v2 v2.42.0
|
||||
github.com/PagerDuty/go-pagerduty v1.8.0
|
||||
github.com/cdevents/sdk-go v0.4.1
|
||||
github.com/chainguard-dev/git-urls v1.0.2
|
||||
github.com/elazarl/goproxy v1.7.2
|
||||
github.com/fluxcd/cli-utils v0.36.0-flux.14
|
||||
github.com/fluxcd/notification-controller/api v1.6.0
|
||||
github.com/fluxcd/pkg/apis/event v0.18.0
|
||||
github.com/fluxcd/pkg/apis/meta v1.17.0
|
||||
github.com/fluxcd/pkg/auth v0.21.0
|
||||
github.com/fluxcd/pkg/cache v0.10.0
|
||||
github.com/fluxcd/pkg/git v0.34.0
|
||||
github.com/fluxcd/pkg/masktoken v0.7.0
|
||||
github.com/fluxcd/pkg/runtime v0.69.0
|
||||
github.com/fluxcd/pkg/ssa v0.51.0
|
||||
github.com/fluxcd/pkg/ssh v0.20.0
|
||||
github.com/getsentry/sentry-go v0.34.1
|
||||
github.com/go-logr/logr v1.4.3
|
||||
github.com/google/cel-go v0.25.0
|
||||
github.com/google/go-github/v64 v64.0.0
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/hashicorp/go-retryablehttp v0.7.8
|
||||
github.com/ktrysmt/go-bitbucket v0.9.86
|
||||
github.com/microsoft/azure-devops-go-api/azuredevops/v6 v6.0.1
|
||||
github.com/onsi/gomega v1.27.2
|
||||
github.com/sethvargo/go-limiter v0.7.2
|
||||
github.com/slok/go-http-metrics v0.10.0
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/stretchr/testify v1.8.2
|
||||
github.com/whilp/git-urls v1.0.0
|
||||
github.com/xanzy/go-gitlab v0.80.2
|
||||
golang.org/x/oauth2 v0.5.0
|
||||
k8s.io/api v0.26.1
|
||||
k8s.io/apimachinery v0.26.1
|
||||
k8s.io/client-go v0.26.1
|
||||
sigs.k8s.io/cli-utils v0.34.0
|
||||
sigs.k8s.io/controller-runtime v0.14.4
|
||||
sigs.k8s.io/yaml v1.3.0
|
||||
github.com/nats-io/nats.go v1.43.0
|
||||
github.com/onsi/gomega v1.37.0
|
||||
github.com/sethvargo/go-limiter v1.0.0
|
||||
github.com/slok/go-http-metrics v0.13.0
|
||||
github.com/spf13/pflag v1.0.6
|
||||
github.com/stretchr/testify v1.10.0
|
||||
gitlab.com/gitlab-org/api/client-go v0.134.0
|
||||
golang.org/x/oauth2 v0.30.0
|
||||
golang.org/x/text v0.27.0
|
||||
google.golang.org/api v0.241.0
|
||||
k8s.io/api v0.33.2
|
||||
k8s.io/apimachinery v0.33.2
|
||||
k8s.io/client-go v0.33.2
|
||||
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397
|
||||
sigs.k8s.io/controller-runtime v0.21.0
|
||||
sigs.k8s.io/yaml v1.5.0
|
||||
)
|
||||
|
||||
// Fix CVE-2022-28948
|
||||
replace gopkg.in/yaml.v3 => gopkg.in/yaml.v3 v3.0.1
|
||||
|
||||
// Fix CVE-2022-1996 (for v2, Go Modules incompatible)
|
||||
replace github.com/emicklei/go-restful => github.com/emicklei/go-restful v2.16.0+incompatible
|
||||
|
||||
require (
|
||||
cel.dev/expr v0.23.1 // indirect
|
||||
cloud.google.com/go v0.120.0 // indirect
|
||||
cloud.google.com/go/auth v0.16.2 // indirect
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.7.0 // indirect
|
||||
cloud.google.com/go/iam v1.5.2 // indirect
|
||||
github.com/42wim/httpsig v1.2.2 // indirect
|
||||
github.com/Azure/azure-sdk-for-go v65.0.0+incompatible // indirect
|
||||
github.com/Azure/go-amqp v0.18.0 // indirect
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.9.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/containers/azcontainerregistry v0.2.3 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice v1.0.0 // indirect
|
||||
github.com/Azure/go-amqp v1.3.0 // indirect
|
||||
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
|
||||
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
|
||||
github.com/Azure/go-autorest/autorest v0.11.28 // indirect
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.21 // indirect
|
||||
|
@ -57,95 +79,140 @@ require (
|
|||
github.com/Azure/go-autorest/autorest/validation v0.3.1 // indirect
|
||||
github.com/Azure/go-autorest/logger v0.2.1 // indirect
|
||||
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 // indirect
|
||||
github.com/DataDog/zstd v1.5.2 // indirect
|
||||
github.com/MakeNowJust/heredoc v1.0.0 // indirect
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230201104953-d1d05f4e2bfb // indirect
|
||||
github.com/ProtonMail/go-crypto v1.3.0 // indirect
|
||||
github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/blang/semver/v4 v4.0.0 // indirect
|
||||
github.com/bradleyfalzon/ghinstallation/v2 v2.16.0 // indirect
|
||||
github.com/carapace-sh/carapace-shlex v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/chai2010/gettext-go v1.0.2 // indirect
|
||||
github.com/cloudflare/circl v1.3.2 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.2.3 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/cloudevents/sdk-go/v2 v2.15.2 // indirect
|
||||
github.com/cloudflare/circl v1.6.1 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.4.1 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/davidmz/go-pageant v1.0.2 // indirect
|
||||
github.com/devigned/tab v0.1.1 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.10.0 // indirect
|
||||
github.com/evanphx/json-patch v5.6.0+incompatible // indirect
|
||||
github.com/evanphx/json-patch/v5 v5.6.0 // indirect
|
||||
github.com/docker/cli v28.2.2+incompatible // indirect
|
||||
github.com/docker/docker-credential-helpers v0.9.3 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.12.2 // indirect
|
||||
github.com/evanphx/json-patch/v5 v5.9.11 // indirect
|
||||
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect
|
||||
github.com/fatih/color v1.13.0 // indirect
|
||||
github.com/fluxcd/pkg/apis/acl v0.1.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||
github.com/go-errors/errors v1.4.2 // indirect
|
||||
github.com/go-logr/zapr v1.2.3 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||
github.com/go-openapi/jsonreference v0.20.0 // indirect
|
||||
github.com/go-openapi/swag v0.22.3 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/fluxcd/pkg/apis/acl v0.7.0 // indirect
|
||||
github.com/fluxcd/pkg/apis/kustomize v1.11.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.8.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.5 // indirect
|
||||
github.com/go-errors/errors v1.5.1 // indirect
|
||||
github.com/go-fed/httpsig v1.1.0 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-logr/zapr v1.3.0 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.21.1 // indirect
|
||||
github.com/go-openapi/jsonreference v0.21.0 // indirect
|
||||
github.com/go-openapi/swag v0.23.1 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.22.0 // indirect
|
||||
github.com/goccy/go-json v0.10.3 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.4.2 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/google/btree v1.1.2 // indirect
|
||||
github.com/google/gnostic v0.6.9 // indirect
|
||||
github.com/google/go-cmp v0.5.9 // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.5.2 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
|
||||
github.com/google/btree v1.1.3 // indirect
|
||||
github.com/google/gnostic-models v0.7.0 // indirect
|
||||
github.com/google/go-cmp v0.7.0 // indirect
|
||||
github.com/google/go-containerregistry v0.20.6 // indirect
|
||||
github.com/google/go-github/v72 v72.0.0 // indirect
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/google/s2a-go v0.1.9 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.14.2 // indirect
|
||||
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect
|
||||
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-version v1.6.0 // indirect
|
||||
github.com/imdario/mergo v0.3.13 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.1 // indirect
|
||||
github.com/hashicorp/go-version v1.7.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/joho/godotenv v1.5.1 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/jpillora/backoff v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/compress v1.18.0 // indirect
|
||||
github.com/kylelemons/godebug v1.1.0 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.16 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||
github.com/mailru/easyjson v0.9.0 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/moby/spdystream v0.2.0 // indirect
|
||||
github.com/moby/term v0.0.0-20221105221325-4eb28fa6025c // indirect
|
||||
github.com/moby/spdystream v0.5.0 // indirect
|
||||
github.com/moby/term v0.5.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
|
||||
github.com/nats-io/nkeys v0.4.11 // indirect
|
||||
github.com/nats-io/nuid v1.0.1 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/package-url/packageurl-go v0.1.1 // indirect
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
|
||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_golang v1.14.0 // indirect
|
||||
github.com/prometheus/client_model v0.3.0 // indirect
|
||||
github.com/prometheus/common v0.37.0 // indirect
|
||||
github.com/prometheus/procfs v0.8.0 // indirect
|
||||
github.com/rogpeppe/go-internal v1.8.0 // indirect
|
||||
github.com/russross/blackfriday v1.6.0 // indirect
|
||||
github.com/spf13/cobra v1.6.1 // indirect
|
||||
github.com/xlab/treeprint v1.1.0 // indirect
|
||||
go.starlark.net v0.0.0-20221028183056-acb66ad56dd2 // indirect
|
||||
go.uber.org/atomic v1.10.0 // indirect
|
||||
go.uber.org/multierr v1.8.0 // indirect
|
||||
go.uber.org/zap v1.24.0 // indirect
|
||||
golang.org/x/crypto v0.6.0 // indirect
|
||||
golang.org/x/net v0.7.0 // indirect
|
||||
golang.org/x/sys v0.5.0 // indirect
|
||||
golang.org/x/term v0.5.0 // indirect
|
||||
golang.org/x/text v0.7.0 // indirect
|
||||
golang.org/x/time v0.3.0 // indirect
|
||||
gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/protobuf v1.28.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/prometheus/client_golang v1.22.0 // indirect
|
||||
github.com/prometheus/client_model v0.6.2 // indirect
|
||||
github.com/prometheus/common v0.65.0 // indirect
|
||||
github.com/prometheus/procfs v0.17.0 // indirect
|
||||
github.com/rogpeppe/go-internal v1.14.1 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1 // indirect
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/spf13/cobra v1.9.1 // indirect
|
||||
github.com/stoewer/go-strcase v1.3.0 // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
github.com/xlab/treeprint v1.2.0 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
|
||||
go.opentelemetry.io/otel v1.37.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.37.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.37.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.27.0 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.2 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||
golang.org/x/crypto v0.39.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e // indirect
|
||||
golang.org/x/mod v0.25.0 // indirect
|
||||
golang.org/x/net v0.41.0 // indirect
|
||||
golang.org/x/sync v0.16.0 // indirect
|
||||
golang.org/x/sys v0.34.0 // indirect
|
||||
golang.org/x/term v0.33.0 // indirect
|
||||
golang.org/x/time v0.12.0 // indirect
|
||||
gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250505200425-f936aa4a68b2 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect
|
||||
google.golang.org/grpc v1.73.0 // indirect
|
||||
google.golang.org/protobuf v1.36.6 // indirect
|
||||
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/apiextensions-apiserver v0.26.1 // indirect
|
||||
k8s.io/cli-runtime v0.25.4 // indirect
|
||||
k8s.io/component-base v0.26.1 // indirect
|
||||
k8s.io/klog/v2 v2.90.0 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20221110221610-a28e98eb7c70 // indirect
|
||||
k8s.io/kubectl v0.25.4 // indirect
|
||||
k8s.io/utils v0.0.0-20221128185143-99ec85e7a448 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect
|
||||
sigs.k8s.io/kustomize/api v0.12.1 // indirect
|
||||
sigs.k8s.io/kustomize/kyaml v0.13.9 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
|
||||
k8s.io/apiextensions-apiserver v0.33.2 // indirect
|
||||
k8s.io/cli-runtime v0.33.2 // indirect
|
||||
k8s.io/component-base v0.33.2 // indirect
|
||||
k8s.io/klog/v2 v2.130.1 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20250701173324-9bd5c66d9911 // indirect
|
||||
k8s.io/kubectl v0.33.2 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
|
||||
sigs.k8s.io/kustomize/api v0.20.0 // indirect
|
||||
sigs.k8s.io/kustomize/kyaml v0.20.0 // indirect
|
||||
sigs.k8s.io/randfill v1.0.0 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.7.0 // indirect
|
||||
)
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
"externalPackages": [
|
||||
{
|
||||
"typeMatchPrefix": "^k8s\\.io/apimachinery/pkg/apis/meta/v1\\.Duration$",
|
||||
"docsURLTemplate": "https://godoc.org/k8s.io/apimachinery/pkg/apis/meta/v1#Duration"
|
||||
"docsURLTemplate": "https://pkg.go.dev/k8s.io/apimachinery/pkg/apis/meta/v1#Duration"
|
||||
},
|
||||
{
|
||||
"typeMatchPrefix": "^k8s\\.io/apiextensions-apiserver/pkg/apis/apiextensions/v1\\.JSON$",
|
||||
|
@ -21,15 +21,19 @@
|
|||
},
|
||||
{
|
||||
"typeMatchPrefix": "^github.com/fluxcd/pkg/runtime/dependency\\.CrossNamespaceDependencyReference$",
|
||||
"docsURLTemplate": "https://godoc.org/github.com/fluxcd/pkg/runtime/dependency#CrossNamespaceDependencyReference"
|
||||
"docsURLTemplate": "https://pkg.go.dev/github.com/fluxcd/pkg/runtime/dependency#CrossNamespaceDependencyReference"
|
||||
},
|
||||
{
|
||||
"typeMatchPrefix": "^github.com/fluxcd/pkg/apis/kustomize",
|
||||
"docsURLTemplate": "https://godoc.org/github.com/fluxcd/pkg/apis/kustomize#{{ .TypeIdentifier }}"
|
||||
"docsURLTemplate": "https://pkg.go.dev/github.com/fluxcd/pkg/apis/kustomize#{{ .TypeIdentifier }}"
|
||||
},
|
||||
{
|
||||
"typeMatchPrefix": "^github.com/fluxcd/pkg/apis/meta",
|
||||
"docsURLTemplate": "https://godoc.org/github.com/fluxcd/pkg/apis/meta#{{ .TypeIdentifier }}"
|
||||
"docsURLTemplate": "https://pkg.go.dev/github.com/fluxcd/pkg/apis/meta#{{ .TypeIdentifier }}"
|
||||
},
|
||||
{
|
||||
"typeMatchPrefix": "^github.com/fluxcd/notification-controller/api/v1",
|
||||
"docsURLTemplate": "https://pkg.go.dev/github.com/fluxcd/notification-controller/api/v1#{{ .TypeIdentifier }}"
|
||||
}
|
||||
],
|
||||
"typeDisplayNamePrefixOverrides": {
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
{{ define "packages" }}
|
||||
<h1>Notification API reference</h1>
|
||||
<h1>Notification API reference
|
||||
{{- with (index .packages 0) -}}
|
||||
{{ with (index .GoPackages 0 ) -}}
|
||||
{{ printf " %s" .Name -}}
|
||||
{{ end -}}
|
||||
{{ end }}</h1>
|
||||
|
||||
{{ with .packages}}
|
||||
<p>Packages:</p>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2022 The Flux authors
|
||||
Copyright 2023 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
Copyright 2023 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
kuberecorder "k8s.io/client-go/tools/record"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/builder"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||
|
||||
apiv1 "github.com/fluxcd/notification-controller/api/v1"
|
||||
apiv1beta3 "github.com/fluxcd/notification-controller/api/v1beta3"
|
||||
"github.com/fluxcd/pkg/runtime/patch"
|
||||
)
|
||||
|
||||
// +kubebuilder:rbac:groups=notification.toolkit.fluxcd.io,resources=alerts,verbs=get;list;watch;create;update;patch;delete
|
||||
// +kubebuilder:rbac:groups="",resources=events,verbs=create;patch
|
||||
|
||||
// AlertReconciler reconciles an Alert object to migrate it to static Alert.
|
||||
type AlertReconciler struct {
|
||||
client.Client
|
||||
kuberecorder.EventRecorder
|
||||
|
||||
ControllerName string
|
||||
}
|
||||
|
||||
func (r *AlertReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
||||
return ctrl.NewControllerManagedBy(mgr).
|
||||
For(&apiv1beta3.Alert{}, builder.WithPredicates(finalizerPredicate{})).
|
||||
Complete(r)
|
||||
}
|
||||
|
||||
func (r *AlertReconciler) Reconcile(ctx context.Context, req ctrl.Request) (result ctrl.Result, retErr error) {
|
||||
log := ctrl.LoggerFrom(ctx)
|
||||
|
||||
obj := &apiv1beta3.Alert{}
|
||||
if err := r.Get(ctx, req.NamespacedName, obj); err != nil {
|
||||
return ctrl.Result{}, client.IgnoreNotFound(err)
|
||||
}
|
||||
|
||||
// Early return if no migration is needed.
|
||||
if !controllerutil.ContainsFinalizer(obj, apiv1.NotificationFinalizer) {
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
// Examine if the object is under deletion.
|
||||
var delete bool
|
||||
if !obj.ObjectMeta.DeletionTimestamp.IsZero() {
|
||||
delete = true
|
||||
}
|
||||
|
||||
// Skip if it's suspend and not being deleted.
|
||||
if obj.Spec.Suspend && !delete {
|
||||
log.Info("reconciliation is suspended for this object")
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
patcher, err := patch.NewHelper(obj, r.Client)
|
||||
if err != nil {
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err := patcher.Patch(ctx, obj); err != nil {
|
||||
retErr = err
|
||||
}
|
||||
}()
|
||||
|
||||
// Remove the notification-controller finalizer.
|
||||
controllerutil.RemoveFinalizer(obj, apiv1.NotificationFinalizer)
|
||||
|
||||
log.Info("removed finalizer from Alert to migrate to static Alert")
|
||||
r.Event(obj, corev1.EventTypeNormal, "Migration", "removed finalizer from Alert to migrate to static Alert")
|
||||
|
||||
return
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
Copyright 2023 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package controller
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
"github.com/fluxcd/pkg/runtime/patch"
|
||||
. "github.com/onsi/gomega"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||
|
||||
apiv1 "github.com/fluxcd/notification-controller/api/v1"
|
||||
apiv1beta3 "github.com/fluxcd/notification-controller/api/v1beta3"
|
||||
)
|
||||
|
||||
func TestAlertReconciler(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
|
||||
timeout := 10 * time.Second
|
||||
|
||||
testns, err := testEnv.CreateNamespace(ctx, "alert-test")
|
||||
g.Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
t.Cleanup(func() {
|
||||
g.Expect(testEnv.Cleanup(ctx, testns)).ToNot(HaveOccurred())
|
||||
})
|
||||
|
||||
alert := &apiv1beta3.Alert{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: fmt.Sprintf("alert-%s", randStringRunes(5)),
|
||||
Namespace: testns.Name,
|
||||
},
|
||||
}
|
||||
alertKey := client.ObjectKeyFromObject(alert)
|
||||
|
||||
// Remove finalizer at create.
|
||||
|
||||
alert.ObjectMeta.Finalizers = append(alert.ObjectMeta.Finalizers, "foo.bar", apiv1.NotificationFinalizer)
|
||||
alert.Spec = apiv1beta3.AlertSpec{
|
||||
ProviderRef: meta.LocalObjectReference{Name: "foo-provider"},
|
||||
EventSources: []apiv1.CrossNamespaceObjectReference{},
|
||||
}
|
||||
g.Expect(testEnv.Create(ctx, alert)).ToNot(HaveOccurred())
|
||||
|
||||
g.Eventually(func() bool {
|
||||
_ = testEnv.Get(ctx, alertKey, alert)
|
||||
return !controllerutil.ContainsFinalizer(alert, apiv1.NotificationFinalizer)
|
||||
}, timeout, time.Second).Should(BeTrue())
|
||||
|
||||
// Remove finalizer at update.
|
||||
|
||||
patchHelper, err := patch.NewHelper(alert, testEnv.Client)
|
||||
g.Expect(err).ToNot(HaveOccurred())
|
||||
alert.ObjectMeta.Finalizers = append(alert.ObjectMeta.Finalizers, apiv1.NotificationFinalizer)
|
||||
g.Expect(patchHelper.Patch(ctx, alert)).ToNot(HaveOccurred())
|
||||
|
||||
g.Eventually(func() bool {
|
||||
_ = testEnv.Get(ctx, alertKey, alert)
|
||||
return !controllerutil.ContainsFinalizer(alert, apiv1.NotificationFinalizer)
|
||||
}, timeout, time.Second).Should(BeTrue())
|
||||
|
||||
// Remove finalizer at delete.
|
||||
|
||||
patchHelper, err = patch.NewHelper(alert, testEnv.Client)
|
||||
g.Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
// Suspend the alert to prevent finalizer from getting removed.
|
||||
// Ensure only flux finalizer is set to allow the object to be garbage
|
||||
// collected at the end.
|
||||
// NOTE: Suspending and updating finalizers are done separately here as
|
||||
// doing them in a single patch results in flaky test where the finalizer
|
||||
// update doesn't gets registered with the kube-apiserver, resulting in
|
||||
// timeout waiting for finalizer to appear on the object below.
|
||||
alert.Spec.Suspend = true
|
||||
g.Expect(patchHelper.Patch(ctx, alert)).ToNot(HaveOccurred())
|
||||
g.Eventually(func() bool {
|
||||
_ = k8sClient.Get(ctx, alertKey, alert)
|
||||
return alert.Spec.Suspend == true
|
||||
}, timeout).Should(BeTrue())
|
||||
|
||||
patchHelper, err = patch.NewHelper(alert, testEnv.Client)
|
||||
g.Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
// Add finalizer and verify that finalizer exists on the object using a live
|
||||
// client.
|
||||
alert.ObjectMeta.Finalizers = []string{apiv1.NotificationFinalizer}
|
||||
g.Expect(patchHelper.Patch(ctx, alert)).ToNot(HaveOccurred())
|
||||
g.Eventually(func() bool {
|
||||
_ = k8sClient.Get(ctx, alertKey, alert)
|
||||
return controllerutil.ContainsFinalizer(alert, apiv1.NotificationFinalizer)
|
||||
}, timeout).Should(BeTrue())
|
||||
|
||||
// Delete the object and verify.
|
||||
g.Expect(testEnv.Delete(ctx, alert)).ToNot(HaveOccurred())
|
||||
g.Eventually(func() bool {
|
||||
if err := testEnv.Get(ctx, alertKey, alert); err != nil {
|
||||
return apierrors.IsNotFound(err)
|
||||
}
|
||||
return false
|
||||
}, timeout).Should(BeTrue())
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
Copyright 2023 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package controller
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||
"sigs.k8s.io/controller-runtime/pkg/event"
|
||||
"sigs.k8s.io/controller-runtime/pkg/predicate"
|
||||
|
||||
apiv1 "github.com/fluxcd/notification-controller/api/v1"
|
||||
)
|
||||
|
||||
// finalizerPredicate implements predicate functions to allow events for objects
|
||||
// that have the flux finalizer.
|
||||
type finalizerPredicate struct {
|
||||
predicate.Funcs
|
||||
}
|
||||
|
||||
// Create allows events for objects with flux finalizer that have beed created.
|
||||
func (finalizerPredicate) Create(e event.CreateEvent) bool {
|
||||
return controllerutil.ContainsFinalizer(e.Object, apiv1.NotificationFinalizer)
|
||||
}
|
||||
|
||||
// Update allows events for objects with flux finalizer that have been updated.
|
||||
func (finalizerPredicate) Update(e event.UpdateEvent) bool {
|
||||
if e.ObjectNew == nil {
|
||||
return false
|
||||
}
|
||||
return controllerutil.ContainsFinalizer(e.ObjectNew, apiv1.NotificationFinalizer)
|
||||
}
|
||||
|
||||
// Delete allows events for objects with flux finalizer that have been marked
|
||||
// for deletion.
|
||||
func (finalizerPredicate) Delete(e event.DeleteEvent) bool {
|
||||
return controllerutil.ContainsFinalizer(e.Object, apiv1.NotificationFinalizer)
|
||||
}
|
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
Copyright 2023 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package controller
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "github.com/onsi/gomega"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/event"
|
||||
|
||||
apiv1 "github.com/fluxcd/notification-controller/api/v1"
|
||||
apiv1beta3 "github.com/fluxcd/notification-controller/api/v1beta3"
|
||||
)
|
||||
|
||||
func getAlertWithFinalizers(finalizers []string) *apiv1beta3.Alert {
|
||||
return &apiv1beta3.Alert{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Finalizers: finalizers,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestFinalizerPredicateCreate(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
object client.Object
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
name: "no finalizer",
|
||||
object: getAlertWithFinalizers([]string{}),
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "no flux finalizer",
|
||||
object: getAlertWithFinalizers([]string{"foo.bar", "baz.bar"}),
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "has flux finalizer",
|
||||
object: getAlertWithFinalizers([]string{"foo.bar", apiv1.NotificationFinalizer, "baz.bar"}),
|
||||
want: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
|
||||
event := event.CreateEvent{
|
||||
Object: tt.object,
|
||||
}
|
||||
|
||||
mp := finalizerPredicate{}
|
||||
g.Expect(mp.Create(event)).To(Equal(tt.want))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFinalizerPredicateDelete(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
object client.Object
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
name: "no finalizer",
|
||||
object: getAlertWithFinalizers([]string{}),
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "no flux finalizer",
|
||||
object: getAlertWithFinalizers([]string{"foo.bar", "baz.bar"}),
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "has flux finalizer",
|
||||
object: getAlertWithFinalizers([]string{"foo.bar", apiv1.NotificationFinalizer, "baz.bar"}),
|
||||
want: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
|
||||
event := event.DeleteEvent{
|
||||
Object: tt.object,
|
||||
}
|
||||
|
||||
mp := finalizerPredicate{}
|
||||
g.Expect(mp.Delete(event)).To(Equal(tt.want))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFinalizerPredicateUpdate(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
oldObject client.Object
|
||||
newObject client.Object
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
name: "no new object",
|
||||
oldObject: getAlertWithFinalizers([]string{apiv1.NotificationFinalizer}),
|
||||
newObject: nil,
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "no old object, new object without flux finalizer",
|
||||
oldObject: nil,
|
||||
newObject: getAlertWithFinalizers([]string{"foo.bar"}),
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "no old object, new object with flux finalizer",
|
||||
oldObject: nil,
|
||||
newObject: getAlertWithFinalizers([]string{apiv1.NotificationFinalizer}),
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "old and new objects with flux finalizer",
|
||||
oldObject: getAlertWithFinalizers([]string{"foo.bar", apiv1.NotificationFinalizer, "baz.bar"}),
|
||||
newObject: getAlertWithFinalizers([]string{"foo.bar", apiv1.NotificationFinalizer, "baz.bar"}),
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "old object with flux finalizer, new object without",
|
||||
oldObject: getAlertWithFinalizers([]string{"foo.bar", apiv1.NotificationFinalizer, "baz.bar"}),
|
||||
newObject: getAlertWithFinalizers([]string{"foo.bar", "baz.bar"}),
|
||||
want: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
|
||||
event := event.UpdateEvent{
|
||||
ObjectOld: tt.oldObject,
|
||||
ObjectNew: tt.newObject,
|
||||
}
|
||||
|
||||
mp := finalizerPredicate{}
|
||||
g.Expect(mp.Update(event)).To(Equal(tt.want))
|
||||
})
|
||||
}
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
Copyright 2023 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
kuberecorder "k8s.io/client-go/tools/record"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/builder"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||
|
||||
apiv1 "github.com/fluxcd/notification-controller/api/v1"
|
||||
apiv1beta3 "github.com/fluxcd/notification-controller/api/v1beta3"
|
||||
"github.com/fluxcd/pkg/cache"
|
||||
"github.com/fluxcd/pkg/runtime/patch"
|
||||
|
||||
"github.com/fluxcd/notification-controller/internal/notifier"
|
||||
)
|
||||
|
||||
// +kubebuilder:rbac:groups=notification.toolkit.fluxcd.io,resources=providers,verbs=get;list;watch;create;update;patch;delete
|
||||
// +kubebuilder:rbac:groups="",resources=secrets,verbs=get;list;watch
|
||||
// +kubebuilder:rbac:groups="",resources=events,verbs=create;patch
|
||||
// +kubebuilder:rbac:groups="",resources=serviceaccounts/token,verbs=create
|
||||
|
||||
// ProviderReconciler reconciles a Provider object to migrate it to static
|
||||
// Provider.
|
||||
type ProviderReconciler struct {
|
||||
client.Client
|
||||
kuberecorder.EventRecorder
|
||||
|
||||
TokenCache *cache.TokenCache
|
||||
}
|
||||
|
||||
func (r *ProviderReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
||||
return ctrl.NewControllerManagedBy(mgr).
|
||||
For(&apiv1beta3.Provider{}, builder.WithPredicates(providerPredicate{})).
|
||||
Complete(r)
|
||||
}
|
||||
|
||||
func (r *ProviderReconciler) Reconcile(ctx context.Context, req ctrl.Request) (result ctrl.Result, retErr error) {
|
||||
obj := &apiv1beta3.Provider{}
|
||||
if err := r.Get(ctx, req.NamespacedName, obj); err != nil {
|
||||
return ctrl.Result{}, client.IgnoreNotFound(err)
|
||||
}
|
||||
|
||||
patcher, err := patch.NewHelper(obj, r.Client)
|
||||
if err != nil {
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err := patcher.Patch(ctx, obj); err != nil {
|
||||
retErr = err
|
||||
}
|
||||
}()
|
||||
|
||||
// Examine if the object is under deletion.
|
||||
if !obj.ObjectMeta.DeletionTimestamp.IsZero() {
|
||||
return r.reconcileDelete(obj)
|
||||
}
|
||||
|
||||
// Add finalizer if it doesn't exist.
|
||||
if !controllerutil.ContainsFinalizer(obj, apiv1.NotificationFinalizer) {
|
||||
controllerutil.AddFinalizer(obj, apiv1.NotificationFinalizer)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// reconcileDelete handles the deletion of the object.
|
||||
// It cleans up the caches and removes the finalizer.
|
||||
func (r *ProviderReconciler) reconcileDelete(obj *apiv1beta3.Provider) (ctrl.Result, error) {
|
||||
// Remove our finalizer from the list
|
||||
controllerutil.RemoveFinalizer(obj, apiv1.NotificationFinalizer)
|
||||
|
||||
// Cleanup caches.
|
||||
r.TokenCache.DeleteEventsForObject(apiv1beta3.ProviderKind,
|
||||
obj.GetName(), obj.GetNamespace(), notifier.OperationPost)
|
||||
|
||||
// Stop reconciliation as the object is being deleted
|
||||
return ctrl.Result{}, nil
|
||||
}
|
|
@ -0,0 +1,169 @@
|
|||
/*
|
||||
Copyright 2023 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package controller
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/fluxcd/pkg/runtime/patch"
|
||||
. "github.com/onsi/gomega"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||
|
||||
apiv1 "github.com/fluxcd/notification-controller/api/v1"
|
||||
apiv1beta3 "github.com/fluxcd/notification-controller/api/v1beta3"
|
||||
)
|
||||
|
||||
func TestProviderReconciler(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
|
||||
timeout := 10 * time.Second
|
||||
|
||||
testns, err := testEnv.CreateNamespace(ctx, "provider-test")
|
||||
g.Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
t.Cleanup(func() {
|
||||
g.Expect(testEnv.Cleanup(ctx, testns)).ToNot(HaveOccurred())
|
||||
})
|
||||
|
||||
provider := &apiv1beta3.Provider{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: fmt.Sprintf("provider-%s", randStringRunes(5)),
|
||||
Namespace: testns.Name,
|
||||
},
|
||||
}
|
||||
providerKey := client.ObjectKeyFromObject(provider)
|
||||
|
||||
// Create without finalizer.
|
||||
provider.Spec = apiv1beta3.ProviderSpec{
|
||||
Type: "generic",
|
||||
}
|
||||
g.Expect(testEnv.Create(ctx, provider)).ToNot(HaveOccurred())
|
||||
|
||||
// Should eventually have finalizer.
|
||||
g.Eventually(func() bool {
|
||||
_ = testEnv.Get(ctx, providerKey, provider)
|
||||
return controllerutil.ContainsFinalizer(provider, apiv1.NotificationFinalizer)
|
||||
}, timeout, time.Second).Should(BeTrue())
|
||||
|
||||
// Remove finalizer.
|
||||
patchHelper, err := patch.NewHelper(provider, testEnv.Client)
|
||||
g.Expect(err).ToNot(HaveOccurred())
|
||||
controllerutil.RemoveFinalizer(provider, apiv1.NotificationFinalizer)
|
||||
g.Expect(patchHelper.Patch(ctx, provider)).ToNot(HaveOccurred())
|
||||
|
||||
// Should eventually have finalizer again.
|
||||
g.Eventually(func() bool {
|
||||
_ = testEnv.Get(ctx, providerKey, provider)
|
||||
return controllerutil.ContainsFinalizer(provider, apiv1.NotificationFinalizer)
|
||||
}, timeout, time.Second).Should(BeTrue())
|
||||
|
||||
// Delete the object and verify.
|
||||
g.Expect(testEnv.Delete(ctx, provider)).ToNot(HaveOccurred())
|
||||
g.Eventually(func() bool {
|
||||
if err := testEnv.Get(ctx, providerKey, provider); err != nil {
|
||||
return apierrors.IsNotFound(err)
|
||||
}
|
||||
return false
|
||||
}, timeout).Should(BeTrue())
|
||||
}
|
||||
|
||||
func TestProviderReconciler_APIServerValidation(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
providerType string
|
||||
commitStatusExpr string
|
||||
err string
|
||||
}{
|
||||
{
|
||||
name: "github provider types can create providers with commitStatusExpr",
|
||||
providerType: "github",
|
||||
commitStatusExpr: "event.metadata.namespace + '/' + event.metadata.name + '/' + provider.metadata.uid",
|
||||
},
|
||||
{
|
||||
name: "gitlab provider types can create providers with commitStatusExpr",
|
||||
providerType: "gitlab",
|
||||
commitStatusExpr: "event.metadata.namespace + '/' + event.metadata.name + '/' + provider.metadata.uid",
|
||||
},
|
||||
{
|
||||
name: "gitea provider types can create providers with commitStatusExpr",
|
||||
providerType: "gitea",
|
||||
commitStatusExpr: "event.metadata.namespace + '/' + event.metadata.name + '/' + provider.metadata.uid",
|
||||
},
|
||||
{
|
||||
name: "bitbucketserver provider types can create providers with commitStatusExpr",
|
||||
providerType: "bitbucketserver",
|
||||
commitStatusExpr: "event.metadata.namespace + '/' + event.metadata.name + '/' + provider.metadata.uid",
|
||||
},
|
||||
{
|
||||
name: "bitbucket provider types can create providers with commitStatusExpr",
|
||||
providerType: "bitbucket",
|
||||
commitStatusExpr: "event.metadata.namespace + '/' + event.metadata.name + '/' + provider.metadata.uid",
|
||||
},
|
||||
{
|
||||
name: "azuredevops provider types can create providers with commitStatusExpr",
|
||||
providerType: "azuredevops",
|
||||
commitStatusExpr: "event.metadata.namespace + '/' + event.metadata.name + '/' + provider.metadata.uid",
|
||||
},
|
||||
{
|
||||
name: "unsupported provider types cannot create providers with commitStatusExpr",
|
||||
providerType: "slack",
|
||||
commitStatusExpr: "event.metadata.namespace + '/' + event.metadata.name + '/' + provider.metadata.uid",
|
||||
err: "spec.commitStatusExpr is only supported for the 'github', 'gitlab', 'gitea', 'bitbucketserver', 'bitbucket', 'azuredevops' provider types",
|
||||
},
|
||||
{
|
||||
name: "github provider types can create providers without commitStatusExpr",
|
||||
providerType: "github",
|
||||
commitStatusExpr: "",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
|
||||
obj := &apiv1beta3.Provider{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
GenerateName: "provider-reconcile-",
|
||||
Namespace: "default",
|
||||
},
|
||||
Spec: apiv1beta3.ProviderSpec{
|
||||
Type: tt.providerType,
|
||||
CommitStatusExpr: tt.commitStatusExpr,
|
||||
},
|
||||
}
|
||||
|
||||
err := testEnv.Create(ctx, obj)
|
||||
if err == nil {
|
||||
defer func() {
|
||||
err := testEnv.Delete(ctx, obj)
|
||||
g.Expect(err).ToNot(HaveOccurred())
|
||||
}()
|
||||
}
|
||||
|
||||
if tt.err != "" {
|
||||
g.Expect(err.Error()).To(ContainSubstring(tt.err))
|
||||
} else {
|
||||
g.Expect(err).NotTo(HaveOccurred())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
Copyright 2025 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package controller
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||
"sigs.k8s.io/controller-runtime/pkg/event"
|
||||
|
||||
apiv1 "github.com/fluxcd/notification-controller/api/v1"
|
||||
apiv1beta3 "github.com/fluxcd/notification-controller/api/v1beta3"
|
||||
)
|
||||
|
||||
// providerPredicate implements predicate functions for the Provider API.
|
||||
type providerPredicate struct{}
|
||||
|
||||
func (providerPredicate) Create(e event.CreateEvent) bool {
|
||||
return !controllerutil.ContainsFinalizer(e.Object, apiv1.NotificationFinalizer)
|
||||
}
|
||||
|
||||
func (providerPredicate) Update(e event.UpdateEvent) bool {
|
||||
if e.ObjectNew == nil {
|
||||
return false
|
||||
}
|
||||
return !controllerutil.ContainsFinalizer(e.ObjectNew, apiv1.NotificationFinalizer) ||
|
||||
!e.ObjectNew.(*apiv1beta3.Provider).ObjectMeta.DeletionTimestamp.IsZero()
|
||||
}
|
||||
|
||||
func (providerPredicate) Delete(e event.DeleteEvent) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (providerPredicate) Generic(e event.GenericEvent) bool {
|
||||
return !controllerutil.ContainsFinalizer(e.Object, apiv1.NotificationFinalizer)
|
||||
}
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package controllers
|
||||
package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
@ -26,13 +26,14 @@ import (
|
|||
"k8s.io/apimachinery/pkg/types"
|
||||
kerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||
kuberecorder "k8s.io/client-go/tools/record"
|
||||
"k8s.io/client-go/util/workqueue"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/builder"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||
"sigs.k8s.io/controller-runtime/pkg/predicate"
|
||||
"sigs.k8s.io/controller-runtime/pkg/ratelimiter"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
"github.com/fluxcd/pkg/runtime/conditions"
|
||||
|
@ -40,7 +41,8 @@ import (
|
|||
"github.com/fluxcd/pkg/runtime/patch"
|
||||
"github.com/fluxcd/pkg/runtime/predicates"
|
||||
|
||||
apiv1 "github.com/fluxcd/notification-controller/api/v1beta2"
|
||||
apiv1 "github.com/fluxcd/notification-controller/api/v1"
|
||||
"github.com/fluxcd/notification-controller/internal/server"
|
||||
)
|
||||
|
||||
// ReceiverReconciler reconciles a Receiver object
|
||||
|
@ -53,8 +55,7 @@ type ReceiverReconciler struct {
|
|||
}
|
||||
|
||||
type ReceiverReconcilerOptions struct {
|
||||
MaxConcurrentReconciles int
|
||||
RateLimiter ratelimiter.RateLimiter
|
||||
RateLimiter workqueue.TypedRateLimiter[reconcile.Request]
|
||||
}
|
||||
|
||||
func (r *ReceiverReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
||||
|
@ -62,15 +63,18 @@ func (r *ReceiverReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
|||
}
|
||||
|
||||
func (r *ReceiverReconciler) SetupWithManagerAndOptions(mgr ctrl.Manager, opts ReceiverReconcilerOptions) error {
|
||||
recoverPanic := true
|
||||
// This index is used to list Receivers by their webhook path after the receiver server
|
||||
// gets a request.
|
||||
if err := mgr.GetFieldIndexer().IndexField(context.Background(), &apiv1.Receiver{},
|
||||
server.WebhookPathIndexKey, server.IndexReceiverWebhookPath); err != nil {
|
||||
return err
|
||||
}
|
||||
return ctrl.NewControllerManagedBy(mgr).
|
||||
For(&apiv1.Receiver{}, builder.WithPredicates(
|
||||
predicate.Or(predicate.GenerationChangedPredicate{}, predicates.ReconcileRequestedPredicate{}),
|
||||
)).
|
||||
WithOptions(controller.Options{
|
||||
MaxConcurrentReconciles: opts.MaxConcurrentReconciles,
|
||||
RateLimiter: opts.RateLimiter,
|
||||
RecoverPanic: &recoverPanic,
|
||||
RateLimiter: opts.RateLimiter,
|
||||
}).
|
||||
Complete(r)
|
||||
}
|
||||
|
@ -109,9 +113,7 @@ func (r *ReceiverReconciler) Reconcile(ctx context.Context, req ctrl.Request) (r
|
|||
}
|
||||
|
||||
// Record Prometheus metrics.
|
||||
r.Metrics.RecordReadiness(ctx, obj)
|
||||
r.Metrics.RecordDuration(ctx, obj, reconcileStart)
|
||||
r.Metrics.RecordSuspend(ctx, obj, obj.Spec.Suspend)
|
||||
|
||||
// Emit warning event if the reconciliation failed.
|
||||
if retErr != nil {
|
||||
|
@ -126,18 +128,22 @@ func (r *ReceiverReconciler) Reconcile(ctx context.Context, req ctrl.Request) (r
|
|||
}
|
||||
}()
|
||||
|
||||
if !controllerutil.ContainsFinalizer(obj, apiv1.NotificationFinalizer) {
|
||||
controllerutil.AddFinalizer(obj, apiv1.NotificationFinalizer)
|
||||
result = ctrl.Result{Requeue: true}
|
||||
return
|
||||
}
|
||||
|
||||
if !obj.ObjectMeta.DeletionTimestamp.IsZero() {
|
||||
controllerutil.RemoveFinalizer(obj, apiv1.NotificationFinalizer)
|
||||
result = ctrl.Result{}
|
||||
return
|
||||
}
|
||||
|
||||
// Add finalizer first if not exist to avoid the race condition
|
||||
// between init and delete.
|
||||
// Note: Finalizers in general can only be added when the deletionTimestamp
|
||||
// is not set.
|
||||
if !controllerutil.ContainsFinalizer(obj, apiv1.NotificationFinalizer) {
|
||||
controllerutil.AddFinalizer(obj, apiv1.NotificationFinalizer)
|
||||
result = ctrl.Result{Requeue: true}
|
||||
return
|
||||
}
|
||||
|
||||
// Return early if the object is suspended.
|
||||
if obj.Spec.Suspend {
|
||||
log.Info("Reconciliation is suspended for this object")
|
||||
|
@ -150,27 +156,40 @@ func (r *ReceiverReconciler) Reconcile(ctx context.Context, req ctrl.Request) (r
|
|||
// reconcile steps through the actual reconciliation tasks for the object, it returns early on the first step that
|
||||
// produces an error.
|
||||
func (r *ReceiverReconciler) reconcile(ctx context.Context, obj *apiv1.Receiver) (ctrl.Result, error) {
|
||||
log := ctrl.LoggerFrom(ctx)
|
||||
|
||||
if filter := obj.Spec.ResourceFilter; filter != "" {
|
||||
if err := server.ValidateResourceFilter(filter); err != nil {
|
||||
const msg = "Reconciliation failed terminally due to configuration error"
|
||||
errMsg := fmt.Sprintf("%s: %v", msg, err)
|
||||
conditions.MarkFalse(obj, meta.ReadyCondition, meta.InvalidCELExpressionReason, "%s", errMsg)
|
||||
conditions.MarkStalled(obj, meta.InvalidCELExpressionReason, "%s", errMsg)
|
||||
obj.Status.ObservedGeneration = obj.Generation
|
||||
log.Error(err, msg)
|
||||
r.Event(obj, corev1.EventTypeWarning, meta.InvalidCELExpressionReason, errMsg)
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Mark the resource as under reconciliation.
|
||||
conditions.MarkReconciling(obj, meta.ProgressingReason, "Reconciliation in progress")
|
||||
|
||||
token, err := r.token(ctx, obj)
|
||||
if err != nil {
|
||||
conditions.MarkFalse(obj, meta.ReadyCondition, apiv1.TokenNotFoundReason, err.Error())
|
||||
obj.Status.URL = ""
|
||||
conditions.MarkFalse(obj, meta.ReadyCondition, apiv1.TokenNotFoundReason, "%s", err)
|
||||
obj.Status.WebhookPath = ""
|
||||
return ctrl.Result{Requeue: true}, err
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
|
||||
webhookPath := obj.GetWebhookPath(token)
|
||||
msg := fmt.Sprintf("Receiver initialized for path: %s", webhookPath)
|
||||
|
||||
// Mark the resource as ready and set the webhook path in status.
|
||||
conditions.MarkTrue(obj, meta.ReadyCondition, meta.SucceededReason, msg)
|
||||
conditions.MarkTrue(obj, meta.ReadyCondition, meta.SucceededReason, "%s", msg)
|
||||
|
||||
if obj.Status.WebhookPath != webhookPath {
|
||||
obj.Status.URL = webhookPath
|
||||
obj.Status.WebhookPath = webhookPath
|
||||
ctrl.LoggerFrom(ctx).Info(msg)
|
||||
log.Info(msg)
|
||||
}
|
||||
|
||||
return ctrl.Result{RequeueAfter: obj.GetInterval()}, nil
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package controllers
|
||||
package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
@ -31,6 +31,8 @@ import (
|
|||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/client-go/tools/record"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
||||
|
@ -39,10 +41,47 @@ import (
|
|||
"github.com/fluxcd/pkg/runtime/conditions"
|
||||
"github.com/fluxcd/pkg/ssa"
|
||||
|
||||
apiv1 "github.com/fluxcd/notification-controller/api/v1beta2"
|
||||
apiv1 "github.com/fluxcd/notification-controller/api/v1"
|
||||
"github.com/fluxcd/notification-controller/internal/server"
|
||||
)
|
||||
|
||||
func TestReceiverReconciler_deleteBeforeFinalizer(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
|
||||
namespaceName := "receiver-" + randStringRunes(5)
|
||||
namespace := &corev1.Namespace{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: namespaceName},
|
||||
}
|
||||
g.Expect(k8sClient.Create(ctx, namespace)).ToNot(HaveOccurred())
|
||||
t.Cleanup(func() {
|
||||
g.Expect(k8sClient.Delete(ctx, namespace)).NotTo(HaveOccurred())
|
||||
})
|
||||
|
||||
receiver := &apiv1.Receiver{}
|
||||
receiver.Name = "test-receiver"
|
||||
receiver.Namespace = namespaceName
|
||||
receiver.Spec = apiv1.ReceiverSpec{
|
||||
Type: "github",
|
||||
Resources: []apiv1.CrossNamespaceObjectReference{
|
||||
{Kind: "Bucket", Name: "Foo"},
|
||||
},
|
||||
SecretRef: meta.LocalObjectReference{Name: "foo-secret"},
|
||||
}
|
||||
// Add a test finalizer to prevent the object from getting deleted.
|
||||
receiver.SetFinalizers([]string{"test-finalizer"})
|
||||
g.Expect(k8sClient.Create(ctx, receiver)).NotTo(HaveOccurred())
|
||||
// Add deletion timestamp by deleting the object.
|
||||
g.Expect(k8sClient.Delete(ctx, receiver)).NotTo(HaveOccurred())
|
||||
|
||||
r := &ReceiverReconciler{
|
||||
Client: k8sClient,
|
||||
EventRecorder: record.NewFakeRecorder(32),
|
||||
}
|
||||
// NOTE: Only a real API server responds with an error in this scenario.
|
||||
_, err := r.Reconcile(ctx, ctrl.Request{NamespacedName: client.ObjectKeyFromObject(receiver)})
|
||||
g.Expect(err).NotTo(HaveOccurred())
|
||||
}
|
||||
|
||||
func TestReceiverReconciler_Reconcile(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
|
||||
|
@ -102,6 +141,46 @@ func TestReceiverReconciler_Reconcile(t *testing.T) {
|
|||
|
||||
g.Expect(conditions.Has(resultR, meta.ReconcilingCondition)).To(BeFalse())
|
||||
g.Expect(controllerutil.ContainsFinalizer(resultR, apiv1.NotificationFinalizer)).To(BeTrue())
|
||||
g.Expect(resultR.Spec.Interval.Duration).To(BeIdenticalTo(10 * time.Minute))
|
||||
})
|
||||
|
||||
t.Run("fails with invalid CEL resource filter", func(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
g.Expect(k8sClient.Get(context.Background(), client.ObjectKeyFromObject(receiver), resultR)).To(Succeed())
|
||||
|
||||
// Incomplete CEL expression
|
||||
patch := []byte(`{"spec":{"resourceFilter":"has(res.metadata.annotations"}}`)
|
||||
g.Expect(k8sClient.Patch(context.Background(), resultR, client.RawPatch(types.MergePatchType, patch))).To(Succeed())
|
||||
|
||||
g.Eventually(func() bool {
|
||||
_ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(receiver), resultR)
|
||||
return !conditions.IsReady(resultR)
|
||||
}, timeout, time.Second).Should(BeTrue())
|
||||
|
||||
g.Expect(resultR.Status.ObservedGeneration).To(Equal(resultR.Generation))
|
||||
|
||||
g.Expect(conditions.GetReason(resultR, meta.ReadyCondition)).To(BeIdenticalTo(meta.InvalidCELExpressionReason))
|
||||
g.Expect(conditions.GetMessage(resultR, meta.ReadyCondition)).To(ContainSubstring("annotations"))
|
||||
|
||||
g.Expect(conditions.Has(resultR, meta.StalledCondition)).To(BeTrue())
|
||||
g.Expect(conditions.GetReason(resultR, meta.StalledCondition)).To(BeIdenticalTo(meta.InvalidCELExpressionReason))
|
||||
g.Expect(conditions.GetObservedGeneration(resultR, meta.StalledCondition)).To(BeIdenticalTo(resultR.Generation))
|
||||
})
|
||||
|
||||
t.Run("recovers when the CEL expression is valid", func(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
// Incomplete CEL expression
|
||||
patch := []byte(`{"spec":{"resourceFilter":"has(res.metadata.annotations)"}}`)
|
||||
g.Expect(k8sClient.Patch(context.Background(), resultR, client.RawPatch(types.MergePatchType, patch))).To(Succeed())
|
||||
|
||||
g.Eventually(func() bool {
|
||||
_ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(receiver), resultR)
|
||||
return conditions.IsReady(resultR)
|
||||
}, timeout, time.Second).Should(BeTrue())
|
||||
|
||||
g.Expect(conditions.GetObservedGeneration(resultR, meta.ReadyCondition)).To(BeIdenticalTo(resultR.Generation))
|
||||
g.Expect(resultR.Status.ObservedGeneration).To(BeIdenticalTo(resultR.Generation))
|
||||
g.Expect(conditions.Has(resultR, meta.ReconcilingCondition)).To(BeFalse())
|
||||
})
|
||||
|
||||
t.Run("fails with secret not found error", func(t *testing.T) {
|
||||
|
@ -197,7 +276,9 @@ func TestReceiverReconciler_EventHandler(t *testing.T) {
|
|||
timeout := 30 * time.Second
|
||||
resultR := &apiv1.Receiver{}
|
||||
|
||||
receiverServer := server.NewReceiverServer("127.0.0.1:56788", logf.Log, k8sClient)
|
||||
// Use the client from the manager as the server handler needs to list objects from the cache
|
||||
// which the "live" k8s client does not have access to.
|
||||
receiverServer := server.NewReceiverServer("127.0.0.1:56788", logf.Log, testEnv.GetClient(), true, true)
|
||||
receiverMdlw := middleware.New(middleware.Config{
|
||||
Recorder: prommetrics.NewRecorder(prommetrics.Config{
|
||||
Prefix: "gotk_receiver",
|
||||
|
@ -276,7 +357,6 @@ func TestReceiverReconciler_EventHandler(t *testing.T) {
|
|||
return conditions.IsReady(resultR)
|
||||
}, timeout, time.Second).Should(BeTrue())
|
||||
|
||||
g.Expect(resultR.Status.URL).To(BeIdenticalTo(address))
|
||||
g.Expect(resultR.Status.WebhookPath).To(BeIdenticalTo(address))
|
||||
g.Expect(conditions.GetMessage(resultR, meta.ReadyCondition)).To(ContainSubstring(address))
|
||||
})
|
||||
|
@ -295,7 +375,6 @@ func TestReceiverReconciler_EventHandler(t *testing.T) {
|
|||
}, timeout, time.Second).Should(BeTrue())
|
||||
|
||||
g.Expect(conditions.IsReady(resultR))
|
||||
g.Expect(resultR.Status.URL).To(BeIdenticalTo(address))
|
||||
g.Expect(resultR.Status.WebhookPath).To(BeIdenticalTo(address))
|
||||
})
|
||||
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package controllers
|
||||
package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
@ -31,16 +31,20 @@ import (
|
|||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
"sigs.k8s.io/cli-utils/pkg/kstatus/polling"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
|
||||
|
||||
"github.com/fluxcd/cli-utils/pkg/kstatus/polling"
|
||||
runtimeclient "github.com/fluxcd/pkg/runtime/client"
|
||||
"github.com/fluxcd/pkg/runtime/controller"
|
||||
"github.com/fluxcd/pkg/runtime/metrics"
|
||||
"github.com/fluxcd/pkg/runtime/testenv"
|
||||
"github.com/fluxcd/pkg/ssa"
|
||||
ssautil "github.com/fluxcd/pkg/ssa/utils"
|
||||
|
||||
apiv1 "github.com/fluxcd/notification-controller/api/v1beta2"
|
||||
apiv1 "github.com/fluxcd/notification-controller/api/v1"
|
||||
apiv1b2 "github.com/fluxcd/notification-controller/api/v1beta2"
|
||||
apiv1b3 "github.com/fluxcd/notification-controller/api/v1beta3"
|
||||
// +kubebuilder:scaffold:imports
|
||||
)
|
||||
|
||||
|
@ -54,9 +58,11 @@ var (
|
|||
func TestMain(m *testing.M) {
|
||||
var err error
|
||||
utilruntime.Must(apiv1.AddToScheme(scheme.Scheme))
|
||||
utilruntime.Must(apiv1b2.AddToScheme(scheme.Scheme))
|
||||
utilruntime.Must(apiv1b3.AddToScheme(scheme.Scheme))
|
||||
|
||||
testEnv = testenv.New(testenv.WithCRDPath(
|
||||
filepath.Join("..", "config", "crd", "bases"),
|
||||
filepath.Join("..", "..", "config", "crd", "bases"),
|
||||
))
|
||||
|
||||
k8sClient, err = client.New(testEnv.Config, client.Options{Scheme: scheme.Scheme})
|
||||
|
@ -65,27 +71,20 @@ func TestMain(m *testing.M) {
|
|||
}
|
||||
|
||||
controllerName := "notification-controller"
|
||||
testMetricsH := controller.MustMakeMetrics(testEnv)
|
||||
testMetricsH := controller.NewMetrics(testEnv, metrics.MustMakeRecorder(), apiv1.NotificationFinalizer)
|
||||
|
||||
if err := (&AlertReconciler{
|
||||
Client: testEnv,
|
||||
Metrics: testMetricsH,
|
||||
ControllerName: controllerName,
|
||||
EventRecorder: testEnv.GetEventRecorderFor(controllerName),
|
||||
}).SetupWithManagerAndOptions(testEnv, AlertReconcilerOptions{
|
||||
RateLimiter: controller.GetDefaultRateLimiter(),
|
||||
}); err != nil {
|
||||
panic(fmt.Sprintf("Failed to start AlerReconciler: %v", err))
|
||||
}).SetupWithManager(testEnv); err != nil {
|
||||
panic(fmt.Sprintf("Failed to start AlertReconciler: %v", err))
|
||||
}
|
||||
|
||||
if err := (&ProviderReconciler{
|
||||
Client: testEnv,
|
||||
Metrics: testMetricsH,
|
||||
ControllerName: controllerName,
|
||||
EventRecorder: testEnv.GetEventRecorderFor(controllerName),
|
||||
}).SetupWithManagerAndOptions(testEnv, ProviderReconcilerOptions{
|
||||
RateLimiter: controller.GetDefaultRateLimiter(),
|
||||
}); err != nil {
|
||||
Client: testEnv,
|
||||
EventRecorder: testEnv.GetEventRecorderFor(controllerName),
|
||||
}).SetupWithManager(testEnv); err != nil {
|
||||
panic(fmt.Sprintf("Failed to start ProviderReconciler: %v", err))
|
||||
}
|
||||
|
||||
|
@ -108,7 +107,7 @@ func TestMain(m *testing.M) {
|
|||
}()
|
||||
<-testEnv.Manager.Elected()
|
||||
|
||||
restMapper, err := apiutil.NewDynamicRESTMapper(testEnv.Config)
|
||||
restMapper, err := runtimeclient.NewDynamicRESTMapper(testEnv.Config)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("Failed to create restmapper: %v", restMapper))
|
||||
}
|
||||
|
@ -156,7 +155,7 @@ func readManifest(manifest, namespace string) (*unstructured.Unstructured, error
|
|||
}
|
||||
yml := fmt.Sprintf(string(data), namespace)
|
||||
|
||||
object, err := ssa.ReadObject(strings.NewReader(yml))
|
||||
object, err := ssautil.ReadObject(strings.NewReader(yml))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
apiVersion: source.toolkit.fluxcd.io/v1beta1
|
||||
apiVersion: source.toolkit.fluxcd.io/v1
|
||||
kind: GitRepository
|
||||
metadata:
|
||||
name: podinfo-two
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
apiVersion: source.toolkit.fluxcd.io/v1beta1
|
||||
apiVersion: source.toolkit.fluxcd.io/v1
|
||||
kind: GitRepository
|
||||
metadata:
|
||||
name: podinfo
|
|
@ -18,7 +18,10 @@ limitations under the License.
|
|||
// and their default states.
|
||||
package features
|
||||
|
||||
import feathelper "github.com/fluxcd/pkg/runtime/features"
|
||||
import (
|
||||
"github.com/fluxcd/pkg/auth"
|
||||
feathelper "github.com/fluxcd/pkg/runtime/features"
|
||||
)
|
||||
|
||||
const (
|
||||
// CacheSecretsAndConfigMaps controls whether Secrets and ConfigMaps should
|
||||
|
@ -35,6 +38,10 @@ var features = map[string]bool{
|
|||
CacheSecretsAndConfigMaps: false,
|
||||
}
|
||||
|
||||
func init() {
|
||||
auth.SetFeatureGates(features)
|
||||
}
|
||||
|
||||
// FeatureGates contains a list of all supported feature gates and
|
||||
// their default values.
|
||||
func FeatureGates() map[string]bool {
|
||||
|
|
|
@ -18,36 +18,73 @@ package notifier
|
|||
|
||||
import (
|
||||
"context"
|
||||
"crypto/x509"
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/go-retryablehttp"
|
||||
"golang.org/x/text/cases"
|
||||
"golang.org/x/text/language"
|
||||
|
||||
eventv1 "github.com/fluxcd/pkg/apis/event/v1beta1"
|
||||
)
|
||||
|
||||
type Alertmanager struct {
|
||||
URL string
|
||||
ProxyURL string
|
||||
CertPool *x509.CertPool
|
||||
URL string
|
||||
ProxyURL string
|
||||
TLSConfig *tls.Config
|
||||
Token string
|
||||
}
|
||||
|
||||
type AlertManagerAlert struct {
|
||||
Status string `json:"status"`
|
||||
Labels map[string]string `json:"labels"`
|
||||
Annotations map[string]string `json:"annotations"`
|
||||
|
||||
StartsAt AlertManagerTime `json:"startsAt"`
|
||||
EndsAt AlertManagerTime `json:"endsAt,omitempty"`
|
||||
}
|
||||
|
||||
func NewAlertmanager(hookURL string, proxyURL string, certPool *x509.CertPool) (*Alertmanager, error) {
|
||||
// AlertManagerTime takes care of representing time.Time as RFC3339.
|
||||
// See https://prometheus.io/docs/alerting/0.27/clients/
|
||||
type AlertManagerTime time.Time
|
||||
|
||||
func (a AlertManagerTime) String() string {
|
||||
return time.Time(a).Format(time.RFC3339)
|
||||
}
|
||||
|
||||
func (a AlertManagerTime) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(a.String())
|
||||
}
|
||||
|
||||
func (a *AlertManagerTime) UnmarshalJSON(jsonRepr []byte) error {
|
||||
var serializedTime string
|
||||
if err := json.Unmarshal(jsonRepr, &serializedTime); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
t, err := time.Parse(time.RFC3339, serializedTime)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*a = AlertManagerTime(t)
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewAlertmanager(hookURL string, proxyURL string, tlsConfig *tls.Config, token string) (*Alertmanager, error) {
|
||||
_, err := url.ParseRequestURI(hookURL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid Alertmanager URL %s: '%w'", hookURL, err)
|
||||
}
|
||||
|
||||
return &Alertmanager{
|
||||
URL: hookURL,
|
||||
ProxyURL: proxyURL,
|
||||
CertPool: certPool,
|
||||
URL: hookURL,
|
||||
ProxyURL: proxyURL,
|
||||
Token: token,
|
||||
TLSConfig: tlsConfig,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -70,28 +107,52 @@ func (s *Alertmanager) Post(ctx context.Context, event eventv1.Event) error {
|
|||
if event.Metadata != nil {
|
||||
labels = event.Metadata
|
||||
}
|
||||
labels["alertname"] = "Flux" + event.InvolvedObject.Kind + strings.Title(event.Reason)
|
||||
labels["alertname"] = "Flux" + event.InvolvedObject.Kind + cases.Title(language.Und).String(event.Reason)
|
||||
labels["severity"] = event.Severity
|
||||
labels["reason"] = event.Reason
|
||||
labels["timestamp"] = event.Timestamp.String()
|
||||
|
||||
labels["kind"] = event.InvolvedObject.Kind
|
||||
labels["name"] = event.InvolvedObject.Name
|
||||
labels["namespace"] = event.InvolvedObject.Namespace
|
||||
labels["reportingcontroller"] = event.ReportingController
|
||||
|
||||
// The best reasonable `endsAt` value would be multiplying
|
||||
// InvolvedObject's reconciliation interval by 2 then adding that to
|
||||
// `startsAt` (the next successful reconciliation would make sure
|
||||
// the alert is cleared after the timeout). Due to
|
||||
// event.InvolvedObject only containing the object reference (namely
|
||||
// the GVKNN) best we can do is leave it unset up to Alertmanager's
|
||||
// default `resolve_timeout`.
|
||||
//
|
||||
// https://prometheus.io/docs/alerting/0.27/configuration/#file-layout-and-global-settings
|
||||
startsAt := AlertManagerTime(event.Timestamp.Time)
|
||||
|
||||
payload := []AlertManagerAlert{
|
||||
{
|
||||
Labels: labels,
|
||||
Annotations: annotations,
|
||||
Status: "firing",
|
||||
|
||||
StartsAt: startsAt,
|
||||
},
|
||||
}
|
||||
|
||||
err := postMessage(ctx, s.URL, s.ProxyURL, s.CertPool, payload)
|
||||
var opts []postOption
|
||||
if s.ProxyURL != "" {
|
||||
opts = append(opts, withProxy(s.ProxyURL))
|
||||
}
|
||||
if s.TLSConfig != nil {
|
||||
opts = append(opts, withTLSConfig(s.TLSConfig))
|
||||
}
|
||||
if s.Token != "" {
|
||||
opts = append(opts, withRequestModifier(func(request *retryablehttp.Request) {
|
||||
request.Header.Add("Authorization", "Bearer "+s.Token)
|
||||
}))
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if err := postMessage(ctx, s.URL, payload, opts...); err != nil {
|
||||
return fmt.Errorf("postMessage failed: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ package notifier
|
|||
|
||||
import (
|
||||
"context"
|
||||
"crypto/x509"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
@ -43,10 +43,10 @@ func Fuzz_AlertManager(f *testing.F) {
|
|||
}))
|
||||
defer ts.Close()
|
||||
|
||||
var cert x509.CertPool
|
||||
_ = fuzz.NewConsumer(seed).GenerateStruct(&cert)
|
||||
var tlsConfig tls.Config
|
||||
_ = fuzz.NewConsumer(seed).GenerateStruct(&tlsConfig)
|
||||
|
||||
alertmanager, err := NewAlertmanager(fmt.Sprintf("%s/%s", ts.URL, urlSuffix), "", &cert)
|
||||
alertmanager, err := NewAlertmanager(fmt.Sprintf("%s/%s", ts.URL, urlSuffix), "", &tlsConfig, "")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ func TestAlertmanager_Post(t *testing.T) {
|
|||
}))
|
||||
defer ts.Close()
|
||||
|
||||
alertmanager, err := NewAlertmanager(ts.URL, "", nil)
|
||||
alertmanager, err := NewAlertmanager(ts.URL, "", nil, "")
|
||||
require.NoError(t, err)
|
||||
|
||||
err = alertmanager.Post(context.TODO(), testEvent())
|
||||
|
|
|
@ -33,16 +33,21 @@ import (
|
|||
|
||||
const genre string = "fluxcd"
|
||||
|
||||
// AzureDevOps is a Azure DevOps notifier.
|
||||
type azureDevOpsClient interface {
|
||||
CreateCommitStatus(context.Context, git.CreateCommitStatusArgs) (*git.GitStatus, error)
|
||||
GetStatuses(context.Context, git.GetStatusesArgs) (*[]git.GitStatus, error)
|
||||
}
|
||||
|
||||
// AzureDevOps is an Azure DevOps notifier.
|
||||
type AzureDevOps struct {
|
||||
Project string
|
||||
Repo string
|
||||
ProviderUID string
|
||||
Client git.Client
|
||||
Project string
|
||||
Repo string
|
||||
CommitStatus string
|
||||
Client azureDevOpsClient
|
||||
}
|
||||
|
||||
// NewAzureDevOps creates and returns a new AzureDevOps notifier.
|
||||
func NewAzureDevOps(providerUID string, addr string, token string, certPool *x509.CertPool) (*AzureDevOps, error) {
|
||||
func NewAzureDevOps(commitStatus string, addr string, token string, certPool *x509.CertPool) (*AzureDevOps, error) {
|
||||
if len(token) == 0 {
|
||||
return nil, errors.New("azure devops token cannot be empty")
|
||||
}
|
||||
|
@ -52,6 +57,11 @@ func NewAzureDevOps(providerUID string, addr string, token string, certPool *x50
|
|||
return nil, err
|
||||
}
|
||||
|
||||
// this should never happen
|
||||
if commitStatus == "" {
|
||||
return nil, errors.New("commit status cannot be empty")
|
||||
}
|
||||
|
||||
comp := strings.Split(id, "/")
|
||||
if len(comp) != 4 {
|
||||
return nil, fmt.Errorf("invalid repository id %q", id)
|
||||
|
@ -72,10 +82,10 @@ func NewAzureDevOps(providerUID string, addr string, token string, certPool *x50
|
|||
Client: *client,
|
||||
}
|
||||
return &AzureDevOps{
|
||||
Project: proj,
|
||||
Repo: repo,
|
||||
ProviderUID: providerUID,
|
||||
Client: gitClient,
|
||||
Project: proj,
|
||||
Repo: repo,
|
||||
CommitStatus: commitStatus,
|
||||
Client: gitClient,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -86,7 +96,7 @@ func (a AzureDevOps) Post(ctx context.Context, event eventv1.Event) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
revString, ok := event.Metadata[eventv1.MetaRevisionKey]
|
||||
revString, ok := event.GetRevision()
|
||||
if !ok {
|
||||
return errors.New("missing revision metadata")
|
||||
}
|
||||
|
@ -100,9 +110,10 @@ func (a AzureDevOps) Post(ctx context.Context, event eventv1.Event) error {
|
|||
}
|
||||
|
||||
// Check if the exact status is already set
|
||||
g := genre
|
||||
g := commitStatusGenre(event)
|
||||
|
||||
_, desc := formatNameAndDescription(event)
|
||||
id := generateCommitStatusID(a.ProviderUID, event)
|
||||
id := a.CommitStatus
|
||||
createArgs := git.CreateCommitStatusArgs{
|
||||
Project: &a.Project,
|
||||
RepositoryId: &a.Repo,
|
||||
|
@ -123,8 +134,9 @@ func (a AzureDevOps) Post(ctx context.Context, event eventv1.Event) error {
|
|||
}
|
||||
statuses, err := a.Client.GetStatuses(ctx, getArgs)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not list commit statuses: %v", err)
|
||||
return fmt.Errorf("could not list commit statuses: %w", err)
|
||||
}
|
||||
|
||||
if duplicateAzureDevOpsStatus(statuses, createArgs.GitCommitStatusToCreate) {
|
||||
return nil
|
||||
}
|
||||
|
@ -132,7 +144,7 @@ func (a AzureDevOps) Post(ctx context.Context, event eventv1.Event) error {
|
|||
// Create a new status
|
||||
_, err = a.Client.CreateCommitStatus(ctx, createArgs)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not create commit status: %v", err)
|
||||
return fmt.Errorf("could not create commit status: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -172,3 +184,12 @@ func duplicateAzureDevOpsStatus(statuses *[]git.GitStatus, status *git.GitStatus
|
|||
|
||||
return false
|
||||
}
|
||||
|
||||
func commitStatusGenre(event eventv1.Event) string {
|
||||
summary, ok := event.Metadata["summary"]
|
||||
if ok {
|
||||
return fmt.Sprintf("%s:%s", genre, summary)
|
||||
}
|
||||
|
||||
return genre
|
||||
}
|
||||
|
|
|
@ -33,12 +33,12 @@ import (
|
|||
const apiLocations = `{"count":0,"value":[{"area":"","id":"428dd4fb-fda5-4722-af02-9313b80305da","routeTemplate":"","resourceName":"","maxVersion":"6.0","minVersion":"5.0","releasedVersion":"6.0"}]}`
|
||||
|
||||
func Fuzz_AzureDevOps(f *testing.F) {
|
||||
f.Add("0c9c2e41-d2f9-4f9b-9c41-bebc1984d67a", "alakazam", "org/proj/_git/repo", "revision/dsa123a", "error", "", []byte{}, []byte(`{"count":1,"value":[{"state":"error","description":"","context":{"genre":"fluxcd","name":"/"}}]}`))
|
||||
f.Add("0c9c2e41-d2f9-4f9b-9c41-bebc1984d67a", "alakazam", "org/proj/_git/repo", "revision/dsa123a", "info", "", []byte{}, []byte(`{"count":1,"value":[{"state":"info","description":"","context":{"genre":"fluxcd","name":"/"}}]}`))
|
||||
f.Add("0c9c2e41-d2f9-4f9b-9c41-bebc1984d67a", "alakazam", "org/proj/_git/repo", "revision/dsa123a", "info", "", []byte{}, []byte(`{"count":0,"value":[]}`))
|
||||
f.Add("0c9c2e41-d2f9-4f9b-9c41-bebc1984d67a", "alakazam", "org/proj/_git/repo", "", "", "Progressing", []byte{}, []byte{})
|
||||
f.Add("kustomization/gitops-system/0c9c2e41", "alakazam", "org/proj/_git/repo", "revision/dsa123a", "error", "", []byte{}, []byte(`{"count":1,"value":[{"state":"error","description":"","context":{"genre":"fluxcd","name":"/"}}]}`))
|
||||
f.Add("kustomization/gitops-system/0c9c2e41", "alakazam", "org/proj/_git/repo", "revision/dsa123a", "info", "", []byte{}, []byte(`{"count":1,"value":[{"state":"info","description":"","context":{"genre":"fluxcd","name":"/"}}]}`))
|
||||
f.Add("kustomization/gitops-system/0c9c2e41", "alakazam", "org/proj/_git/repo", "revision/dsa123a", "info", "", []byte{}, []byte(`{"count":0,"value":[]}`))
|
||||
f.Add("kustomization/gitops-system/0c9c2e41", "alakazam", "org/proj/_git/repo", "", "", "Progressing", []byte{}, []byte{})
|
||||
|
||||
f.Fuzz(func(t *testing.T, uuid, token, urlSuffix, revision, severity, reason string, seed, response []byte) {
|
||||
f.Fuzz(func(t *testing.T, commitStatus, token, urlSuffix, revision, severity, reason string, seed, response []byte) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if strings.HasSuffix(r.URL.Path, "_apis") {
|
||||
w.Write([]byte(apiLocations))
|
||||
|
@ -54,7 +54,7 @@ func Fuzz_AzureDevOps(f *testing.F) {
|
|||
var cert x509.CertPool
|
||||
_ = fuzz.NewConsumer(seed).GenerateStruct(&cert)
|
||||
|
||||
azureDevOps, err := NewAzureDevOps(uuid, fmt.Sprintf("%s/%s", ts.URL, urlSuffix), token, &cert)
|
||||
azureDevOps, err := NewAzureDevOps(commitStatus, fmt.Sprintf("%s/%s", ts.URL, urlSuffix), token, &cert)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue