Compare commits

..

No commits in common. "main" and "v0.32.1" have entirely different histories.

181 changed files with 4579 additions and 19062 deletions

View File

@ -1,30 +0,0 @@
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"

30
.github/labels.yaml vendored
View File

@ -1,30 +0,0 @@
# 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'

View File

@ -1,31 +0,0 @@
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}.

View File

@ -1,7 +1,8 @@
name: fuzz name: fuzz
on: on:
pull_request: pull_request:
branches: [ 'main', 'release/**' ] branches:
- main
permissions: permissions:
contents: read # for actions/checkout to fetch code contents: read # for actions/checkout to fetch code
@ -11,13 +12,20 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 uses: actions/checkout@v3
- name: Setup Go - name: Setup Go
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 uses: actions/setup-go@v3
with: with:
go-version: 1.24.x go-version: 1.19.x
cache-dependency-path: | - id: go-env
**/go.sum run: |
**/go.mod 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 - name: Smoke test Fuzzers
run: make fuzz-smoketest run: make fuzz-smoketest

View File

@ -2,7 +2,8 @@ name: e2e
on: on:
pull_request: pull_request:
push: push:
branches: [ 'main', 'release/**' ] branches:
- main
permissions: permissions:
contents: read # for actions/checkout to fetch code contents: read # for actions/checkout to fetch code
@ -12,14 +13,25 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 uses: actions/checkout@v3
- name: Setup QEMU - name: Setup QEMU
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0 uses: docker/setup-qemu-action@v2
with:
platforms: all
- name: Setup Docker Buildx - name: Setup Docker Buildx
id: buildx id: buildx
uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0 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-
- name: Cache Docker layers - name: Cache Docker layers
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 uses: actions/cache@v3
id: cache id: cache
with: with:
path: /tmp/.buildx-cache path: /tmp/.buildx-cache
@ -27,18 +39,16 @@ jobs:
restore-keys: | restore-keys: |
${{ runner.os }}-buildx-ghcache- ${{ runner.os }}-buildx-ghcache-
- name: Setup Go - name: Setup Go
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 uses: actions/setup-go@v3
with: with:
go-version: 1.24.x go-version: 1.19.x
cache-dependency-path: |
**/go.sum
**/go.mod
- name: Setup Kubernetes - name: Setup Kubernetes
uses: helm/kind-action@a1b0e391336a6ee6713a0583f8c6240d70863de3 # v1.12.0 uses: helm/kind-action@v1.5.0
with: with:
version: v0.17.0
cluster_name: kind cluster_name: kind
- name: Setup Kustomize - name: Setup Kustomize
uses: fluxcd/pkg/actions/kustomize@main uses: fluxcd/pkg//actions/kustomize@main
- name: Run tests - name: Run tests
run: make test run: make test
- name: Check if working tree is dirty - name: Check if working tree is dirty
@ -69,7 +79,7 @@ jobs:
- name: Run default status test - name: Run default status test
run: | run: |
kubectl apply -f config/testdata/status-defaults kubectl apply -f config/testdata/status-defaults
for crd in receiver ; do for crd in alert provider receiver ; do
RESULT=$(kubectl get ${crd} status-defaults -o go-template={{.status}}) RESULT=$(kubectl get ${crd} status-defaults -o go-template={{.status}})
EXPECTED='map[observedGeneration:-1]' EXPECTED='map[observedGeneration:-1]'
if [ "${RESULT}" != "${EXPECTED}" ] ; then if [ "${RESULT}" != "${EXPECTED}" ] ; then
@ -86,6 +96,9 @@ jobs:
- name: Run smoke tests - name: Run smoke tests
run: | run: |
kubectl -n notification-system apply -f ./config/samples 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 kubectl -n notification-system wait receiver/receiver-sample --for=condition=ready --timeout=1m
- name: Logs - name: Logs
run: | run: |

View File

@ -7,29 +7,22 @@ on:
inputs: inputs:
tag: tag:
description: 'image tag prefix' description: 'image tag prefix'
default: 'preview' default: 'rc'
required: true required: true
permissions: permissions:
contents: read contents: write # needed to write releases
id-token: write # needed for keyless signing
packages: write # needed for ghcr access
env: env:
CONTROLLER: ${{ github.event.repository.name }} CONTROLLER: ${{ github.event.repository.name }}
jobs: jobs:
release: build-push:
outputs:
hashes: ${{ steps.slsa.outputs.hashes }}
image_url: ${{ steps.slsa.outputs.image_url }}
image_digest: ${{ steps.slsa.outputs.image_digest }}
runs-on: ubuntu-latest 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: steps:
- name: Checkout - uses: actions/checkout@v3
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Setup Kustomize - name: Setup Kustomize
uses: fluxcd/pkg/actions/kustomize@main uses: fluxcd/pkg/actions/kustomize@main
- name: Prepare - name: Prepare
@ -42,24 +35,24 @@ jobs:
echo "BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_OUTPUT echo "BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_OUTPUT
echo "VERSION=${VERSION}" >> $GITHUB_OUTPUT echo "VERSION=${VERSION}" >> $GITHUB_OUTPUT
- name: Setup QEMU - name: Setup QEMU
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0 uses: docker/setup-qemu-action@v2
- name: Setup Docker Buildx - name: Setup Docker Buildx
id: buildx id: buildx
uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0 uses: docker/setup-buildx-action@v2
- name: Login to GitHub Container Registry - name: Login to GitHub Container Registry
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 uses: docker/login-action@v2
with: with:
registry: ghcr.io registry: ghcr.io
username: fluxcdbot username: fluxcdbot
password: ${{ secrets.GHCR_TOKEN }} password: ${{ secrets.GHCR_TOKEN }}
- name: Login to Docker Hub - name: Login to Docker Hub
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 uses: docker/login-action@v2
with: with:
username: fluxcdbot username: fluxcdbot
password: ${{ secrets.DOCKER_FLUXCD_PASSWORD }} password: ${{ secrets.DOCKER_FLUXCD_PASSWORD }}
- name: Generate images meta - name: Generate images meta
id: meta id: meta
uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0 uses: docker/metadata-action@v4
with: with:
images: | images: |
fluxcd/${{ env.CONTROLLER }} fluxcd/${{ env.CONTROLLER }}
@ -67,8 +60,7 @@ jobs:
tags: | tags: |
type=raw,value=${{ steps.prep.outputs.VERSION }} type=raw,value=${{ steps.prep.outputs.VERSION }}
- name: Publish images - name: Publish images
id: build-push uses: docker/build-push-action@v3
uses: docker/build-push-action@1dc73863535b631f98b2378be8619f83b136f4a0 # v6.17.0
with: with:
sbom: true sbom: true
provenance: true provenance: true
@ -79,82 +71,32 @@ jobs:
platforms: linux/amd64,linux/arm/v7,linux/arm64 platforms: linux/amd64,linux/arm/v7,linux/arm64
tags: ${{ steps.meta.outputs.tags }} tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }} labels: ${{ steps.meta.outputs.labels }}
- uses: sigstore/cosign-installer@3454372f43399081ed03b604cb2d021dabca52bb # v3.8.2 - 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
- name: Sign images - name: Sign images
env: env:
COSIGN_EXPERIMENTAL: 1 COSIGN_EXPERIMENTAL: 1
run: | run: |
cosign sign --yes fluxcd/${{ env.CONTROLLER }}@${{ steps.build-push.outputs.digest }} cosign sign fluxcd/${{ env.CONTROLLER }}:${{ steps.prep.outputs.VERSION }}
cosign sign --yes ghcr.io/fluxcd/${{ env.CONTROLLER }}@${{ steps.build-push.outputs.digest }} cosign sign ghcr.io/fluxcd/${{ env.CONTROLLER }}:${{ steps.prep.outputs.VERSION }}
- name: Generate release artifacts - name: Generate release artifacts
if: startsWith(github.ref, 'refs/tags/v') if: startsWith(github.ref, 'refs/tags/v')
run: | run: |
mkdir -p config/release mkdir -p config/release
kustomize build ./config/crd > ./config/release/${{ env.CONTROLLER }}.crds.yaml kustomize build ./config/crd > ./config/release/${{ env.CONTROLLER }}.crds.yaml
kustomize build ./config/manager > ./config/release/${{ env.CONTROLLER }}.deployment.yaml kustomize build ./config/manager > ./config/release/${{ env.CONTROLLER }}.deployment.yaml
- uses: anchore/sbom-action/download-syft@e11c554f704a0b820cbf8c51673f6945e0731532 # v0.20.0 echo '[CHANGELOG](https://github.com/fluxcd/${{ env.CONTROLLER }}/blob/main/CHANGELOG.md)' > ./config/release/notes.md
- uses: anchore/sbom-action/download-syft@v0
- name: Create release and SBOM - name: Create release and SBOM
id: run-goreleaser
if: startsWith(github.ref, 'refs/tags/v') if: startsWith(github.ref, 'refs/tags/v')
uses: goreleaser/goreleaser-action@9c156ee8a17a598857849441385a2041ef570552 # v6.3.0 uses: goreleaser/goreleaser-action@v3
with: with:
version: latest version: latest
args: release --clean --skip=validate args: release --release-notes=config/release/notes.md --rm-dist --skip-validate
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 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 }}

View File

@ -1,10 +1,9 @@
name: scan name: scan
on: on:
push: push:
branches: [ 'main', 'release/**' ] branches: [ main ]
pull_request: pull_request:
branches: [ 'main', 'release/**' ] branches: [ main ]
schedule: schedule:
- cron: '18 10 * * 3' - cron: '18 10 * * 3'
@ -17,10 +16,9 @@ jobs:
name: FOSSA name: FOSSA
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - uses: actions/checkout@v3
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Run FOSSA scan and upload build data - name: Run FOSSA scan and upload build data
uses: fossa-contrib/fossa-action@3d2ef181b1820d6dcd1972f86a767d18167fa19b # v3.0.1 uses: fossa-contrib/fossa-action@v1
with: with:
# FOSSA Push-Only API Token # FOSSA Push-Only API Token
fossa-api-key: 5ee8bf422db1471e0bcf2bcb289185de fossa-api-key: 5ee8bf422db1471e0bcf2bcb289185de
@ -30,23 +28,17 @@ jobs:
name: CodeQL name: CodeQL
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 uses: actions/checkout@v3
- name: Setup Go - name: Setup Go
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 uses: actions/setup-go@v3
with: with:
go-version: 1.24.x go-version: 1.19.x
cache-dependency-path: |
**/go.sum
**/go.mod
- name: Initialize CodeQL - name: Initialize CodeQL
uses: github/codeql-action/init@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18 uses: github/codeql-action/init@v2
with: with:
languages: go 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 - name: Autobuild
uses: github/codeql-action/autobuild@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18 uses: github/codeql-action/autobuild@v2
- name: Perform CodeQL Analysis - name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18 uses: github/codeql-action/analyze@v2

View File

@ -1,28 +0,0 @@
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

View File

@ -4,26 +4,9 @@ builds:
- skip: true - skip: true
release: release:
prerelease: "true"
extra_files: extra_files:
- glob: config/release/*.yaml - 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: checksum:
extra_files: extra_files:
@ -49,7 +32,6 @@ signs:
certificate: "${artifact}.pem" certificate: "${artifact}.pem"
args: args:
- sign-blob - sign-blob
- "--yes"
- "--output-certificate=${certificate}" - "--output-certificate=${certificate}"
- "--output-signature=${signature}" - "--output-signature=${signature}"
- "${artifact}" - "${artifact}"

View File

@ -2,622 +2,6 @@
All notable changes to this project are documented in this file. 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 ## 0.32.1
**Release date:** 2023-02-28 **Release date:** 2023-02-28

View File

@ -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 ## How to run the test suite
Prerequisites: Prerequisites:
- Go >= 1.24 - Go >= 1.17
You can run the test suite by simply doing: You can run the test suite by simply doing:

View File

@ -1,9 +1,9 @@
ARG GO_VERSION=1.24 ARG GO_VERSION=1.19
ARG XX_VERSION=1.6.1 ARG XX_VERSION=1.1.0
FROM --platform=$BUILDPLATFORM tonistiigi/xx:${XX_VERSION} AS xx 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 the build utilities.
COPY --from=xx / / COPY --from=xx / /
@ -24,21 +24,21 @@ RUN go mod download
# copy source code # copy source code
COPY main.go main.go COPY main.go main.go
COPY controllers/ controllers/
COPY internal/ internal/ COPY internal/ internal/
# build # build
ENV CGO_ENABLED=0 ENV CGO_ENABLED=0
RUN xx-go build -trimpath -a -o notification-controller main.go RUN xx-go build -trimpath -a -o notification-controller main.go
FROM alpine:3.21 FROM alpine:3.17
ARG TARGETPLATFORM LABEL org.opencontainers.image.source="https://github.com/fluxcd/notification-controller"
RUN apk --no-cache add ca-certificates \ RUN apk add --no-cache ca-certificates tini
&& update-ca-certificates
COPY --from=builder /workspace/notification-controller /usr/local/bin/ COPY --from=builder /workspace/notification-controller /usr/local/bin/
USER 65534:65534 USER 65534:65534
ENTRYPOINT ["notification-controller" ] ENTRYPOINT [ "/sbin/tini", "--", "notification-controller" ]

View File

@ -7,6 +7,4 @@ as listed in
https://github.com/fluxcd/flux2/blob/main/MAINTAINERS https://github.com/fluxcd/flux2/blob/main/MAINTAINERS
In alphabetical order: Somtochi Onyekwere, Weaveworks <somtochi@weave.works> (github: @SomtochiAma, slack: somtoxhi)
Somtochi Onyekwere, Independent <somtochionyekwere@gmail.com> (github: @somtochiama, slack: somtochiama)

View File

@ -2,14 +2,14 @@
IMG ?= fluxcd/notification-controller:latest IMG ?= fluxcd/notification-controller:latest
# Produce CRDs that work back to Kubernetes 1.16 # Produce CRDs that work back to Kubernetes 1.16
CRD_OPTIONS ?= crd:crdVersions=v1 CRD_OPTIONS ?= crd:crdVersions=v1
SOURCE_VER ?= v1.2.4 SOURCE_VER ?= v0.35.0
# Repository root based on Git metadata # Repository root based on Git metadata
REPOSITORY_ROOT := $(shell git rev-parse --show-toplevel) REPOSITORY_ROOT := $(shell git rev-parse --show-toplevel)
BUILD_DIR := $(REPOSITORY_ROOT)/build BUILD_DIR := $(REPOSITORY_ROOT)/build
# API (doc) generation utilities # API (doc) generation utilities
CONTROLLER_GEN_VERSION ?= v0.16.1 CONTROLLER_GEN_VERSION ?= v0.11.1
GEN_API_REF_DOCS_VERSION ?= e327d0730470cbd61b06300f81c5fcf91c23c113 GEN_API_REF_DOCS_VERSION ?= e327d0730470cbd61b06300f81c5fcf91c23c113
# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set) # Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
@ -87,14 +87,12 @@ manifests: controller-gen
# Generate API reference documentation # Generate API reference documentation
api-docs: gen-crd-api-reference-docs 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/v1beta2/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/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 # Run go mod tidy
tidy: tidy:
cd api; rm -f go.sum; go mod tidy -compat=1.24 cd api; rm -f go.sum; go mod tidy -compat=1.19
rm -f go.sum; go mod tidy -compat=1.24 rm -f go.sum; go mod tidy -compat=1.19
# Run go fmt against code # Run go fmt against code
fmt: fmt:
@ -153,13 +151,13 @@ fuzz-native:
./tests/fuzz/native_go_run.sh ./tests/fuzz/native_go_run.sh
# Find or download controller-gen # Find or download controller-gen
CONTROLLER_GEN = $(GOBIN)/controller-gen CONTROLLER_GEN = $(shell pwd)/bin/controller-gen
.PHONY: controller-gen .PHONY: controller-gen
controller-gen: ## Download controller-gen locally if necessary. 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)) $(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 # Find or download gen-crd-api-reference-docs
GEN_CRD_API_REFERENCE_DOCS = $(GOBIN)/gen-crd-api-reference-docs GEN_CRD_API_REFERENCE_DOCS = $(shell pwd)/bin/gen-crd-api-reference-docs
.PHONY: gen-crd-api-reference-docs .PHONY: gen-crd-api-reference-docs
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)) $(call go-install-tool,$(GEN_CRD_API_REFERENCE_DOCS),github.com/ahmetb/gen-crd-api-reference-docs@$(GEN_API_REF_DOCS_VERSION))
@ -171,7 +169,7 @@ install-envtest: setup-envtest
mkdir -p ${ENVTEST_ASSETS_DIR} mkdir -p ${ENVTEST_ASSETS_DIR}
$(ENVTEST) use $(ENVTEST_KUBERNETES_VERSION) --arch=$(ENVTEST_ARCH) --bin-dir=$(ENVTEST_ASSETS_DIR) $(ENVTEST) use $(ENVTEST_KUBERNETES_VERSION) --arch=$(ENVTEST_ARCH) --bin-dir=$(ENVTEST_ASSETS_DIR)
ENVTEST = $(GOBIN)/setup-envtest ENVTEST = $(shell pwd)/bin/setup-envtest
.PHONY: envtest .PHONY: envtest
setup-envtest: ## Download envtest-setup locally if necessary. setup-envtest: ## Download envtest-setup locally if necessary.
$(call go-install-tool,$(ENVTEST),sigs.k8s.io/controller-runtime/tools/setup-envtest@latest) $(call go-install-tool,$(ENVTEST),sigs.k8s.io/controller-runtime/tools/setup-envtest@latest)
@ -185,7 +183,7 @@ TMP_DIR=$$(mktemp -d) ;\
cd $$TMP_DIR ;\ cd $$TMP_DIR ;\
go mod init tmp ;\ go mod init tmp ;\
echo "Downloading $(2)" ;\ echo "Downloading $(2)" ;\
GOBIN=$(GOBIN) go install $(2) ;\ GOBIN=$(PROJECT_DIR)/bin go install $(2) ;\
rm -rf $$TMP_DIR ;\ rm -rf $$TMP_DIR ;\
} }
endef endef

13
PROJECT
View File

@ -1,13 +1,6 @@
# 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 domain: toolkit.fluxcd.io
repo: github.com/fluxcd/notification-controller repo: github.com/fluxcd/notification-controller
resources: resources:
- group: notification
kind: Receiver
version: v1
- group: notification - group: notification
kind: Provider kind: Provider
version: v1beta1 version: v1beta1
@ -26,10 +19,4 @@ resources:
- group: notification - group: notification
kind: Receiver kind: Receiver
version: v1beta2 version: v1beta2
- group: notification
kind: Provider
version: v1beta3
- group: notification
kind: Alert
version: v1beta3
version: "2" version: "2"

View File

@ -7,7 +7,7 @@
[![release](https://img.shields.io/github/release/fluxcd/notification-controller/all.svg)](https://github.com/fluxcd/notification-controller/releases) [![release](https://img.shields.io/github/release/fluxcd/notification-controller/all.svg)](https://github.com/fluxcd/notification-controller/releases)
Event forwarder and notification dispatcher for the [GitOps Toolkit](https://fluxcd.io/flux/components/) controllers. 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/v1beta3/README.md) The notification-controller is an implementation of the [notification.toolkit.fluxcd.io](docs/spec/v1beta1/README.md)
API based on the specifications described in the [RFC](docs/spec/README.md). API based on the specifications described in the [RFC](docs/spec/README.md).
![overview](docs/diagrams/notification-controller-overview.png) ![overview](docs/diagrams/notification-controller-overview.png)

View File

@ -1,35 +1,29 @@
module github.com/fluxcd/notification-controller/api module github.com/fluxcd/notification-controller/api
go 1.24.0 go 1.18
require ( require (
github.com/fluxcd/pkg/apis/meta v1.17.0 github.com/fluxcd/pkg/apis/meta v0.19.0
k8s.io/apimachinery v0.33.2 k8s.io/apimachinery v0.26.1
sigs.k8s.io/controller-runtime v0.21.0 sigs.k8s.io/controller-runtime v0.14.4
) )
// Fix CVE-2022-28948 // Fix CVE-2022-28948
replace gopkg.in/yaml.v3 => gopkg.in/yaml.v3 v3.0.1 replace gopkg.in/yaml.v3 => gopkg.in/yaml.v3 v3.0.1
require ( require (
github.com/fxamacker/cbor/v2 v2.8.0 // indirect github.com/go-logr/logr v1.2.3 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/gogo/protobuf v1.3.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/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/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/spf13/pflag v1.0.6 // indirect golang.org/x/net v0.7.0 // indirect
github.com/x448/float16 v0.8.4 // indirect golang.org/x/text v0.7.0 // 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/inf.v0 v0.9.1 // indirect
k8s.io/klog/v2 v2.130.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect
k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e // indirect k8s.io/klog/v2 v2.80.1 // indirect
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect k8s.io/utils v0.0.0-20221128185143-99ec85e7a448 // indirect
sigs.k8s.io/randfill v1.0.0 // indirect sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.7.0 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
sigs.k8s.io/yaml v1.5.0 // indirect
) )

View File

@ -1,61 +1,38 @@
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.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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fluxcd/pkg/apis/meta v1.17.0 h1:KVMDyJQj1NYCsppsFUkbJGMnKxsqJVpnKBFolHf/q8E= github.com/fluxcd/pkg/apis/meta v0.19.0 h1:CX75e/eaRWZDTzNdMSWomY1InlssLKcS8GQDSg/aopI=
github.com/fluxcd/pkg/apis/meta v1.17.0/go.mod h1:97l3hTwBpJbXBY+wetNbqrUsvES8B1jGioKcBUxmqd8= github.com/fluxcd/pkg/apis/meta v0.19.0/go.mod h1:7b6prDPsViyAzoY7eRfSPS0/MbXpGGsOMvRq2QrTKa4=
github.com/fxamacker/cbor/v2 v2.8.0 h1:fFtUGXUzXPHTIUdne5+zzMPTfffl3RD5qYnkY40vtxU= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/fxamacker/cbor/v2 v2.8.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
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 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
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.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= 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/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/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 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 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-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 h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 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 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/onsi/ginkgo/v2 v2.22.0 h1:Yed107/8DjTr0lKCNt7Dn8yQ6ybuDRQoMGrNFKzMfHg= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/onsi/ginkgo/v2 v2.22.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= github.com/onsi/ginkgo/v2 v2.6.0 h1:9t9b9vRUbFq3C4qKFCGkVuq/fIHji802N1nrtkh1mNc=
github.com/onsi/gomega v1.36.1 h1:bJDPBO7ibjxcbHMgSCoo4Yj18UWbKDlLwX1x9sybDcw= github.com/onsi/gomega v1.24.1 h1:KORJXNNTzJXzu4ScJWssJfJMnJ+2QJqhoQSRwNlze9E=
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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
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/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.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
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.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/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-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-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
@ -65,54 +42,46 @@ 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-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-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.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 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-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/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-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-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
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.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 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-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-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.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-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-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-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/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 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
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 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= 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= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= k8s.io/api v0.26.1 h1:f+SWYiPd/GsiWwVRz+NbFyCgvv75Pk9NK6dlkZgpCRQ=
k8s.io/api v0.33.0 h1:yTgZVn1XEe6opVpP1FylmNrIFWuDqe2H0V8CT5gxfIU= k8s.io/apimachinery v0.26.1 h1:8EZ/eGJL+hY/MYCNwhmDzVqq2lPl3N3Bo8rvweJwXUQ=
k8s.io/api v0.33.0/go.mod h1:CTO61ECK/KU7haa3qq8sarQ0biLq2ju405IZAd9zsiM= k8s.io/apimachinery v0.26.1/go.mod h1:tnPmbONNJ7ByJNz9+n9kMjNP8ON+1qoAIIC70lztu74=
k8s.io/apimachinery v0.33.2 h1:IHFVhqg59mb8PJWTLi8m1mAoepkUNYmptHsV+Z1m5jY= k8s.io/klog/v2 v2.80.1 h1:atnLQ121W371wYYFawwYx1aEY2eUfs4l3J72wtgAwV4=
k8s.io/apimachinery v0.33.2/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM= k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/utils v0.0.0-20221128185143-99ec85e7a448 h1:KTgPnR10d5zhztWptI952TNtt/4u5h3IzDXkdIMuo2Y=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/utils v0.0.0-20221128185143-99ec85e7a448/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e h1:KqK5c/ghOm8xkHYhlodbp6i6+r+ChV2vuAuVRdFbLro= sigs.k8s.io/controller-runtime v0.14.4 h1:Kd/Qgx5pd2XUL08eOV2vwIq3L9GhIbJ5Nxengbd4/0M=
k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= sigs.k8s.io/controller-runtime v0.14.4/go.mod h1:WqIdsAY6JBsjfc/CqO0CORmNtoCtE4S6qbPc9s68h+0=
sigs.k8s.io/controller-runtime v0.21.0 h1:CYfjpEuicjUecRk+KAeyYh+ouUBn4llGyDYytIGcJS8= sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 h1:iXTIw73aPyC+oRdyqqvVJuloN1p0AC/kzH07hu3NE+k=
sigs.k8s.io/controller-runtime v0.21.0/go.mod h1:OSg14+F65eWqIu4DceX7k/+QRAbTTvxeQSNSOQpukWM= sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE= sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE=
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E=
sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
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=

View File

@ -1,31 +0,0 @@
/*
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"
)

View File

@ -1,33 +0,0 @@
/*
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
)

View File

@ -1,164 +0,0 @@
/*
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{})
}

View File

@ -1,51 +0,0 @@
/*
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"`
}

View File

@ -1,163 +0,0 @@
//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
}

View File

@ -67,9 +67,9 @@ type AlertStatus struct {
} }
// +genclient // +genclient
// +genclient:Namespaced
// +kubebuilder:object:root=true // +kubebuilder:object:root=true
// +kubebuilder:subresource:status // +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="Age",type="date",JSONPath=".metadata.creationTimestamp",description=""
// +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].status",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="" // +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].message",description=""

View File

@ -110,9 +110,9 @@ type ProviderStatus struct {
} }
// +genclient // +genclient
// +genclient:Namespaced
// +kubebuilder:object:root=true // +kubebuilder:object:root=true
// +kubebuilder:subresource:status // +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="Age",type="date",JSONPath=".metadata.creationTimestamp",description=""
// +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].status",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="" // +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].message",description=""

View File

@ -97,9 +97,9 @@ func (in *Receiver) SetConditions(conditions []metav1.Condition) {
} }
// +genclient // +genclient
// +genclient:Namespaced
// +kubebuilder:object:root=true // +kubebuilder:object:root=true
// +kubebuilder:subresource:status // +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="Age",type="date",JSONPath=".metadata.creationTimestamp",description=""
// +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].status",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="" // +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].message",description=""

View File

@ -1,7 +1,8 @@
//go:build !ignore_autogenerated //go:build !ignore_autogenerated
// +build !ignore_autogenerated
/* /*
Copyright 2023 The Flux authors Copyright 2022 The Flux authors
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -19,8 +19,6 @@ package v1beta2
import ( import (
"github.com/fluxcd/pkg/apis/meta" "github.com/fluxcd/pkg/apis/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
v1 "github.com/fluxcd/notification-controller/api/v1"
) )
const ( const (
@ -43,20 +41,7 @@ type AlertSpec struct {
// EventSources specifies how to filter events based // EventSources specifies how to filter events based
// on the involved object kind, name and namespace. // on the involved object kind, name and namespace.
// +required // +required
EventSources []v1.CrossNamespaceObjectReference `json:"eventSources"` EventSources []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 // ExclusionList specifies a list of Golang regular expressions
// to be used for excluding messages. // to be used for excluding messages.
@ -88,9 +73,10 @@ type AlertStatus struct {
} }
// +genclient // +genclient
// +genclient:Namespaced
// +kubebuilder:storageversion
// +kubebuilder:object:root=true // +kubebuilder:object:root=true
// +kubebuilder:subresource:status // +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="Age",type="date",JSONPath=".metadata.creationTimestamp",description=""
// +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].status",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="" // +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].message",description=""

View File

@ -36,11 +36,9 @@ const (
GitHubProvider string = "github" GitHubProvider string = "github"
GitLabProvider string = "gitlab" GitLabProvider string = "gitlab"
GiteaProvider string = "gitea" GiteaProvider string = "gitea"
BitbucketServerProvider string = "bitbucketserver"
BitbucketProvider string = "bitbucket" BitbucketProvider string = "bitbucket"
AzureDevOpsProvider string = "azuredevops" AzureDevOpsProvider string = "azuredevops"
GoogleChatProvider string = "googlechat" GoogleChatProvider string = "googlechat"
GooglePubSubProvider string = "googlepubsub"
WebexProvider string = "webex" WebexProvider string = "webex"
SentryProvider string = "sentry" SentryProvider string = "sentry"
AzureEventHubProvider string = "azureeventhub" AzureEventHubProvider string = "azureeventhub"
@ -49,14 +47,12 @@ const (
Matrix string = "matrix" Matrix string = "matrix"
OpsgenieProvider string = "opsgenie" OpsgenieProvider string = "opsgenie"
AlertManagerProvider string = "alertmanager" AlertManagerProvider string = "alertmanager"
PagerDutyProvider string = "pagerduty"
DataDogProvider string = "datadog"
) )
// ProviderSpec defines the desired state of the Provider. // ProviderSpec defines the desired state of the Provider.
type ProviderSpec struct { type ProviderSpec struct {
// Type specifies which Provider implementation to use. // 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 // +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;
// +required // +required
Type string `json:"type"` Type string `json:"type"`
@ -76,10 +72,8 @@ type ProviderSpec struct {
// +optional // +optional
Username string `json:"username,omitempty"` Username string `json:"username,omitempty"`
// Address specifies the endpoint, in a generic sense, to where alerts are sent. // Address specifies the HTTP/S incoming webhook address of this Provider.
// What kind of endpoint depends on the specific Provider type being used. // +kubebuilder:validation:Pattern="^(http|https)://.*$"
// 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:MaxLength:=2048
// +kubebuilder:validation:Optional // +kubebuilder:validation:Optional
// +optional // +optional
@ -104,11 +98,8 @@ type ProviderSpec struct {
SecretRef *meta.LocalObjectReference `json:"secretRef,omitempty"` SecretRef *meta.LocalObjectReference `json:"secretRef,omitempty"`
// CertSecretRef specifies the Secret containing // CertSecretRef specifies the Secret containing
// a PEM-encoded CA certificate (in the `ca.crt` key). // a PEM-encoded CA certificate (`caFile`).
// +optional // +optional
//
// Note: Support for the `caFile` key has
// been deprecated.
CertSecretRef *meta.LocalObjectReference `json:"certSecretRef,omitempty"` CertSecretRef *meta.LocalObjectReference `json:"certSecretRef,omitempty"`
// Suspend tells the controller to suspend subsequent // Suspend tells the controller to suspend subsequent
@ -131,9 +122,10 @@ type ProviderStatus struct {
} }
// +genclient // +genclient
// +genclient:Namespaced
// +kubebuilder:storageversion
// +kubebuilder:object:root=true // +kubebuilder:object:root=true
// +kubebuilder:subresource:status // +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="Age",type="date",JSONPath=".metadata.creationTimestamp",description=""
// +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].status",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="" // +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].message",description=""

View File

@ -24,8 +24,6 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/fluxcd/pkg/apis/meta" "github.com/fluxcd/pkg/apis/meta"
v1 "github.com/fluxcd/notification-controller/api/v1"
) )
const ( const (
@ -65,7 +63,7 @@ type ReceiverSpec struct {
// A list of resources to be notified about changes. // A list of resources to be notified about changes.
// +required // +required
Resources []v1.CrossNamespaceObjectReference `json:"resources"` Resources []CrossNamespaceObjectReference `json:"resources"`
// SecretRef specifies the Secret containing the token used // SecretRef specifies the Secret containing the token used
// to validate the payload authenticity. // to validate the payload authenticity.
@ -129,9 +127,10 @@ func (in *Receiver) GetInterval() time.Duration {
} }
// +genclient // +genclient
// +genclient:Namespaced
// +kubebuilder:storageversion
// +kubebuilder:object:root=true // +kubebuilder:object:root=true
// +kubebuilder:subresource:status // +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="Age",type="date",JSONPath=".metadata.creationTimestamp",description=""
// +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].status",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="" // +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].message",description=""

View File

@ -1,7 +1,8 @@
//go:build !ignore_autogenerated //go:build !ignore_autogenerated
// +build !ignore_autogenerated
/* /*
Copyright 2023 The Flux authors Copyright 2022 The Flux authors
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -21,9 +22,8 @@ limitations under the License.
package v1beta2 package v1beta2
import ( import (
"github.com/fluxcd/notification-controller/api/v1"
"github.com/fluxcd/pkg/apis/meta" "github.com/fluxcd/pkg/apis/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime" runtime "k8s.io/apimachinery/pkg/runtime"
) )
@ -92,23 +92,11 @@ func (in *AlertSpec) DeepCopyInto(out *AlertSpec) {
out.ProviderRef = in.ProviderRef out.ProviderRef = in.ProviderRef
if in.EventSources != nil { if in.EventSources != nil {
in, out := &in.EventSources, &out.EventSources in, out := &in.EventSources, &out.EventSources
*out = make([]v1.CrossNamespaceObjectReference, len(*in)) *out = make([]CrossNamespaceObjectReference, len(*in))
for i := range *in { for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i]) (*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 { if in.ExclusionList != nil {
in, out := &in.ExclusionList, &out.ExclusionList in, out := &in.ExclusionList, &out.ExclusionList
*out = make([]string, len(*in)) *out = make([]string, len(*in))
@ -132,7 +120,7 @@ func (in *AlertStatus) DeepCopyInto(out *AlertStatus) {
out.ReconcileRequestStatus = in.ReconcileRequestStatus out.ReconcileRequestStatus = in.ReconcileRequestStatus
if in.Conditions != nil { if in.Conditions != nil {
in, out := &in.Conditions, &out.Conditions in, out := &in.Conditions, &out.Conditions
*out = make([]metav1.Condition, len(*in)) *out = make([]v1.Condition, len(*in))
for i := range *in { for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i]) (*in)[i].DeepCopyInto(&(*out)[i])
} }
@ -235,12 +223,12 @@ func (in *ProviderSpec) DeepCopyInto(out *ProviderSpec) {
*out = *in *out = *in
if in.Interval != nil { if in.Interval != nil {
in, out := &in.Interval, &out.Interval in, out := &in.Interval, &out.Interval
*out = new(metav1.Duration) *out = new(v1.Duration)
**out = **in **out = **in
} }
if in.Timeout != nil { if in.Timeout != nil {
in, out := &in.Timeout, &out.Timeout in, out := &in.Timeout, &out.Timeout
*out = new(metav1.Duration) *out = new(v1.Duration)
**out = **in **out = **in
} }
if in.SecretRef != nil { if in.SecretRef != nil {
@ -271,7 +259,7 @@ func (in *ProviderStatus) DeepCopyInto(out *ProviderStatus) {
out.ReconcileRequestStatus = in.ReconcileRequestStatus out.ReconcileRequestStatus = in.ReconcileRequestStatus
if in.Conditions != nil { if in.Conditions != nil {
in, out := &in.Conditions, &out.Conditions in, out := &in.Conditions, &out.Conditions
*out = make([]metav1.Condition, len(*in)) *out = make([]v1.Condition, len(*in))
for i := range *in { for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i]) (*in)[i].DeepCopyInto(&(*out)[i])
} }
@ -352,7 +340,7 @@ func (in *ReceiverSpec) DeepCopyInto(out *ReceiverSpec) {
*out = *in *out = *in
if in.Interval != nil { if in.Interval != nil {
in, out := &in.Interval, &out.Interval in, out := &in.Interval, &out.Interval
*out = new(metav1.Duration) *out = new(v1.Duration)
**out = **in **out = **in
} }
if in.Events != nil { if in.Events != nil {
@ -362,7 +350,7 @@ func (in *ReceiverSpec) DeepCopyInto(out *ReceiverSpec) {
} }
if in.Resources != nil { if in.Resources != nil {
in, out := &in.Resources, &out.Resources in, out := &in.Resources, &out.Resources
*out = make([]v1.CrossNamespaceObjectReference, len(*in)) *out = make([]CrossNamespaceObjectReference, len(*in))
for i := range *in { for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i]) (*in)[i].DeepCopyInto(&(*out)[i])
} }
@ -386,7 +374,7 @@ func (in *ReceiverStatus) DeepCopyInto(out *ReceiverStatus) {
out.ReconcileRequestStatus = in.ReconcileRequestStatus out.ReconcileRequestStatus = in.ReconcileRequestStatus
if in.Conditions != nil { if in.Conditions != nil {
in, out := &in.Conditions, &out.Conditions in, out := &in.Conditions, &out.Conditions
*out = make([]metav1.Condition, len(*in)) *out = make([]v1.Condition, len(*in))
for i := range *in { for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i]) (*in)[i].DeepCopyInto(&(*out)[i])
} }

View File

@ -1,104 +0,0 @@
/*
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{})
}

View File

@ -1,20 +0,0 @@
/*
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

View File

@ -1,33 +0,0 @@
/*
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
)

View File

@ -1,187 +0,0 @@
/*
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
}

View File

@ -1,224 +0,0 @@
//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
}

View File

@ -3,7 +3,8 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition kind: CustomResourceDefinition
metadata: metadata:
annotations: annotations:
controller-gen.kubebuilder.io/version: v0.16.1 controller-gen.kubebuilder.io/version: v0.11.1
creationTimestamp: null
name: alerts.notification.toolkit.fluxcd.io name: alerts.notification.toolkit.fluxcd.io
spec: spec:
group: notification.toolkit.fluxcd.io group: notification.toolkit.fluxcd.io
@ -24,27 +25,20 @@ spec:
- jsonPath: .status.conditions[?(@.type=="Ready")].message - jsonPath: .status.conditions[?(@.type=="Ready")].message
name: Status name: Status
type: string type: string
deprecated: true
deprecationWarning: v1beta1 Alert is deprecated, upgrade to v1beta3
name: v1beta1 name: v1beta1
schema: schema:
openAPIV3Schema: openAPIV3Schema:
description: Alert is the Schema for the alerts API description: Alert is the Schema for the alerts API
properties: properties:
apiVersion: apiVersion:
description: |- description: 'APIVersion defines the versioned schema of this representation
APIVersion defines the versioned schema of this representation of an object. of an object. Servers should convert recognized schemas to the latest
Servers should convert recognized schemas to the latest internal value, and internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
type: string type: string
kind: kind:
description: |- description: 'Kind is a string value representing the REST resource this
Kind is a string value representing the REST resource this object represents. object represents. Servers may infer this from the endpoint the client
Servers may infer this from the endpoint the client submits requests to. submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
type: string type: string
metadata: metadata:
type: object type: object
@ -54,8 +48,7 @@ spec:
properties: properties:
eventSeverity: eventSeverity:
default: info default: info
description: |- description: Filter events based on severity, defaults to ('info').
Filter events based on severity, defaults to ('info').
If set to 'info' no events will be filtered. If set to 'info' no events will be filtered.
enum: enum:
- info - info
@ -64,9 +57,8 @@ spec:
eventSources: eventSources:
description: Filter events based on the involved objects. description: Filter events based on the involved objects.
items: items:
description: |- description: CrossNamespaceObjectReference contains enough information
CrossNamespaceObjectReference contains enough information to let you locate the to let you locate the typed referenced object at cluster level
typed referenced object at cluster level
properties: properties:
apiVersion: apiVersion:
description: API version of the referent description: API version of the referent
@ -88,10 +80,11 @@ spec:
matchLabels: matchLabels:
additionalProperties: additionalProperties:
type: string type: string
description: |- description: MatchLabels is a map of {key,value} pairs. A single
MatchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels {key,value} in the matchLabels map is equivalent to an element
map is equivalent to an element of matchExpressions, whose key field is "key", the of matchExpressions, whose key field is "key", the operator
operator is "In", and the values array contains only "value". The requirements are ANDed. is "In", and the values array contains only "value". The requirements
are ANDed.
type: object type: object
name: name:
description: Name of the referent description: Name of the referent
@ -104,7 +97,6 @@ spec:
minLength: 1 minLength: 1
type: string type: string
required: required:
- kind
- name - name
type: object type: object
type: array type: array
@ -127,9 +119,8 @@ spec:
description: Short description of the impact and affected cluster. description: Short description of the impact and affected cluster.
type: string type: string
suspend: suspend:
description: |- description: This flag tells the controller to suspend subsequent
This flag tells the controller to suspend subsequent events dispatching. events dispatching. Defaults to false.
Defaults to false.
type: boolean type: boolean
required: required:
- eventSources - eventSources
@ -142,35 +133,43 @@ spec:
properties: properties:
conditions: conditions:
items: items:
description: Condition contains details for one aspect of the current description: "Condition contains details for one aspect of the current
state of this API Resource. 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 }"
properties: properties:
lastTransitionTime: lastTransitionTime:
description: |- description: lastTransitionTime is the last time the condition
lastTransitionTime is the last time the condition transitioned from one status to another. transitioned from one status to another. This should be when
This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. the underlying condition changed. If that is not known, then
using the time when the API field changed is acceptable.
format: date-time format: date-time
type: string type: string
message: message:
description: |- description: message is a human readable message indicating
message is a human readable message indicating details about the transition. details about the transition. This may be an empty string.
This may be an empty string.
maxLength: 32768 maxLength: 32768
type: string type: string
observedGeneration: observedGeneration:
description: |- description: observedGeneration represents the .metadata.generation
observedGeneration represents the .metadata.generation that the condition was set based upon. that the condition was set based upon. For instance, if .metadata.generation
For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date is currently 12, but the .status.conditions[x].observedGeneration
with respect to the current state of the instance. is 9, the condition is out of date with respect to the current
state of the instance.
format: int64 format: int64
minimum: 0 minimum: 0
type: integer type: integer
reason: reason:
description: |- description: reason contains a programmatic identifier indicating
reason contains a programmatic identifier indicating the reason for the condition's last transition. the reason for the condition's last transition. Producers
Producers of specific condition types may define expected values and meanings for this field, of specific condition types may define expected values and
and whether the values are considered a guaranteed API. meanings for this field, and whether the values are considered
The value should be a CamelCase string. a guaranteed API. The value should be a CamelCase string.
This field may not be empty. This field may not be empty.
maxLength: 1024 maxLength: 1024
minLength: 1 minLength: 1
@ -185,6 +184,10 @@ spec:
type: string type: string
type: type:
description: type of condition in CamelCase or in foo.example.com/CamelCase. 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 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])$ 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 type: string
@ -216,27 +219,20 @@ spec:
- jsonPath: .status.conditions[?(@.type=="Ready")].message - jsonPath: .status.conditions[?(@.type=="Ready")].message
name: Status name: Status
type: string type: string
deprecated: true
deprecationWarning: v1beta2 Alert is deprecated, upgrade to v1beta3
name: v1beta2 name: v1beta2
schema: schema:
openAPIV3Schema: openAPIV3Schema:
description: Alert is the Schema for the alerts API description: Alert is the Schema for the alerts API
properties: properties:
apiVersion: apiVersion:
description: |- description: 'APIVersion defines the versioned schema of this representation
APIVersion defines the versioned schema of this representation of an object. of an object. Servers should convert recognized schemas to the latest
Servers should convert recognized schemas to the latest internal value, and internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
type: string type: string
kind: kind:
description: |- description: 'Kind is a string value representing the REST resource this
Kind is a string value representing the REST resource this object represents. object represents. Servers may infer this from the endpoint the client
Servers may infer this from the endpoint the client submits requests to. submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
type: string type: string
metadata: metadata:
type: object type: object
@ -244,39 +240,26 @@ spec:
description: AlertSpec defines an alerting rule for events involving a description: AlertSpec defines an alerting rule for events involving a
list of objects. list of objects.
properties: 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: eventSeverity:
default: info default: info
description: |- description: EventSeverity specifies how to filter events based on
EventSeverity specifies how to filter events based on severity. severity. If set to 'info' no events will be filtered.
If set to 'info' no events will be filtered.
enum: enum:
- info - info
- error - error
type: string type: string
eventSources: eventSources:
description: |- description: EventSources specifies how to filter events based on
EventSources specifies how to filter events based the involved object kind, name and namespace.
on the involved object kind, name and namespace.
items: items:
description: |- description: CrossNamespaceObjectReference contains enough information
CrossNamespaceObjectReference contains enough information to let you locate the to let you locate the typed referenced object at cluster level
typed referenced object at cluster level
properties: properties:
apiVersion: apiVersion:
description: API version of the referent description: API version of the referent.
type: string type: string
kind: kind:
description: Kind of the referent description: Kind of the referent.
enum: enum:
- Bucket - Bucket
- GitRepository - GitRepository
@ -292,43 +275,32 @@ spec:
matchLabels: matchLabels:
additionalProperties: additionalProperties:
type: string type: string
description: |- description: MatchLabels is a map of {key,value} pairs. A single
MatchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels {key,value} in the matchLabels map is equivalent to an element
map is equivalent to an element of matchExpressions, whose key field is "key", the of matchExpressions, whose key field is "key", the operator
operator is "In", and the values array contains only "value". The requirements are ANDed. is "In", and the values array contains only "value". The requirements
MatchLabels requires the name to be set to `*`. are ANDed.
type: object type: object
name: name:
description: |- description: Name of the referent.
Name of the referent maxLength: 53
If multiple resources are targeted `*` may be set.
maxLength: 253
minLength: 1 minLength: 1
type: string type: string
namespace: namespace:
description: Namespace of the referent description: Namespace of the referent.
maxLength: 253 maxLength: 53
minLength: 1 minLength: 1
type: string type: string
required: required:
- kind
- name - name
type: object type: object
type: array type: array
exclusionList: exclusionList:
description: |- description: ExclusionList specifies a list of Golang regular expressions
ExclusionList specifies a list of Golang regular expressions
to be used for excluding messages. to be used for excluding messages.
items: items:
type: string type: string
type: array type: array
inclusionList:
description: |-
InclusionList specifies a list of Golang regular expressions
to be used for including messages.
items:
type: string
type: array
providerRef: providerRef:
description: ProviderRef specifies which Provider this Alert should description: ProviderRef specifies which Provider this Alert should
use. use.
@ -345,9 +317,8 @@ spec:
maxLength: 255 maxLength: 255
type: string type: string
suspend: suspend:
description: |- description: Suspend tells the controller to suspend subsequent events
Suspend tells the controller to suspend subsequent handling for this Alert.
events handling for this Alert.
type: boolean type: boolean
required: required:
- eventSources - eventSources
@ -361,35 +332,43 @@ spec:
conditions: conditions:
description: Conditions holds the conditions for the Alert. description: Conditions holds the conditions for the Alert.
items: items:
description: Condition contains details for one aspect of the current description: "Condition contains details for one aspect of the current
state of this API Resource. 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 }"
properties: properties:
lastTransitionTime: lastTransitionTime:
description: |- description: lastTransitionTime is the last time the condition
lastTransitionTime is the last time the condition transitioned from one status to another. transitioned from one status to another. This should be when
This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. the underlying condition changed. If that is not known, then
using the time when the API field changed is acceptable.
format: date-time format: date-time
type: string type: string
message: message:
description: |- description: message is a human readable message indicating
message is a human readable message indicating details about the transition. details about the transition. This may be an empty string.
This may be an empty string.
maxLength: 32768 maxLength: 32768
type: string type: string
observedGeneration: observedGeneration:
description: |- description: observedGeneration represents the .metadata.generation
observedGeneration represents the .metadata.generation that the condition was set based upon. that the condition was set based upon. For instance, if .metadata.generation
For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date is currently 12, but the .status.conditions[x].observedGeneration
with respect to the current state of the instance. is 9, the condition is out of date with respect to the current
state of the instance.
format: int64 format: int64
minimum: 0 minimum: 0
type: integer type: integer
reason: reason:
description: |- description: reason contains a programmatic identifier indicating
reason contains a programmatic identifier indicating the reason for the condition's last transition. the reason for the condition's last transition. Producers
Producers of specific condition types may define expected values and meanings for this field, of specific condition types may define expected values and
and whether the values are considered a guaranteed API. meanings for this field, and whether the values are considered
The value should be a CamelCase string. a guaranteed API. The value should be a CamelCase string.
This field may not be empty. This field may not be empty.
maxLength: 1024 maxLength: 1024
minLength: 1 minLength: 1
@ -404,6 +383,10 @@ spec:
type: string type: string
type: type:
description: type of condition in CamelCase or in foo.example.com/CamelCase. 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 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])$ 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 type: string
@ -416,10 +399,9 @@ spec:
type: object type: object
type: array type: array
lastHandledReconcileAt: lastHandledReconcileAt:
description: |- description: LastHandledReconcileAt holds the value of the most recent
LastHandledReconcileAt holds the value of the most recent reconcile request value, so a change of the annotation value can
reconcile request value, so a change of the annotation value be detected.
can be detected.
type: string type: string
observedGeneration: observedGeneration:
description: ObservedGeneration is the last observed generation. description: ObservedGeneration is the last observed generation.
@ -428,150 +410,6 @@ spec:
type: object type: object
type: object type: object
served: true served: true
storage: false storage: true
subresources: subresources:
status: {} 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: {}

View File

@ -3,7 +3,8 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition kind: CustomResourceDefinition
metadata: metadata:
annotations: annotations:
controller-gen.kubebuilder.io/version: v0.16.1 controller-gen.kubebuilder.io/version: v0.11.1
creationTimestamp: null
name: providers.notification.toolkit.fluxcd.io name: providers.notification.toolkit.fluxcd.io
spec: spec:
group: notification.toolkit.fluxcd.io group: notification.toolkit.fluxcd.io
@ -24,27 +25,20 @@ spec:
- jsonPath: .status.conditions[?(@.type=="Ready")].message - jsonPath: .status.conditions[?(@.type=="Ready")].message
name: Status name: Status
type: string type: string
deprecated: true
deprecationWarning: v1beta1 Provider is deprecated, upgrade to v1beta3
name: v1beta1 name: v1beta1
schema: schema:
openAPIV3Schema: openAPIV3Schema:
description: Provider is the Schema for the providers API description: Provider is the Schema for the providers API
properties: properties:
apiVersion: apiVersion:
description: |- description: 'APIVersion defines the versioned schema of this representation
APIVersion defines the versioned schema of this representation of an object. of an object. Servers should convert recognized schemas to the latest
Servers should convert recognized schemas to the latest internal value, and internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
type: string type: string
kind: kind:
description: |- description: 'Kind is a string value representing the REST resource this
Kind is a string value representing the REST resource this object represents. object represents. Servers may infer this from the endpoint the client
Servers may infer this from the endpoint the client submits requests to. submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
type: string type: string
metadata: metadata:
type: object type: object
@ -56,8 +50,7 @@ spec:
pattern: ^(http|https):// pattern: ^(http|https)://
type: string type: string
certSecretRef: certSecretRef:
description: |- description: CertSecretRef can be given the name of a secret containing
CertSecretRef can be given the name of a secret containing
a PEM-encoded CA certificate (`caFile`) a PEM-encoded CA certificate (`caFile`)
properties: properties:
name: name:
@ -74,8 +67,7 @@ spec:
pattern: ^(http|https):// pattern: ^(http|https)://
type: string type: string
secretRef: secretRef:
description: |- description: Secret reference containing the provider webhook URL
Secret reference containing the provider webhook URL
using "address" as data key using "address" as data key
properties: properties:
name: name:
@ -85,9 +77,8 @@ spec:
- name - name
type: object type: object
suspend: suspend:
description: |- description: This flag tells the controller to suspend subsequent
This flag tells the controller to suspend subsequent events handling. events handling. Defaults to false.
Defaults to false.
type: boolean type: boolean
timeout: timeout:
description: Timeout for sending alerts to the provider. description: Timeout for sending alerts to the provider.
@ -131,35 +122,43 @@ spec:
properties: properties:
conditions: conditions:
items: items:
description: Condition contains details for one aspect of the current description: "Condition contains details for one aspect of the current
state of this API Resource. 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 }"
properties: properties:
lastTransitionTime: lastTransitionTime:
description: |- description: lastTransitionTime is the last time the condition
lastTransitionTime is the last time the condition transitioned from one status to another. transitioned from one status to another. This should be when
This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. the underlying condition changed. If that is not known, then
using the time when the API field changed is acceptable.
format: date-time format: date-time
type: string type: string
message: message:
description: |- description: message is a human readable message indicating
message is a human readable message indicating details about the transition. details about the transition. This may be an empty string.
This may be an empty string.
maxLength: 32768 maxLength: 32768
type: string type: string
observedGeneration: observedGeneration:
description: |- description: observedGeneration represents the .metadata.generation
observedGeneration represents the .metadata.generation that the condition was set based upon. that the condition was set based upon. For instance, if .metadata.generation
For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date is currently 12, but the .status.conditions[x].observedGeneration
with respect to the current state of the instance. is 9, the condition is out of date with respect to the current
state of the instance.
format: int64 format: int64
minimum: 0 minimum: 0
type: integer type: integer
reason: reason:
description: |- description: reason contains a programmatic identifier indicating
reason contains a programmatic identifier indicating the reason for the condition's last transition. the reason for the condition's last transition. Producers
Producers of specific condition types may define expected values and meanings for this field, of specific condition types may define expected values and
and whether the values are considered a guaranteed API. meanings for this field, and whether the values are considered
The value should be a CamelCase string. a guaranteed API. The value should be a CamelCase string.
This field may not be empty. This field may not be empty.
maxLength: 1024 maxLength: 1024
minLength: 1 minLength: 1
@ -174,6 +173,10 @@ spec:
type: string type: string
type: type:
description: type of condition in CamelCase or in foo.example.com/CamelCase. 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 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])$ 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 type: string
@ -205,27 +208,20 @@ spec:
- jsonPath: .status.conditions[?(@.type=="Ready")].message - jsonPath: .status.conditions[?(@.type=="Ready")].message
name: Status name: Status
type: string type: string
deprecated: true
deprecationWarning: v1beta2 Provider is deprecated, upgrade to v1beta3
name: v1beta2 name: v1beta2
schema: schema:
openAPIV3Schema: openAPIV3Schema:
description: Provider is the Schema for the providers API. description: Provider is the Schema for the providers API.
properties: properties:
apiVersion: apiVersion:
description: |- description: 'APIVersion defines the versioned schema of this representation
APIVersion defines the versioned schema of this representation of an object. of an object. Servers should convert recognized schemas to the latest
Servers should convert recognized schemas to the latest internal value, and internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
type: string type: string
kind: kind:
description: |- description: 'Kind is a string value representing the REST resource this
Kind is a string value representing the REST resource this object represents. object represents. Servers may infer this from the endpoint the client
Servers may infer this from the endpoint the client submits requests to. submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
type: string type: string
metadata: metadata:
type: object type: object
@ -233,20 +229,14 @@ spec:
description: ProviderSpec defines the desired state of the Provider. description: ProviderSpec defines the desired state of the Provider.
properties: properties:
address: address:
description: |- description: Address specifies the HTTP/S incoming webhook address
Address specifies the endpoint, in a generic sense, to where alerts are sent. of this Provider.
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 maxLength: 2048
pattern: ^(http|https)://.*$
type: string type: string
certSecretRef: certSecretRef:
description: |- description: CertSecretRef specifies the Secret containing a PEM-encoded
CertSecretRef specifies the Secret containing CA certificate (`caFile`).
a PEM-encoded CA certificate (in the `ca.crt` key).
Note: Support for the `caFile` key has
been deprecated.
properties: properties:
name: name:
description: Name of the referent. description: Name of the referent.
@ -270,8 +260,7 @@ spec:
pattern: ^(http|https)://.*$ pattern: ^(http|https)://.*$
type: string type: string
secretRef: secretRef:
description: |- description: SecretRef specifies the Secret containing the authentication
SecretRef specifies the Secret containing the authentication
credentials for this Provider. credentials for this Provider.
properties: properties:
name: name:
@ -281,9 +270,8 @@ spec:
- name - name
type: object type: object
suspend: suspend:
description: |- description: Suspend tells the controller to suspend subsequent events
Suspend tells the controller to suspend subsequent handling for this Provider.
events handling for this Provider.
type: boolean type: boolean
timeout: timeout:
description: Timeout for sending alerts to the Provider. description: Timeout for sending alerts to the Provider.
@ -301,11 +289,9 @@ spec:
- github - github
- gitlab - gitlab
- gitea - gitea
- bitbucketserver
- bitbucket - bitbucket
- azuredevops - azuredevops
- googlechat - googlechat
- googlepubsub
- webex - webex
- sentry - sentry
- azureeventhub - azureeventhub
@ -316,8 +302,6 @@ spec:
- alertmanager - alertmanager
- grafana - grafana
- githubdispatch - githubdispatch
- pagerduty
- datadog
type: string type: string
username: username:
description: Username specifies the name under which events are posted. description: Username specifies the name under which events are posted.
@ -334,35 +318,43 @@ spec:
conditions: conditions:
description: Conditions holds the conditions for the Provider. description: Conditions holds the conditions for the Provider.
items: items:
description: Condition contains details for one aspect of the current description: "Condition contains details for one aspect of the current
state of this API Resource. 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 }"
properties: properties:
lastTransitionTime: lastTransitionTime:
description: |- description: lastTransitionTime is the last time the condition
lastTransitionTime is the last time the condition transitioned from one status to another. transitioned from one status to another. This should be when
This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. the underlying condition changed. If that is not known, then
using the time when the API field changed is acceptable.
format: date-time format: date-time
type: string type: string
message: message:
description: |- description: message is a human readable message indicating
message is a human readable message indicating details about the transition. details about the transition. This may be an empty string.
This may be an empty string.
maxLength: 32768 maxLength: 32768
type: string type: string
observedGeneration: observedGeneration:
description: |- description: observedGeneration represents the .metadata.generation
observedGeneration represents the .metadata.generation that the condition was set based upon. that the condition was set based upon. For instance, if .metadata.generation
For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date is currently 12, but the .status.conditions[x].observedGeneration
with respect to the current state of the instance. is 9, the condition is out of date with respect to the current
state of the instance.
format: int64 format: int64
minimum: 0 minimum: 0
type: integer type: integer
reason: reason:
description: |- description: reason contains a programmatic identifier indicating
reason contains a programmatic identifier indicating the reason for the condition's last transition. the reason for the condition's last transition. Producers
Producers of specific condition types may define expected values and meanings for this field, of specific condition types may define expected values and
and whether the values are considered a guaranteed API. meanings for this field, and whether the values are considered
The value should be a CamelCase string. a guaranteed API. The value should be a CamelCase string.
This field may not be empty. This field may not be empty.
maxLength: 1024 maxLength: 1024
minLength: 1 minLength: 1
@ -377,6 +369,10 @@ spec:
type: string type: string
type: type:
description: type of condition in CamelCase or in foo.example.com/CamelCase. 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 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])$ 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 type: string
@ -389,10 +385,9 @@ spec:
type: object type: object
type: array type: array
lastHandledReconcileAt: lastHandledReconcileAt:
description: |- description: LastHandledReconcileAt holds the value of the most recent
LastHandledReconcileAt holds the value of the most recent reconcile request value, so a change of the annotation value can
reconcile request value, so a change of the annotation value be detected.
can be detected.
type: string type: string
observedGeneration: observedGeneration:
description: ObservedGeneration is the last reconciled generation. description: ObservedGeneration is the last reconciled generation.
@ -401,175 +396,6 @@ spec:
type: object type: object
type: object type: object
served: true served: true
storage: false storage: true
subresources: subresources:
status: {} 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: {}

View File

@ -3,7 +3,8 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition kind: CustomResourceDefinition
metadata: metadata:
annotations: annotations:
controller-gen.kubebuilder.io/version: v0.16.1 controller-gen.kubebuilder.io/version: v0.11.1
creationTimestamp: null
name: receivers.notification.toolkit.fluxcd.io name: receivers.notification.toolkit.fluxcd.io
spec: spec:
group: notification.toolkit.fluxcd.io group: notification.toolkit.fluxcd.io
@ -24,258 +25,20 @@ spec:
- jsonPath: .status.conditions[?(@.type=="Ready")].message - jsonPath: .status.conditions[?(@.type=="Ready")].message
name: Status name: Status
type: string type: string
name: v1
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 the Receiver.
properties:
events:
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
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
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 name: v1beta1
schema: schema:
openAPIV3Schema: openAPIV3Schema:
description: Receiver is the Schema for the receivers API description: Receiver is the Schema for the receivers API
properties: properties:
apiVersion: apiVersion:
description: |- description: 'APIVersion defines the versioned schema of this representation
APIVersion defines the versioned schema of this representation of an object. of an object. Servers should convert recognized schemas to the latest
Servers should convert recognized schemas to the latest internal value, and internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
type: string type: string
kind: kind:
description: |- description: 'Kind is a string value representing the REST resource this
Kind is a string value representing the REST resource this object represents. object represents. Servers may infer this from the endpoint the client
Servers may infer this from the endpoint the client submits requests to. submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
type: string type: string
metadata: metadata:
type: object type: object
@ -283,18 +46,16 @@ spec:
description: ReceiverSpec defines the desired state of Receiver description: ReceiverSpec defines the desired state of Receiver
properties: properties:
events: events:
description: |- description: A list of events to handle, e.g. 'push' for GitHub or
A list of events to handle, 'Push Hook' for GitLab.
e.g. 'push' for GitHub or 'Push Hook' for GitLab.
items: items:
type: string type: string
type: array type: array
resources: resources:
description: A list of resources to be notified about changes. description: A list of resources to be notified about changes.
items: items:
description: |- description: CrossNamespaceObjectReference contains enough information
CrossNamespaceObjectReference contains enough information to let you locate the to let you locate the typed referenced object at cluster level
typed referenced object at cluster level
properties: properties:
apiVersion: apiVersion:
description: API version of the referent description: API version of the referent
@ -316,10 +77,11 @@ spec:
matchLabels: matchLabels:
additionalProperties: additionalProperties:
type: string type: string
description: |- description: MatchLabels is a map of {key,value} pairs. A single
MatchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels {key,value} in the matchLabels map is equivalent to an element
map is equivalent to an element of matchExpressions, whose key field is "key", the of matchExpressions, whose key field is "key", the operator
operator is "In", and the values array contains only "value". The requirements are ANDed. is "In", and the values array contains only "value". The requirements
are ANDed.
type: object type: object
name: name:
description: Name of the referent description: Name of the referent
@ -332,14 +94,12 @@ spec:
minLength: 1 minLength: 1
type: string type: string
required: required:
- kind
- name - name
type: object type: object
type: array type: array
secretRef: secretRef:
description: |- description: Secret reference containing the token used to validate
Secret reference containing the token used the payload authenticity
to validate the payload authenticity
properties: properties:
name: name:
description: Name of the referent. description: Name of the referent.
@ -348,14 +108,12 @@ spec:
- name - name
type: object type: object
suspend: suspend:
description: |- description: This flag tells the controller to suspend subsequent
This flag tells the controller to suspend subsequent events handling. events handling. Defaults to false.
Defaults to false.
type: boolean type: boolean
type: type:
description: |- description: Type of webhook sender, used to determine the validation
Type of webhook sender, used to determine procedure and payload deserialization.
the validation procedure and payload deserialization.
enum: enum:
- generic - generic
- generic-hmac - generic-hmac
@ -371,7 +129,6 @@ spec:
type: string type: string
required: required:
- resources - resources
- secretRef
- type - type
type: object type: object
status: status:
@ -381,35 +138,43 @@ spec:
properties: properties:
conditions: conditions:
items: items:
description: Condition contains details for one aspect of the current description: "Condition contains details for one aspect of the current
state of this API Resource. 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 }"
properties: properties:
lastTransitionTime: lastTransitionTime:
description: |- description: lastTransitionTime is the last time the condition
lastTransitionTime is the last time the condition transitioned from one status to another. transitioned from one status to another. This should be when
This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. the underlying condition changed. If that is not known, then
using the time when the API field changed is acceptable.
format: date-time format: date-time
type: string type: string
message: message:
description: |- description: message is a human readable message indicating
message is a human readable message indicating details about the transition. details about the transition. This may be an empty string.
This may be an empty string.
maxLength: 32768 maxLength: 32768
type: string type: string
observedGeneration: observedGeneration:
description: |- description: observedGeneration represents the .metadata.generation
observedGeneration represents the .metadata.generation that the condition was set based upon. that the condition was set based upon. For instance, if .metadata.generation
For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date is currently 12, but the .status.conditions[x].observedGeneration
with respect to the current state of the instance. is 9, the condition is out of date with respect to the current
state of the instance.
format: int64 format: int64
minimum: 0 minimum: 0
type: integer type: integer
reason: reason:
description: |- description: reason contains a programmatic identifier indicating
reason contains a programmatic identifier indicating the reason for the condition's last transition. the reason for the condition's last transition. Producers
Producers of specific condition types may define expected values and meanings for this field, of specific condition types may define expected values and
and whether the values are considered a guaranteed API. meanings for this field, and whether the values are considered
The value should be a CamelCase string. a guaranteed API. The value should be a CamelCase string.
This field may not be empty. This field may not be empty.
maxLength: 1024 maxLength: 1024
minLength: 1 minLength: 1
@ -424,6 +189,10 @@ spec:
type: string type: string
type: type:
description: type of condition in CamelCase or in foo.example.com/CamelCase. 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 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])$ 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 type: string
@ -440,9 +209,7 @@ spec:
format: int64 format: int64
type: integer type: integer
url: url:
description: |- description: Generated webhook URL in the format of '/hook/sha256sum(token+name+namespace)'.
Generated webhook URL in the format
of '/hook/sha256sum(token+name+namespace)'.
type: string type: string
type: object type: object
type: object type: object
@ -460,27 +227,20 @@ spec:
- jsonPath: .status.conditions[?(@.type=="Ready")].message - jsonPath: .status.conditions[?(@.type=="Ready")].message
name: Status name: Status
type: string type: string
deprecated: true
deprecationWarning: v1beta2 Receiver is deprecated, upgrade to v1
name: v1beta2 name: v1beta2
schema: schema:
openAPIV3Schema: openAPIV3Schema:
description: Receiver is the Schema for the receivers API. description: Receiver is the Schema for the receivers API.
properties: properties:
apiVersion: apiVersion:
description: |- description: 'APIVersion defines the versioned schema of this representation
APIVersion defines the versioned schema of this representation of an object. of an object. Servers should convert recognized schemas to the latest
Servers should convert recognized schemas to the latest internal value, and internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
type: string type: string
kind: kind:
description: |- description: 'Kind is a string value representing the REST resource this
Kind is a string value representing the REST resource this object represents. object represents. Servers may infer this from the endpoint the client
Servers may infer this from the endpoint the client submits requests to. submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
type: string type: string
metadata: metadata:
type: object type: object
@ -488,9 +248,8 @@ spec:
description: ReceiverSpec defines the desired state of the Receiver. description: ReceiverSpec defines the desired state of the Receiver.
properties: properties:
events: events:
description: |- description: Events specifies the list of event types to handle, e.g.
Events specifies the list of event types to handle, 'push' for GitHub or 'Push Hook' for GitLab.
e.g. 'push' for GitHub or 'Push Hook' for GitLab.
items: items:
type: string type: string
type: array type: array
@ -502,15 +261,14 @@ spec:
resources: resources:
description: A list of resources to be notified about changes. description: A list of resources to be notified about changes.
items: items:
description: |- description: CrossNamespaceObjectReference contains enough information
CrossNamespaceObjectReference contains enough information to let you locate the to let you locate the typed referenced object at cluster level
typed referenced object at cluster level
properties: properties:
apiVersion: apiVersion:
description: API version of the referent description: API version of the referent.
type: string type: string
kind: kind:
description: Kind of the referent description: Kind of the referent.
enum: enum:
- Bucket - Bucket
- GitRepository - GitRepository
@ -526,32 +284,28 @@ spec:
matchLabels: matchLabels:
additionalProperties: additionalProperties:
type: string type: string
description: |- description: MatchLabels is a map of {key,value} pairs. A single
MatchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels {key,value} in the matchLabels map is equivalent to an element
map is equivalent to an element of matchExpressions, whose key field is "key", the of matchExpressions, whose key field is "key", the operator
operator is "In", and the values array contains only "value". The requirements are ANDed. is "In", and the values array contains only "value". The requirements
MatchLabels requires the name to be set to `*`. are ANDed.
type: object type: object
name: name:
description: |- description: Name of the referent.
Name of the referent maxLength: 53
If multiple resources are targeted `*` may be set.
maxLength: 253
minLength: 1 minLength: 1
type: string type: string
namespace: namespace:
description: Namespace of the referent description: Namespace of the referent.
maxLength: 253 maxLength: 53
minLength: 1 minLength: 1
type: string type: string
required: required:
- kind
- name - name
type: object type: object
type: array type: array
secretRef: secretRef:
description: |- description: SecretRef specifies the Secret containing the token used
SecretRef specifies the Secret containing the token used
to validate the payload authenticity. to validate the payload authenticity.
properties: properties:
name: name:
@ -561,14 +315,12 @@ spec:
- name - name
type: object type: object
suspend: suspend:
description: |- description: Suspend tells the controller to suspend subsequent events
Suspend tells the controller to suspend subsequent handling for this receiver.
events handling for this receiver.
type: boolean type: boolean
type: type:
description: |- description: Type of webhook sender, used to determine the validation
Type of webhook sender, used to determine procedure and payload deserialization.
the validation procedure and payload deserialization.
enum: enum:
- generic - generic
- generic-hmac - generic-hmac
@ -584,7 +336,6 @@ spec:
type: string type: string
required: required:
- resources - resources
- secretRef
- type - type
type: object type: object
status: status:
@ -595,35 +346,43 @@ spec:
conditions: conditions:
description: Conditions holds the conditions for the Receiver. description: Conditions holds the conditions for the Receiver.
items: items:
description: Condition contains details for one aspect of the current description: "Condition contains details for one aspect of the current
state of this API Resource. 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 }"
properties: properties:
lastTransitionTime: lastTransitionTime:
description: |- description: lastTransitionTime is the last time the condition
lastTransitionTime is the last time the condition transitioned from one status to another. transitioned from one status to another. This should be when
This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. the underlying condition changed. If that is not known, then
using the time when the API field changed is acceptable.
format: date-time format: date-time
type: string type: string
message: message:
description: |- description: message is a human readable message indicating
message is a human readable message indicating details about the transition. details about the transition. This may be an empty string.
This may be an empty string.
maxLength: 32768 maxLength: 32768
type: string type: string
observedGeneration: observedGeneration:
description: |- description: observedGeneration represents the .metadata.generation
observedGeneration represents the .metadata.generation that the condition was set based upon. that the condition was set based upon. For instance, if .metadata.generation
For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date is currently 12, but the .status.conditions[x].observedGeneration
with respect to the current state of the instance. is 9, the condition is out of date with respect to the current
state of the instance.
format: int64 format: int64
minimum: 0 minimum: 0
type: integer type: integer
reason: reason:
description: |- description: reason contains a programmatic identifier indicating
reason contains a programmatic identifier indicating the reason for the condition's last transition. the reason for the condition's last transition. Producers
Producers of specific condition types may define expected values and meanings for this field, of specific condition types may define expected values and
and whether the values are considered a guaranteed API. meanings for this field, and whether the values are considered
The value should be a CamelCase string. a guaranteed API. The value should be a CamelCase string.
This field may not be empty. This field may not be empty.
maxLength: 1024 maxLength: 1024
minLength: 1 minLength: 1
@ -638,6 +397,10 @@ spec:
type: string type: string
type: type:
description: type of condition in CamelCase or in foo.example.com/CamelCase. 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 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])$ 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 type: string
@ -650,10 +413,9 @@ spec:
type: object type: object
type: array type: array
lastHandledReconcileAt: lastHandledReconcileAt:
description: |- description: LastHandledReconcileAt holds the value of the most recent
LastHandledReconcileAt holds the value of the most recent reconcile request value, so a change of the annotation value can
reconcile request value, so a change of the annotation value be detected.
can be detected.
type: string type: string
observedGeneration: observedGeneration:
description: ObservedGeneration is the last observed generation of description: ObservedGeneration is the last observed generation of
@ -661,19 +423,17 @@ spec:
format: int64 format: int64
type: integer type: integer
url: url:
description: |- description: 'URL is the generated incoming webhook address in the
URL is the generated incoming webhook address in the format format of ''/hook/sha256sum(token+name+namespace)''. Deprecated:
of '/hook/sha256sum(token+name+namespace)'. Replaced by WebhookPath.'
Deprecated: Replaced by WebhookPath.
type: string type: string
webhookPath: webhookPath:
description: |- description: WebhookPath is the generated incoming webhook address
WebhookPath is the generated incoming webhook address in the format in the format of '/hook/sha256sum(token+name+namespace)'.
of '/hook/sha256sum(token+name+namespace)'.
type: string type: string
type: object type: object
type: object type: object
served: true served: true
storage: false storage: true
subresources: subresources:
status: {} status: {}

View File

@ -6,4 +6,4 @@ resources:
images: images:
- name: fluxcd/notification-controller - name: fluxcd/notification-controller
newName: fluxcd/notification-controller newName: fluxcd/notification-controller
newTag: v1.6.0 newTag: v0.32.1

View File

@ -2,6 +2,7 @@
apiVersion: rbac.authorization.k8s.io/v1 apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole kind: ClusterRole
metadata: metadata:
creationTimestamp: null
name: manager-role name: manager-role
rules: rules:
- apiGroups: - apiGroups:
@ -19,12 +20,6 @@ rules:
- get - get
- list - list
- watch - watch
- apiGroups:
- ""
resources:
- serviceaccounts/token
verbs:
- create
- apiGroups: - apiGroups:
- image.fluxcd.io - image.fluxcd.io
resources: resources:
@ -45,7 +40,45 @@ rules:
- notification.toolkit.fluxcd.io - notification.toolkit.fluxcd.io
resources: resources:
- alerts - 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 - 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 - receivers
verbs: verbs:
- create - create
@ -67,9 +100,6 @@ rules:
- source.fluxcd.io - source.fluxcd.io
resources: resources:
- buckets - buckets
- gitrepositories
- helmrepositories
- ocirepositories
verbs: verbs:
- get - get
- list - list
@ -80,8 +110,53 @@ rules:
- source.fluxcd.io - source.fluxcd.io
resources: resources:
- buckets/status - buckets/status
verbs:
- get
- apiGroups:
- source.fluxcd.io
resources:
- gitrepositories
verbs:
- get
- list
- patch
- update
- watch
- apiGroups:
- source.fluxcd.io
resources:
- gitrepositories/status - gitrepositories/status
verbs:
- get
- apiGroups:
- source.fluxcd.io
resources:
- helmrepositories
verbs:
- get
- list
- patch
- update
- watch
- apiGroups:
- source.fluxcd.io
resources:
- helmrepositories/status - helmrepositories/status
verbs:
- get
- apiGroups:
- source.fluxcd.io
resources:
- ocirepositories
verbs:
- get
- list
- patch
- update
- watch
- apiGroups:
- source.fluxcd.io
resources:
- ocirepositories/status - ocirepositories/status
verbs: verbs:
- get - get

View File

@ -1,4 +1,4 @@
apiVersion: notification.toolkit.fluxcd.io/v1 apiVersion: notification.toolkit.fluxcd.io/v1beta2
kind: Receiver kind: Receiver
metadata: metadata:
name: receiver-sample name: receiver-sample

View File

@ -1,13 +0,0 @@
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: '*'

View File

@ -1,34 +0,0 @@
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

8
config/testdata/provider.yaml vendored Normal file
View File

@ -0,0 +1,8 @@
---
apiVersion: notification.toolkit.fluxcd.io/v1beta1
kind: Provider
metadata:
name: status-defaults
spec:
type: generic

View File

@ -0,0 +1,5 @@
---
apiVersion: notification.toolkit.fluxcd.io/v1beta1
kind: Alert
metadata:
name: status-defaults

View File

@ -0,0 +1,4 @@
apiVersion: notification.toolkit.fluxcd.io/v1beta1
kind: Provider
metadata:
name: status-defaults

View File

@ -1,4 +1,4 @@
apiVersion: notification.toolkit.fluxcd.io/v1 apiVersion: notification.toolkit.fluxcd.io/v1beta1
kind: Receiver kind: Receiver
metadata: metadata:
name: status-defaults name: status-defaults

View File

@ -0,0 +1,262 @@
/*
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
}

View File

@ -0,0 +1,426 @@
/*
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
})
}
}

View File

@ -0,0 +1,321 @@
/*
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
}

View File

@ -0,0 +1,202 @@
/*
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())
})
}

View File

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
package controller package controllers
import ( import (
"context" "context"
@ -26,14 +26,13 @@ import (
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
kerrors "k8s.io/apimachinery/pkg/util/errors" kerrors "k8s.io/apimachinery/pkg/util/errors"
kuberecorder "k8s.io/client-go/tools/record" kuberecorder "k8s.io/client-go/tools/record"
"k8s.io/client-go/util/workqueue"
ctrl "sigs.k8s.io/controller-runtime" ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/builder" "sigs.k8s.io/controller-runtime/pkg/builder"
"sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller" "sigs.k8s.io/controller-runtime/pkg/controller"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
"sigs.k8s.io/controller-runtime/pkg/predicate" "sigs.k8s.io/controller-runtime/pkg/predicate"
"sigs.k8s.io/controller-runtime/pkg/reconcile" "sigs.k8s.io/controller-runtime/pkg/ratelimiter"
"github.com/fluxcd/pkg/apis/meta" "github.com/fluxcd/pkg/apis/meta"
"github.com/fluxcd/pkg/runtime/conditions" "github.com/fluxcd/pkg/runtime/conditions"
@ -41,8 +40,7 @@ import (
"github.com/fluxcd/pkg/runtime/patch" "github.com/fluxcd/pkg/runtime/patch"
"github.com/fluxcd/pkg/runtime/predicates" "github.com/fluxcd/pkg/runtime/predicates"
apiv1 "github.com/fluxcd/notification-controller/api/v1" apiv1 "github.com/fluxcd/notification-controller/api/v1beta2"
"github.com/fluxcd/notification-controller/internal/server"
) )
// ReceiverReconciler reconciles a Receiver object // ReceiverReconciler reconciles a Receiver object
@ -55,7 +53,8 @@ type ReceiverReconciler struct {
} }
type ReceiverReconcilerOptions struct { type ReceiverReconcilerOptions struct {
RateLimiter workqueue.TypedRateLimiter[reconcile.Request] MaxConcurrentReconciles int
RateLimiter ratelimiter.RateLimiter
} }
func (r *ReceiverReconciler) SetupWithManager(mgr ctrl.Manager) error { func (r *ReceiverReconciler) SetupWithManager(mgr ctrl.Manager) error {
@ -63,18 +62,15 @@ func (r *ReceiverReconciler) SetupWithManager(mgr ctrl.Manager) error {
} }
func (r *ReceiverReconciler) SetupWithManagerAndOptions(mgr ctrl.Manager, opts ReceiverReconcilerOptions) error { func (r *ReceiverReconciler) SetupWithManagerAndOptions(mgr ctrl.Manager, opts ReceiverReconcilerOptions) error {
// This index is used to list Receivers by their webhook path after the receiver server recoverPanic := true
// gets a request.
if err := mgr.GetFieldIndexer().IndexField(context.Background(), &apiv1.Receiver{},
server.WebhookPathIndexKey, server.IndexReceiverWebhookPath); err != nil {
return err
}
return ctrl.NewControllerManagedBy(mgr). return ctrl.NewControllerManagedBy(mgr).
For(&apiv1.Receiver{}, builder.WithPredicates( For(&apiv1.Receiver{}, builder.WithPredicates(
predicate.Or(predicate.GenerationChangedPredicate{}, predicates.ReconcileRequestedPredicate{}), predicate.Or(predicate.GenerationChangedPredicate{}, predicates.ReconcileRequestedPredicate{}),
)). )).
WithOptions(controller.Options{ WithOptions(controller.Options{
MaxConcurrentReconciles: opts.MaxConcurrentReconciles,
RateLimiter: opts.RateLimiter, RateLimiter: opts.RateLimiter,
RecoverPanic: &recoverPanic,
}). }).
Complete(r) Complete(r)
} }
@ -113,7 +109,9 @@ func (r *ReceiverReconciler) Reconcile(ctx context.Context, req ctrl.Request) (r
} }
// Record Prometheus metrics. // Record Prometheus metrics.
r.Metrics.RecordReadiness(ctx, obj)
r.Metrics.RecordDuration(ctx, obj, reconcileStart) r.Metrics.RecordDuration(ctx, obj, reconcileStart)
r.Metrics.RecordSuspend(ctx, obj, obj.Spec.Suspend)
// Emit warning event if the reconciliation failed. // Emit warning event if the reconciliation failed.
if retErr != nil { if retErr != nil {
@ -128,22 +126,18 @@ func (r *ReceiverReconciler) Reconcile(ctx context.Context, req ctrl.Request) (r
} }
}() }()
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) { if !controllerutil.ContainsFinalizer(obj, apiv1.NotificationFinalizer) {
controllerutil.AddFinalizer(obj, apiv1.NotificationFinalizer) controllerutil.AddFinalizer(obj, apiv1.NotificationFinalizer)
result = ctrl.Result{Requeue: true} result = ctrl.Result{Requeue: true}
return return
} }
if !obj.ObjectMeta.DeletionTimestamp.IsZero() {
controllerutil.RemoveFinalizer(obj, apiv1.NotificationFinalizer)
result = ctrl.Result{}
return
}
// Return early if the object is suspended. // Return early if the object is suspended.
if obj.Spec.Suspend { if obj.Spec.Suspend {
log.Info("Reconciliation is suspended for this object") log.Info("Reconciliation is suspended for this object")
@ -156,40 +150,27 @@ 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 // reconcile steps through the actual reconciliation tasks for the object, it returns early on the first step that
// produces an error. // produces an error.
func (r *ReceiverReconciler) reconcile(ctx context.Context, obj *apiv1.Receiver) (ctrl.Result, 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. // Mark the resource as under reconciliation.
conditions.MarkReconciling(obj, meta.ProgressingReason, "Reconciliation in progress") conditions.MarkReconciling(obj, meta.ProgressingReason, "Reconciliation in progress")
token, err := r.token(ctx, obj) token, err := r.token(ctx, obj)
if err != nil { if err != nil {
conditions.MarkFalse(obj, meta.ReadyCondition, apiv1.TokenNotFoundReason, "%s", err) conditions.MarkFalse(obj, meta.ReadyCondition, apiv1.TokenNotFoundReason, err.Error())
obj.Status.URL = ""
obj.Status.WebhookPath = "" obj.Status.WebhookPath = ""
return ctrl.Result{}, err return ctrl.Result{Requeue: true}, err
} }
webhookPath := obj.GetWebhookPath(token) webhookPath := obj.GetWebhookPath(token)
msg := fmt.Sprintf("Receiver initialized for path: %s", webhookPath) msg := fmt.Sprintf("Receiver initialized for path: %s", webhookPath)
// Mark the resource as ready and set the webhook path in status. // Mark the resource as ready and set the webhook path in status.
conditions.MarkTrue(obj, meta.ReadyCondition, meta.SucceededReason, "%s", msg) conditions.MarkTrue(obj, meta.ReadyCondition, meta.SucceededReason, msg)
if obj.Status.WebhookPath != webhookPath { if obj.Status.WebhookPath != webhookPath {
obj.Status.URL = webhookPath
obj.Status.WebhookPath = webhookPath obj.Status.WebhookPath = webhookPath
log.Info(msg) ctrl.LoggerFrom(ctx).Info(msg)
} }
return ctrl.Result{RequeueAfter: obj.GetInterval()}, nil return ctrl.Result{RequeueAfter: obj.GetInterval()}, nil

View File

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
package controller package controllers
import ( import (
"context" "context"
@ -31,8 +31,6 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/types" "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/client"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
logf "sigs.k8s.io/controller-runtime/pkg/log" logf "sigs.k8s.io/controller-runtime/pkg/log"
@ -41,47 +39,10 @@ import (
"github.com/fluxcd/pkg/runtime/conditions" "github.com/fluxcd/pkg/runtime/conditions"
"github.com/fluxcd/pkg/ssa" "github.com/fluxcd/pkg/ssa"
apiv1 "github.com/fluxcd/notification-controller/api/v1" apiv1 "github.com/fluxcd/notification-controller/api/v1beta2"
"github.com/fluxcd/notification-controller/internal/server" "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) { func TestReceiverReconciler_Reconcile(t *testing.T) {
g := NewWithT(t) g := NewWithT(t)
@ -141,46 +102,6 @@ func TestReceiverReconciler_Reconcile(t *testing.T) {
g.Expect(conditions.Has(resultR, meta.ReconcilingCondition)).To(BeFalse()) g.Expect(conditions.Has(resultR, meta.ReconcilingCondition)).To(BeFalse())
g.Expect(controllerutil.ContainsFinalizer(resultR, apiv1.NotificationFinalizer)).To(BeTrue()) 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) { t.Run("fails with secret not found error", func(t *testing.T) {
@ -276,9 +197,7 @@ func TestReceiverReconciler_EventHandler(t *testing.T) {
timeout := 30 * time.Second timeout := 30 * time.Second
resultR := &apiv1.Receiver{} resultR := &apiv1.Receiver{}
// Use the client from the manager as the server handler needs to list objects from the cache receiverServer := server.NewReceiverServer("127.0.0.1:56788", logf.Log, k8sClient)
// 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{ receiverMdlw := middleware.New(middleware.Config{
Recorder: prommetrics.NewRecorder(prommetrics.Config{ Recorder: prommetrics.NewRecorder(prommetrics.Config{
Prefix: "gotk_receiver", Prefix: "gotk_receiver",
@ -357,6 +276,7 @@ func TestReceiverReconciler_EventHandler(t *testing.T) {
return conditions.IsReady(resultR) return conditions.IsReady(resultR)
}, timeout, time.Second).Should(BeTrue()) }, timeout, time.Second).Should(BeTrue())
g.Expect(resultR.Status.URL).To(BeIdenticalTo(address))
g.Expect(resultR.Status.WebhookPath).To(BeIdenticalTo(address)) g.Expect(resultR.Status.WebhookPath).To(BeIdenticalTo(address))
g.Expect(conditions.GetMessage(resultR, meta.ReadyCondition)).To(ContainSubstring(address)) g.Expect(conditions.GetMessage(resultR, meta.ReadyCondition)).To(ContainSubstring(address))
}) })
@ -375,6 +295,7 @@ func TestReceiverReconciler_EventHandler(t *testing.T) {
}, timeout, time.Second).Should(BeTrue()) }, timeout, time.Second).Should(BeTrue())
g.Expect(conditions.IsReady(resultR)) g.Expect(conditions.IsReady(resultR))
g.Expect(resultR.Status.URL).To(BeIdenticalTo(address))
g.Expect(resultR.Status.WebhookPath).To(BeIdenticalTo(address)) g.Expect(resultR.Status.WebhookPath).To(BeIdenticalTo(address))
}) })

View File

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
package controller package controllers
import ( import (
"context" "context"
@ -31,20 +31,16 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
utilruntime "k8s.io/apimachinery/pkg/util/runtime" utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/kubernetes/scheme"
"sigs.k8s.io/cli-utils/pkg/kstatus/polling"
ctrl "sigs.k8s.io/controller-runtime" ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client" "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/controller"
"github.com/fluxcd/pkg/runtime/metrics"
"github.com/fluxcd/pkg/runtime/testenv" "github.com/fluxcd/pkg/runtime/testenv"
"github.com/fluxcd/pkg/ssa" "github.com/fluxcd/pkg/ssa"
ssautil "github.com/fluxcd/pkg/ssa/utils"
apiv1 "github.com/fluxcd/notification-controller/api/v1" apiv1 "github.com/fluxcd/notification-controller/api/v1beta2"
apiv1b2 "github.com/fluxcd/notification-controller/api/v1beta2"
apiv1b3 "github.com/fluxcd/notification-controller/api/v1beta3"
// +kubebuilder:scaffold:imports // +kubebuilder:scaffold:imports
) )
@ -58,11 +54,9 @@ var (
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
var err error var err error
utilruntime.Must(apiv1.AddToScheme(scheme.Scheme)) utilruntime.Must(apiv1.AddToScheme(scheme.Scheme))
utilruntime.Must(apiv1b2.AddToScheme(scheme.Scheme))
utilruntime.Must(apiv1b3.AddToScheme(scheme.Scheme))
testEnv = testenv.New(testenv.WithCRDPath( 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}) k8sClient, err = client.New(testEnv.Config, client.Options{Scheme: scheme.Scheme})
@ -71,20 +65,27 @@ func TestMain(m *testing.M) {
} }
controllerName := "notification-controller" controllerName := "notification-controller"
testMetricsH := controller.NewMetrics(testEnv, metrics.MustMakeRecorder(), apiv1.NotificationFinalizer) testMetricsH := controller.MustMakeMetrics(testEnv)
if err := (&AlertReconciler{ if err := (&AlertReconciler{
Client: testEnv, Client: testEnv,
Metrics: testMetricsH,
ControllerName: controllerName, ControllerName: controllerName,
EventRecorder: testEnv.GetEventRecorderFor(controllerName), EventRecorder: testEnv.GetEventRecorderFor(controllerName),
}).SetupWithManager(testEnv); err != nil { }).SetupWithManagerAndOptions(testEnv, AlertReconcilerOptions{
panic(fmt.Sprintf("Failed to start AlertReconciler: %v", err)) RateLimiter: controller.GetDefaultRateLimiter(),
}); err != nil {
panic(fmt.Sprintf("Failed to start AlerReconciler: %v", err))
} }
if err := (&ProviderReconciler{ if err := (&ProviderReconciler{
Client: testEnv, Client: testEnv,
Metrics: testMetricsH,
ControllerName: controllerName,
EventRecorder: testEnv.GetEventRecorderFor(controllerName), EventRecorder: testEnv.GetEventRecorderFor(controllerName),
}).SetupWithManager(testEnv); err != nil { }).SetupWithManagerAndOptions(testEnv, ProviderReconcilerOptions{
RateLimiter: controller.GetDefaultRateLimiter(),
}); err != nil {
panic(fmt.Sprintf("Failed to start ProviderReconciler: %v", err)) panic(fmt.Sprintf("Failed to start ProviderReconciler: %v", err))
} }
@ -107,7 +108,7 @@ func TestMain(m *testing.M) {
}() }()
<-testEnv.Manager.Elected() <-testEnv.Manager.Elected()
restMapper, err := runtimeclient.NewDynamicRESTMapper(testEnv.Config) restMapper, err := apiutil.NewDynamicRESTMapper(testEnv.Config)
if err != nil { if err != nil {
panic(fmt.Sprintf("Failed to create restmapper: %v", restMapper)) panic(fmt.Sprintf("Failed to create restmapper: %v", restMapper))
} }
@ -155,7 +156,7 @@ func readManifest(manifest, namespace string) (*unstructured.Unstructured, error
} }
yml := fmt.Sprintf(string(data), namespace) yml := fmt.Sprintf(string(data), namespace)
object, err := ssautil.ReadObject(strings.NewReader(yml)) object, err := ssa.ReadObject(strings.NewReader(yml))
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -1,5 +1,5 @@
--- ---
apiVersion: source.toolkit.fluxcd.io/v1 apiVersion: source.toolkit.fluxcd.io/v1beta1
kind: GitRepository kind: GitRepository
metadata: metadata:
name: podinfo-two name: podinfo-two

View File

@ -1,5 +1,5 @@
--- ---
apiVersion: source.toolkit.fluxcd.io/v1 apiVersion: source.toolkit.fluxcd.io/v1beta1
kind: GitRepository kind: GitRepository
metadata: metadata:
name: podinfo name: podinfo

View File

@ -1,4 +1,4 @@
<h1>Notification API reference v1beta2</h1> <h1>Notification API reference</h1>
<p>Packages:</p> <p>Packages:</p>
<ul class="simple"> <ul class="simple">
<li> <li>
@ -76,7 +76,7 @@ AlertSpec
<td> <td>
<code>providerRef</code><br> <code>providerRef</code><br>
<em> <em>
<a href="https://pkg.go.dev/github.com/fluxcd/pkg/apis/meta#LocalObjectReference"> <a href="https://godoc.org/github.com/fluxcd/pkg/apis/meta#LocalObjectReference">
github.com/fluxcd/pkg/apis/meta.LocalObjectReference github.com/fluxcd/pkg/apis/meta.LocalObjectReference
</a> </a>
</em> </em>
@ -102,8 +102,8 @@ If set to &lsquo;info&rsquo; no events will be filtered.</p>
<td> <td>
<code>eventSources</code><br> <code>eventSources</code><br>
<em> <em>
<a href="https://pkg.go.dev/github.com/fluxcd/notification-controller/api/v1#CrossNamespaceObjectReference"> <a href="#notification.toolkit.fluxcd.io/v1beta2.CrossNamespaceObjectReference">
[]github.com/fluxcd/notification-controller/api/v1.CrossNamespaceObjectReference []CrossNamespaceObjectReference
</a> </a>
</em> </em>
</td> </td>
@ -114,35 +114,6 @@ on the involved object kind, name and namespace.</p>
</tr> </tr>
<tr> <tr>
<td> <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&rsquo;t happen, i.e. the original value is preserved, and an info
log is printed.</p>
</td>
</tr>
<tr>
<td>
<code>exclusionList</code><br> <code>exclusionList</code><br>
<em> <em>
[]string []string
@ -270,7 +241,7 @@ string
<td> <td>
<code>interval</code><br> <code>interval</code><br>
<em> <em>
<a href="https://pkg.go.dev/k8s.io/apimachinery/pkg/apis/meta/v1#Duration"> <a href="https://godoc.org/k8s.io/apimachinery/pkg/apis/meta/v1#Duration">
Kubernetes meta/v1.Duration Kubernetes meta/v1.Duration
</a> </a>
</em> </em>
@ -313,17 +284,14 @@ string
</td> </td>
<td> <td>
<em>(Optional)</em> <em>(Optional)</em>
<p>Address specifies the endpoint, in a generic sense, to where alerts are sent. <p>Address specifies the HTTP/S incoming webhook address of this Provider.</p>
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> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
<code>timeout</code><br> <code>timeout</code><br>
<em> <em>
<a href="https://pkg.go.dev/k8s.io/apimachinery/pkg/apis/meta/v1#Duration"> <a href="https://godoc.org/k8s.io/apimachinery/pkg/apis/meta/v1#Duration">
Kubernetes meta/v1.Duration Kubernetes meta/v1.Duration
</a> </a>
</em> </em>
@ -349,7 +317,7 @@ string
<td> <td>
<code>secretRef</code><br> <code>secretRef</code><br>
<em> <em>
<a href="https://pkg.go.dev/github.com/fluxcd/pkg/apis/meta#LocalObjectReference"> <a href="https://godoc.org/github.com/fluxcd/pkg/apis/meta#LocalObjectReference">
github.com/fluxcd/pkg/apis/meta.LocalObjectReference github.com/fluxcd/pkg/apis/meta.LocalObjectReference
</a> </a>
</em> </em>
@ -364,7 +332,7 @@ credentials for this Provider.</p>
<td> <td>
<code>certSecretRef</code><br> <code>certSecretRef</code><br>
<em> <em>
<a href="https://pkg.go.dev/github.com/fluxcd/pkg/apis/meta#LocalObjectReference"> <a href="https://godoc.org/github.com/fluxcd/pkg/apis/meta#LocalObjectReference">
github.com/fluxcd/pkg/apis/meta.LocalObjectReference github.com/fluxcd/pkg/apis/meta.LocalObjectReference
</a> </a>
</em> </em>
@ -372,9 +340,7 @@ github.com/fluxcd/pkg/apis/meta.LocalObjectReference
<td> <td>
<em>(Optional)</em> <em>(Optional)</em>
<p>CertSecretRef specifies the Secret containing <p>CertSecretRef specifies the Secret containing
a PEM-encoded CA certificate (in the <code>ca.crt</code> key).</p> a PEM-encoded CA certificate (<code>caFile</code>).</p>
<p>Note: Support for the <code>caFile</code> key has
been deprecated.</p>
</td> </td>
</tr> </tr>
<tr> <tr>
@ -482,7 +448,7 @@ the validation procedure and payload deserialization.</p>
<td> <td>
<code>interval</code><br> <code>interval</code><br>
<em> <em>
<a href="https://pkg.go.dev/k8s.io/apimachinery/pkg/apis/meta/v1#Duration"> <a href="https://godoc.org/k8s.io/apimachinery/pkg/apis/meta/v1#Duration">
Kubernetes meta/v1.Duration Kubernetes meta/v1.Duration
</a> </a>
</em> </em>
@ -509,8 +475,8 @@ e.g. &lsquo;push&rsquo; for GitHub or &lsquo;Push Hook&rsquo; for GitLab.</p>
<td> <td>
<code>resources</code><br> <code>resources</code><br>
<em> <em>
<a href="https://pkg.go.dev/github.com/fluxcd/notification-controller/api/v1#CrossNamespaceObjectReference"> <a href="#notification.toolkit.fluxcd.io/v1beta2.CrossNamespaceObjectReference">
[]github.com/fluxcd/notification-controller/api/v1.CrossNamespaceObjectReference []CrossNamespaceObjectReference
</a> </a>
</em> </em>
</td> </td>
@ -522,7 +488,7 @@ e.g. &lsquo;push&rsquo; for GitHub or &lsquo;Push Hook&rsquo; for GitLab.</p>
<td> <td>
<code>secretRef</code><br> <code>secretRef</code><br>
<em> <em>
<a href="https://pkg.go.dev/github.com/fluxcd/pkg/apis/meta#LocalObjectReference"> <a href="https://godoc.org/github.com/fluxcd/pkg/apis/meta#LocalObjectReference">
github.com/fluxcd/pkg/apis/meta.LocalObjectReference github.com/fluxcd/pkg/apis/meta.LocalObjectReference
</a> </a>
</em> </em>
@ -585,7 +551,7 @@ ReceiverStatus
<td> <td>
<code>providerRef</code><br> <code>providerRef</code><br>
<em> <em>
<a href="https://pkg.go.dev/github.com/fluxcd/pkg/apis/meta#LocalObjectReference"> <a href="https://godoc.org/github.com/fluxcd/pkg/apis/meta#LocalObjectReference">
github.com/fluxcd/pkg/apis/meta.LocalObjectReference github.com/fluxcd/pkg/apis/meta.LocalObjectReference
</a> </a>
</em> </em>
@ -611,8 +577,8 @@ If set to &lsquo;info&rsquo; no events will be filtered.</p>
<td> <td>
<code>eventSources</code><br> <code>eventSources</code><br>
<em> <em>
<a href="https://pkg.go.dev/github.com/fluxcd/notification-controller/api/v1#CrossNamespaceObjectReference"> <a href="#notification.toolkit.fluxcd.io/v1beta2.CrossNamespaceObjectReference">
[]github.com/fluxcd/notification-controller/api/v1.CrossNamespaceObjectReference []CrossNamespaceObjectReference
</a> </a>
</em> </em>
</td> </td>
@ -623,35 +589,6 @@ on the involved object kind, name and namespace.</p>
</tr> </tr>
<tr> <tr>
<td> <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&rsquo;t happen, i.e. the original value is preserved, and an info
log is printed.</p>
</td>
</tr>
<tr>
<td>
<code>exclusionList</code><br> <code>exclusionList</code><br>
<em> <em>
[]string []string
@ -713,7 +650,7 @@ events handling for this Alert.</p>
<td> <td>
<code>ReconcileRequestStatus</code><br> <code>ReconcileRequestStatus</code><br>
<em> <em>
<a href="https://pkg.go.dev/github.com/fluxcd/pkg/apis/meta#ReconcileRequestStatus"> <a href="https://godoc.org/github.com/fluxcd/pkg/apis/meta#ReconcileRequestStatus">
github.com/fluxcd/pkg/apis/meta.ReconcileRequestStatus github.com/fluxcd/pkg/apis/meta.ReconcileRequestStatus
</a> </a>
</em> </em>
@ -756,6 +693,11 @@ int64
</div> </div>
<h3 id="notification.toolkit.fluxcd.io/v1beta2.CrossNamespaceObjectReference">CrossNamespaceObjectReference <h3 id="notification.toolkit.fluxcd.io/v1beta2.CrossNamespaceObjectReference">CrossNamespaceObjectReference
</h3> </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 <p>CrossNamespaceObjectReference contains enough information to let you locate the
typed referenced object at cluster level</p> typed referenced object at cluster level</p>
<div class="md-typeset__scrollwrap"> <div class="md-typeset__scrollwrap">
@ -864,7 +806,7 @@ string
<td> <td>
<code>interval</code><br> <code>interval</code><br>
<em> <em>
<a href="https://pkg.go.dev/k8s.io/apimachinery/pkg/apis/meta/v1#Duration"> <a href="https://godoc.org/k8s.io/apimachinery/pkg/apis/meta/v1#Duration">
Kubernetes meta/v1.Duration Kubernetes meta/v1.Duration
</a> </a>
</em> </em>
@ -907,17 +849,14 @@ string
</td> </td>
<td> <td>
<em>(Optional)</em> <em>(Optional)</em>
<p>Address specifies the endpoint, in a generic sense, to where alerts are sent. <p>Address specifies the HTTP/S incoming webhook address of this Provider.</p>
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> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
<code>timeout</code><br> <code>timeout</code><br>
<em> <em>
<a href="https://pkg.go.dev/k8s.io/apimachinery/pkg/apis/meta/v1#Duration"> <a href="https://godoc.org/k8s.io/apimachinery/pkg/apis/meta/v1#Duration">
Kubernetes meta/v1.Duration Kubernetes meta/v1.Duration
</a> </a>
</em> </em>
@ -943,7 +882,7 @@ string
<td> <td>
<code>secretRef</code><br> <code>secretRef</code><br>
<em> <em>
<a href="https://pkg.go.dev/github.com/fluxcd/pkg/apis/meta#LocalObjectReference"> <a href="https://godoc.org/github.com/fluxcd/pkg/apis/meta#LocalObjectReference">
github.com/fluxcd/pkg/apis/meta.LocalObjectReference github.com/fluxcd/pkg/apis/meta.LocalObjectReference
</a> </a>
</em> </em>
@ -958,7 +897,7 @@ credentials for this Provider.</p>
<td> <td>
<code>certSecretRef</code><br> <code>certSecretRef</code><br>
<em> <em>
<a href="https://pkg.go.dev/github.com/fluxcd/pkg/apis/meta#LocalObjectReference"> <a href="https://godoc.org/github.com/fluxcd/pkg/apis/meta#LocalObjectReference">
github.com/fluxcd/pkg/apis/meta.LocalObjectReference github.com/fluxcd/pkg/apis/meta.LocalObjectReference
</a> </a>
</em> </em>
@ -966,9 +905,7 @@ github.com/fluxcd/pkg/apis/meta.LocalObjectReference
<td> <td>
<em>(Optional)</em> <em>(Optional)</em>
<p>CertSecretRef specifies the Secret containing <p>CertSecretRef specifies the Secret containing
a PEM-encoded CA certificate (in the <code>ca.crt</code> key).</p> a PEM-encoded CA certificate (<code>caFile</code>).</p>
<p>Note: Support for the <code>caFile</code> key has
been deprecated.</p>
</td> </td>
</tr> </tr>
<tr> <tr>
@ -1009,7 +946,7 @@ events handling for this Provider.</p>
<td> <td>
<code>ReconcileRequestStatus</code><br> <code>ReconcileRequestStatus</code><br>
<em> <em>
<a href="https://pkg.go.dev/github.com/fluxcd/pkg/apis/meta#ReconcileRequestStatus"> <a href="https://godoc.org/github.com/fluxcd/pkg/apis/meta#ReconcileRequestStatus">
github.com/fluxcd/pkg/apis/meta.ReconcileRequestStatus github.com/fluxcd/pkg/apis/meta.ReconcileRequestStatus
</a> </a>
</em> </em>
@ -1083,7 +1020,7 @@ the validation procedure and payload deserialization.</p>
<td> <td>
<code>interval</code><br> <code>interval</code><br>
<em> <em>
<a href="https://pkg.go.dev/k8s.io/apimachinery/pkg/apis/meta/v1#Duration"> <a href="https://godoc.org/k8s.io/apimachinery/pkg/apis/meta/v1#Duration">
Kubernetes meta/v1.Duration Kubernetes meta/v1.Duration
</a> </a>
</em> </em>
@ -1110,8 +1047,8 @@ e.g. &lsquo;push&rsquo; for GitHub or &lsquo;Push Hook&rsquo; for GitLab.</p>
<td> <td>
<code>resources</code><br> <code>resources</code><br>
<em> <em>
<a href="https://pkg.go.dev/github.com/fluxcd/notification-controller/api/v1#CrossNamespaceObjectReference"> <a href="#notification.toolkit.fluxcd.io/v1beta2.CrossNamespaceObjectReference">
[]github.com/fluxcd/notification-controller/api/v1.CrossNamespaceObjectReference []CrossNamespaceObjectReference
</a> </a>
</em> </em>
</td> </td>
@ -1123,7 +1060,7 @@ e.g. &lsquo;push&rsquo; for GitHub or &lsquo;Push Hook&rsquo; for GitLab.</p>
<td> <td>
<code>secretRef</code><br> <code>secretRef</code><br>
<em> <em>
<a href="https://pkg.go.dev/github.com/fluxcd/pkg/apis/meta#LocalObjectReference"> <a href="https://godoc.org/github.com/fluxcd/pkg/apis/meta#LocalObjectReference">
github.com/fluxcd/pkg/apis/meta.LocalObjectReference github.com/fluxcd/pkg/apis/meta.LocalObjectReference
</a> </a>
</em> </em>
@ -1171,7 +1108,7 @@ events handling for this receiver.</p>
<td> <td>
<code>ReconcileRequestStatus</code><br> <code>ReconcileRequestStatus</code><br>
<em> <em>
<a href="https://pkg.go.dev/github.com/fluxcd/pkg/apis/meta#ReconcileRequestStatus"> <a href="https://godoc.org/github.com/fluxcd/pkg/apis/meta#ReconcileRequestStatus">
github.com/fluxcd/pkg/apis/meta.ReconcileRequestStatus github.com/fluxcd/pkg/apis/meta.ReconcileRequestStatus
</a> </a>
</em> </em>

View File

@ -1,466 +0,0 @@
<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. &lsquo;push&rsquo; for GitHub or &lsquo;Push Hook&rsquo; 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 &ldquo;key&rdquo;, the
operator is &ldquo;In&rdquo;, and the values array contains only &ldquo;value&rdquo;. 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. &lsquo;push&rsquo; for GitHub or &lsquo;Push Hook&rsquo; 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 &lsquo;/hook/sha256sum(token+name+namespace)&rsquo;.</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>

View File

@ -1,780 +0,0 @@
<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 &lsquo;info&rsquo; 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&rsquo;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 &lsquo;address&rsquo; key with the
HTTP/S address of the proxy server. Optional &lsquo;username&rsquo; and &lsquo;password&rsquo;
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 &ldquo;caFile&rdquo;, &ldquo;certFile&rdquo;, &ldquo;keyFile&rdquo; are supported but deprecated. Use &ldquo;ca.crt&rdquo;, &ldquo;tls.crt&rdquo;, &ldquo;tls.key&rdquo; 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 &lsquo;info&rsquo; 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&rsquo;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 &lsquo;address&rsquo; key with the
HTTP/S address of the proxy server. Optional &lsquo;username&rsquo; and &lsquo;password&rsquo;
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 &ldquo;caFile&rdquo;, &ldquo;certFile&rdquo;, &ldquo;keyFile&rdquo; are supported but deprecated. Use &ldquo;ca.crt&rdquo;, &ldquo;tls.crt&rdquo;, &ldquo;tls.key&rdquo; 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>

View File

@ -1,9 +1,66 @@
# Notification Controller # Notification Controller
## API Specification The Notification Controller is a Kubernetes operator, specialized in handling inbound and outbound events.
* [v1](v1/README.md) ## Motivation
* [v1beta3](v1beta3/README.md)
* [v1beta2](v1beta2/README.md) ### Events dispatching
* [v1beta1](v1beta1/README.md)
* [v1alpha1](v1alpha1/README.md) 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

View File

@ -1,7 +0,0 @@
# 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

View File

@ -4,11 +4,11 @@ This is the v1alpha1 API specification for defining events handling and dispatch
## Specification ## Specification
* [Alert](alerts.md) * [Alert](alert.md)
* [Event](events.md) * [Event](event.md)
* [Provider](providers.md) * [Provider](provider.md)
* [Receiver](receivers.md) * [Receiver](receiver.md)
## Go Client ## Go Client
* [github.com/fluxcd/pkg/runtime/events/recorder.go](https://github.com/fluxcd/pkg/blob/main/runtime/events/recorder.go#L60) * [github.com/fluxcd/pkg/recorder](https://github.com/fluxcd/pkg/tree/main/recorder)

View File

@ -368,8 +368,7 @@ and use `https://api.telegram.org/` as the api url.
--from-literal=address=https://api.telegram.org --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) or username of the target channel (in the format @channelusername)
```yaml ```yaml
@ -380,7 +379,7 @@ metadata:
namespace: flux-system namespace: flux-system
spec: spec:
type: telegram type: telegram
channel: "@fluxtest" # or "-1557265138" (channel id) or "-1552289257:1" (forum chat id with topic id) channel: "@fluxtest" # or "-1557265138" (channel id)
secretRef: secretRef:
name: telegram-token name: telegram-token
``` ```

View File

@ -11,4 +11,4 @@ This is the v1beta2 API specification for defining events handling and dispatchi
## Go Client ## Go Client
* [github.com/fluxcd/pkg/runtime/events](https://pkg.go.dev/github.com/fluxcd/pkg/runtime/events) * [github.com/fluxcd/pkg/recorder](https://github.com/fluxcd/pkg/tree/main/recorder)

View File

@ -1,7 +1,5 @@
# Alerts # Alerts
<!-- menuweight:10 -->
The `Alert` API defines how events are filtered by severity and involved object, and what provider to use for dispatching. The `Alert` API defines how events are filtered by severity and involved object, and what provider to use for dispatching.
## Example ## Example
@ -162,36 +160,6 @@ 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, 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. 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 ### Event severity
`.spec.eventSeverity` is an optional field to filter events based on severity. When not specified, or `.spec.eventSeverity` is an optional field to filter events based on severity. When not specified, or
@ -201,8 +169,7 @@ To receive alerts only on errors, set the field value to `error`.
### Event exclusion ### Event exclusion
`.spec.exclusionList` is an optional field to specify a list of regex expressions to filter `.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 events based on message content.
one of the expressions in the list.
#### Example #### Example
@ -229,39 +196,6 @@ 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 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 ### Suspend
`.spec.suspend` is an optional field to suspend the altering. `.spec.suspend` is an optional field to suspend the altering.

View File

@ -1,7 +1,5 @@
# Events # Events
<!-- menuweight:20 -->
The `Event` API defines the structure of the events issued by Flux controllers. 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) Flux controllers use the [fluxcd/pkg/runtime/events](https://github.com/fluxcd/pkg/tree/main/runtime/events)

View File

@ -1,7 +1,5 @@
# Providers # Providers
<!-- menuweight:40 -->
The `Provider` API defines how events are encoded and where to send them. The `Provider` API defines how events are encoded and where to send them.
## Example ## Example
@ -109,17 +107,14 @@ The supported alerting providers are:
| [Generic webhook](#generic-webhook) | `generic` | | [Generic webhook](#generic-webhook) | `generic` |
| [Generic webhook with HMAC](#generic-webhook-with-hmac) | `generic-hmac` | | [Generic webhook with HMAC](#generic-webhook-with-hmac) | `generic-hmac` |
| [Azure Event Hub](#azure-event-hub) | `azureeventhub` | | [Azure Event Hub](#azure-event-hub) | `azureeventhub` |
| [DataDog](#datadog) | `datadog` |
| [Discord](#discord) | `discord` | | [Discord](#discord) | `discord` |
| [GitHub dispatch](#github-dispatch) | `githubdispatch` | | [GitHub dispatch](#github-dispatch) | `githubdispatch` |
| [Google Chat](#google-chat) | `googlechat` | | [Google Chat](#google-chat) | `googlechat` |
| [Google Pub/Sub](#google-pubsub) | `googlepubsub` |
| [Grafana](#grafana) | `grafana` | | [Grafana](#grafana) | `grafana` |
| [Lark](#lark) | `lark` | | [Lark](#lark) | `lark` |
| [Matrix](#matrix) | `matrix` | | [Matrix](#matrix) | `matrix` |
| [Microsoft Teams](#microsoft-teams) | `msteams` | | [Microsoft Teams](#microsoft-teams) | `msteams` |
| [Opsgenie](#opsgenie) | `opsgenie` | | [Opsgenie](#opsgenie) | `opsgenie` |
| [PagerDuty](#pagerduty) | `pagerduty` |
| [Prometheus Alertmanager](#prometheus-alertmanager) | `alertmanager` | | [Prometheus Alertmanager](#prometheus-alertmanager) | `alertmanager` |
| [Rocket](#rocket) | `rocket` | | [Rocket](#rocket) | `rocket` |
| [Sentry](#sentry) | `sentry` | | [Sentry](#sentry) | `sentry` |
@ -130,10 +125,9 @@ The supported alerting providers are:
The supported providers for [Git commit status updates](#git-commit-status-updates) are: The supported providers for [Git commit status updates](#git-commit-status-updates) are:
| Provider | Type | | Provider | Type |
| ------------------------------------------------| ----------------- | |-------------------------------|---------------|
| [Azure DevOps](#azure-devops) | `azuredevops` | | [Azure DevOps](#azure-devops) | `azuredevops` |
| [Bitbucket](#bitbucket) | `bitbucket` | | [Bitbucket](#bitbucket) | `bitbucket` |
| [BitbucketServer](#bitbucket-serverdata-center) | `bitbucketserver` |
| [GitHub](#github) | `github` | | [GitHub](#github) | `github` |
| [GitLab](#gitlab) | `gitlab` | | [GitLab](#gitlab) | `gitlab` |
| [Gitea](#gitea) | `gitea` | | [Gitea](#gitea) | `gitea` |
@ -238,7 +232,7 @@ func verifySignature(signature string, payload, key []byte) error {
case "sha512": case "sha512":
newF = sha512.New newF = sha512.New
default: default:
return fmt.Errorf("unsupported signature algorithm %q", sig[0]) return fmt.Errorf("unsupported signature algorithm %q", sigHdr[0])
} }
mac := hmac.New(newF, key) mac := hmac.New(newF, key)
@ -247,22 +241,22 @@ func verifySignature(signature string, payload, key []byte) error {
} }
sum := fmt.Sprintf("%x", mac.Sum(nil)) sum := fmt.Sprintf("%x", mac.Sum(nil))
if sum != sig[1] { if sum != sig[0] {
return fmt.Errorf("HMACs do not match: %#v != %#v", sum, sig[1]) return fmt.Errorf("HMACs do not match: %#v != %#v", sum, sigHdr[0])
} }
return nil return nil
} }
func handleRequest(w http.ResponseWriter, r *http.Request) { func handleRequest(w http.ResponseWriter, r *http.Request) {
// Require a X-Signature header // 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) http.Error(w, "missing X-Signature header", http.StatusBadRequest)
return return
} }
// Read the request body with a limit of 1MB // Read the request body with a limit of 1MB
lr := io.LimitReader(r.Body, 1<<20) lr := io.LimitReader(r.Body, 1<<20)
body, err := io.ReadAll(lr) body, err := ioutil.ReadAll(lr)
if err != nil { if err != nil {
http.Error(w, "failed to read request body", http.StatusBadRequest) http.Error(w, "failed to read request body", http.StatusBadRequest)
return return
@ -270,9 +264,9 @@ func handleRequest(w http.ResponseWriter, r *http.Request) {
// Verify signature using the same token as the Secret referenced in // Verify signature using the same token as the Secret referenced in
// Provider // Provider
key := []byte("<token>") key := "<token>"
if err := verifySignature(r.Header.Get("X-Signature"), body, key); err != nil { if err := verifySignature(r.Header.Get("X-Signature"), body, key); err != nil {
http.Error(w, fmt.Sprintf("failed to verify HMAC signature: %s", err.Error()), http.StatusBadRequest) http.Error(w, fmt.Sprintf("failed to verify HMAC signature: %s", err.String()), http.StatusBadRequest)
return return
} }
@ -407,62 +401,6 @@ stringData:
address: "https://xxx.webhook.office.com/..." 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 ##### Discord
When `.spec.type` is set to `discord`, the controller will send a payload for When `.spec.type` is set to `discord`, the controller will send a payload for
@ -563,9 +501,8 @@ The Event will be formatted into a message string, with the metadata attached
as a list of key-value pairs. as a list of key-value pairs.
The Provider's [Channel](#channel) is used to set the receiver of the message. 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, This can be a unique identifier (`-1234567890`) for the target chat, or
a unique identifier with the topic identifier (`-1234567890:1`) for the forum chat, the username (`@username`) of the target channel.
or the username (`@username`) of the target channel.
This Provider type does not support the configuration of a [proxy URL](#https-proxy) This Provider type does not support the configuration of a [proxy URL](#https-proxy)
or [TLS certificates](#tls-certificates). or [TLS certificates](#tls-certificates).
@ -587,7 +524,7 @@ metadata:
spec: spec:
type: telegram type: telegram
address: https://api.telegram.org address: https://api.telegram.org
channel: "@fluxcd" # or "-1557265138" (channel id) or "-1552289257:1" (forum chat id with topic id) channel: "@fluxcd" # or "-1557265138" (channel id)
secretRef: secretRef:
name: telegram-token name: telegram-token
``` ```
@ -732,65 +669,6 @@ stringData:
address: https://chat.googleapis.com/v1/spaces/... 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 ##### Opsgenie
When `.spec.type` is set to `opsgenie`, the controller will send a payload for When `.spec.type` is set to `opsgenie`, the controller will send a payload for
@ -832,64 +710,6 @@ stringData:
token: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 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 ##### Prometheus Alertmanager
When `.spec.type` is set to `alertmanager`, the controller will send a payload for When `.spec.type` is set to `alertmanager`, the controller will send a payload for
@ -995,10 +815,7 @@ stringData:
### Address ### Address
`.spec.address` is an optional field that specifies the endpoint where the events are posted. `.spec.address` is an optional field that specifies the URL 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 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`. recommended to store the address in the Kubernetes secret referenced by `.spec.secretRef.name`.
@ -1097,12 +914,11 @@ stringData:
`.spec.certSecretRef` is an optional field to specify a name reference to a `.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. 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 #### Example
To enable notification-controller to communicate with a provider API over HTTPS To enable notification-controller to communicate with a provider API over HTTPS
using a self-signed TLS certificate, set the `ca.crt` like so: using a self-signed TLS certificate, set the `caFile` like so:
```yaml ```yaml
--- ---
@ -1122,16 +938,11 @@ kind: Secret
metadata: metadata:
name: my-ca-crt name: my-ca-crt
namespace: default namespace: default
type: kubernetes.io/tls # or Opaque
stringData: stringData:
ca.crt: | caFile: |
<--- CA Key ---> <--- 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 ### HTTP/S proxy
`.spec.proxy` is an optional field to specify an HTTP/S proxy address. `.spec.proxy` is an optional field to specify an HTTP/S proxy address.
@ -1486,13 +1297,7 @@ 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 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). [Gitea token](https://docs.gitea.io/en-us/api-usage/#generating-and-listing-api-tokens).
The token must have at least the `write:repository` permission for the provider to The token owner must have permissions to update the commit status for the Gitea repository specified in `.spec.address`.
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: You can create the secret with `kubectl` like this:
@ -1516,32 +1321,6 @@ You can create the secret with `kubectl` like this:
kubectl create secret generic bitbucket-token --from-literal=token=<username>:<app-password> 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 #### Azure DevOps
When `.spec.type` is set to `azuredevops`, the referenced secret must contain a key called `token` with the value set to a When `.spec.type` is set to `azuredevops`, the referenced secret must contain a key called `token` with the value set to a

View File

@ -613,7 +613,7 @@ spec:
### Events ### Events
`.spec.events` is an optional field to specify a list of webhook payload event `.spec.events` in 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 types this Receiver should act on. If left empty, no filtering is applied and
any (valid) payload is handled. any (valid) payload is handled.
@ -629,7 +629,7 @@ called.
A resource entry contains the following fields: A resource entry contains the following fields:
- `apiVersion` (Optional): The Flux Custom Resource API group and version, such as - `apiVersion`: The Flux Custom Resource API group and version, such as
`source.toolkit.fluxcd.io/v1beta2`. `source.toolkit.fluxcd.io/v1beta2`.
- `kind`: The Flux Custom Resource kind, supported values are `Bucket`, - `kind`: The Flux Custom Resource kind, supported values are `Bucket`,
`GitRepository`, `Kustomization`, `HelmRelease`, `HelmChart`, `GitRepository`, `Kustomization`, `HelmRelease`, `HelmChart`,
@ -639,6 +639,7 @@ A resource entry contains the following fields:
- `namespace` (Optional): The Flux Custom Resource `.metadata.namespace`. - `namespace` (Optional): The Flux Custom Resource `.metadata.namespace`.
When not specified, the Receiver's `.metadata.namespace` is used instead. When not specified, the Receiver's `.metadata.namespace` is used instead.
**Note:** Cross-namespace references [can be disabled for security **Note:** Cross-namespace references [can be disabled for security
reasons](#disabling-cross-namespace-selectors). reasons](#disabling-cross-namespace-selectors).
@ -668,7 +669,7 @@ stringData:
### Interval ### Interval
`.spec.interval` is an optional field with a default of ten minutes that specifies `.spec.interval` is a required field with a default of ten minutes that specifies
the time interval at which the controller reconciles the provider with its Secret the time interval at which the controller reconciles the provider with its Secret
reference. reference.

View File

@ -1,13 +0,0 @@
# 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)

View File

@ -1,319 +0,0 @@
# 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.

View File

@ -1,64 +0,0 @@
# 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
View File

@ -1,76 +1,54 @@
module github.com/fluxcd/notification-controller module github.com/fluxcd/notification-controller
go 1.24.0 go 1.18
replace github.com/fluxcd/notification-controller/api => ./api replace github.com/fluxcd/notification-controller/api => ./api
require ( require (
cloud.google.com/go/pubsub v1.49.0 code.gitea.io/sdk/gitea v0.15.1
code.gitea.io/sdk/gitea v0.21.0 github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1
github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 github.com/Azure/azure-amqp-common-go/v4 v4.0.0
github.com/Azure/azure-amqp-common-go/v4 v4.2.0 github.com/Azure/azure-event-hubs-go/v3 v3.4.0
github.com/Azure/azure-event-hubs-go/v3 v3.6.2 github.com/containrrr/shoutrrr v0.7.1
github.com/DataDog/datadog-api-client-go/v2 v2.42.0 github.com/fluxcd/notification-controller/api v0.32.1
github.com/PagerDuty/go-pagerduty v1.8.0 github.com/fluxcd/pkg/apis/event v0.4.0
github.com/cdevents/sdk-go v0.4.1 github.com/fluxcd/pkg/apis/meta v0.19.0
github.com/chainguard-dev/git-urls v1.0.2 github.com/fluxcd/pkg/git v0.10.0
github.com/elazarl/goproxy v1.7.2 github.com/fluxcd/pkg/masktoken v0.2.0
github.com/fluxcd/cli-utils v0.36.0-flux.14 github.com/fluxcd/pkg/runtime v0.29.0
github.com/fluxcd/notification-controller/api v1.6.0 github.com/fluxcd/pkg/ssa v0.24.1
github.com/fluxcd/pkg/apis/event v0.18.0 github.com/getsentry/sentry-go v0.18.0
github.com/fluxcd/pkg/apis/meta v1.17.0 github.com/go-logr/logr v1.2.3
github.com/fluxcd/pkg/auth v0.21.0 github.com/google/go-github/v41 v41.0.0
github.com/fluxcd/pkg/cache v0.10.0 github.com/hashicorp/go-retryablehttp v0.7.2
github.com/fluxcd/pkg/git v0.34.0 github.com/ktrysmt/go-bitbucket v0.9.55
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/microsoft/azure-devops-go-api/azuredevops/v6 v6.0.1
github.com/nats-io/nats.go v1.43.0 github.com/onsi/gomega v1.27.2
github.com/onsi/gomega v1.37.0 github.com/sethvargo/go-limiter v0.7.2
github.com/sethvargo/go-limiter v1.0.0 github.com/slok/go-http-metrics v0.10.0
github.com/slok/go-http-metrics v0.13.0 github.com/spf13/pflag v1.0.5
github.com/spf13/pflag v1.0.6 github.com/stretchr/testify v1.8.2
github.com/stretchr/testify v1.10.0 github.com/whilp/git-urls v1.0.0
gitlab.com/gitlab-org/api/client-go v0.134.0 github.com/xanzy/go-gitlab v0.80.2
golang.org/x/oauth2 v0.30.0 golang.org/x/oauth2 v0.5.0
golang.org/x/text v0.27.0 k8s.io/api v0.26.1
google.golang.org/api v0.241.0 k8s.io/apimachinery v0.26.1
k8s.io/api v0.33.2 k8s.io/client-go v0.26.1
k8s.io/apimachinery v0.33.2 sigs.k8s.io/cli-utils v0.34.0
k8s.io/client-go v0.33.2 sigs.k8s.io/controller-runtime v0.14.4
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 sigs.k8s.io/yaml v1.3.0
sigs.k8s.io/controller-runtime v0.21.0
sigs.k8s.io/yaml v1.5.0
) )
// Fix CVE-2022-28948 // Fix CVE-2022-28948
replace gopkg.in/yaml.v3 => gopkg.in/yaml.v3 v3.0.1 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 ( 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/azure-sdk-for-go v65.0.0+incompatible // indirect
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0 // indirect github.com/Azure/go-amqp v0.18.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.9.0 // indirect github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // 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 v14.2.0+incompatible // indirect
github.com/Azure/go-autorest/autorest v0.11.28 // indirect github.com/Azure/go-autorest/autorest v0.11.28 // indirect
github.com/Azure/go-autorest/autorest/adal v0.9.21 // indirect github.com/Azure/go-autorest/autorest/adal v0.9.21 // indirect
@ -79,140 +57,95 @@ require (
github.com/Azure/go-autorest/autorest/validation v0.3.1 // indirect 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/logger v0.2.1 // indirect
github.com/Azure/go-autorest/tracing v0.6.0 // 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/MakeNowJust/heredoc v1.0.0 // indirect
github.com/ProtonMail/go-crypto v1.3.0 // indirect github.com/ProtonMail/go-crypto v0.0.0-20230201104953-d1d05f4e2bfb // indirect
github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect
github.com/blang/semver/v4 v4.0.0 // indirect github.com/cespare/xxhash/v2 v2.1.2 // 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/chai2010/gettext-go v1.0.2 // indirect
github.com/cloudevents/sdk-go/v2 v2.15.2 // indirect github.com/cloudflare/circl v1.3.2 // indirect
github.com/cloudflare/circl v1.6.1 // indirect github.com/cyphar/filepath-securejoin v0.2.3 // indirect
github.com/cyphar/filepath-securejoin v0.4.1 // indirect github.com/davecgh/go-spew v1.1.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/devigned/tab v0.1.1 // indirect
github.com/docker/cli v28.2.2+incompatible // indirect github.com/emicklei/go-restful/v3 v3.10.0 // indirect
github.com/docker/docker-credential-helpers v0.9.3 // indirect github.com/evanphx/json-patch v5.6.0+incompatible // indirect
github.com/emicklei/go-restful/v3 v3.12.2 // indirect github.com/evanphx/json-patch/v5 v5.6.0 // indirect
github.com/evanphx/json-patch/v5 v5.9.11 // indirect
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fatih/color v1.13.0 // indirect
github.com/fluxcd/pkg/apis/acl v0.7.0 // indirect github.com/fluxcd/pkg/apis/acl v0.1.0 // indirect
github.com/fluxcd/pkg/apis/kustomize v1.11.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/go-errors/errors v1.4.2 // indirect
github.com/fxamacker/cbor/v2 v2.8.0 // indirect github.com/go-logr/zapr v1.2.3 // indirect
github.com/gabriel-vasile/mimetype v1.4.5 // indirect github.com/go-openapi/jsonpointer v0.19.5 // indirect
github.com/go-errors/errors v1.5.1 // indirect github.com/go-openapi/jsonreference v0.20.0 // indirect
github.com/go-fed/httpsig v1.1.0 // indirect github.com/go-openapi/swag v0.22.3 // 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/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt/v4 v4.5.2 // indirect github.com/golang-jwt/jwt/v4 v4.4.2 // indirect
github.com/golang-jwt/jwt/v5 v5.2.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect github.com/golang/protobuf v1.5.2 // indirect
github.com/google/btree v1.1.3 // indirect github.com/google/btree v1.1.2 // indirect
github.com/google/gnostic-models v0.7.0 // indirect github.com/google/gnostic v0.6.9 // indirect
github.com/google/go-cmp v0.7.0 // indirect github.com/google/go-cmp v0.5.9 // 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/go-querystring v1.1.0 // indirect
github.com/google/s2a-go v0.1.9 // indirect github.com/google/gofuzz v1.2.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
github.com/googleapis/gax-go/v2 v2.14.2 // indirect github.com/google/uuid v1.3.0 // indirect
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-version v1.7.0 // indirect github.com/hashicorp/go-version v1.6.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/imdario/mergo v0.3.13 // indirect
github.com/joho/godotenv v1.5.1 // indirect github.com/inconshreveable/mousetrap v1.0.1 // indirect
github.com/josharian/intern v1.0.0 // indirect github.com/josharian/intern v1.0.0 // indirect
github.com/jpillora/backoff v1.0.0 // indirect github.com/jpillora/backoff v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // 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/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
github.com/mailru/easyjson v0.9.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect
github.com/mitchellh/go-homedir v1.1.0 // 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/mitchellh/go-wordwrap v1.0.1 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/moby/spdystream v0.5.0 // indirect github.com/moby/spdystream v0.2.0 // indirect
github.com/moby/term v0.5.0 // indirect github.com/moby/term v0.0.0-20221105221325-4eb28fa6025c // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // 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/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/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_golang v1.22.0 // indirect github.com/prometheus/client_golang v1.14.0 // indirect
github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/client_model v0.3.0 // indirect
github.com/prometheus/common v0.65.0 // indirect github.com/prometheus/common v0.37.0 // indirect
github.com/prometheus/procfs v0.17.0 // indirect github.com/prometheus/procfs v0.8.0 // indirect
github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/rogpeppe/go-internal v1.8.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/russross/blackfriday v1.6.0 // indirect
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1 // indirect github.com/spf13/cobra v1.6.1 // indirect
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect github.com/xlab/treeprint v1.1.0 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect go.starlark.net v0.0.0-20221028183056-acb66ad56dd2 // indirect
github.com/spf13/cobra v1.9.1 // indirect go.uber.org/atomic v1.10.0 // indirect
github.com/stoewer/go-strcase v1.3.0 // indirect go.uber.org/multierr v1.8.0 // indirect
github.com/x448/float16 v0.8.4 // indirect go.uber.org/zap v1.24.0 // indirect
github.com/xlab/treeprint v1.2.0 // indirect golang.org/x/crypto v0.6.0 // indirect
go.opencensus.io v0.24.0 // indirect golang.org/x/net v0.7.0 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect golang.org/x/sys v0.5.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 // indirect golang.org/x/term v0.5.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect golang.org/x/text v0.7.0 // indirect
go.opentelemetry.io/otel v1.37.0 // indirect golang.org/x/time v0.3.0 // indirect
go.opentelemetry.io/otel/metric v1.37.0 // indirect gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
go.opentelemetry.io/otel/trace v1.37.0 // indirect google.golang.org/appengine v1.6.7 // indirect
go.uber.org/multierr v1.11.0 // indirect google.golang.org/protobuf v1.28.1 // 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/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/apiextensions-apiserver v0.33.2 // indirect k8s.io/apiextensions-apiserver v0.26.1 // indirect
k8s.io/cli-runtime v0.33.2 // indirect k8s.io/cli-runtime v0.25.4 // indirect
k8s.io/component-base v0.33.2 // indirect k8s.io/component-base v0.26.1 // indirect
k8s.io/klog/v2 v2.130.1 // indirect k8s.io/klog/v2 v2.90.0 // indirect
k8s.io/kube-openapi v0.0.0-20250701173324-9bd5c66d9911 // indirect k8s.io/kube-openapi v0.0.0-20221110221610-a28e98eb7c70 // indirect
k8s.io/kubectl v0.33.2 // indirect k8s.io/kubectl v0.25.4 // indirect
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect k8s.io/utils v0.0.0-20221128185143-99ec85e7a448 // indirect
sigs.k8s.io/kustomize/api v0.20.0 // indirect sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect
sigs.k8s.io/kustomize/kyaml v0.20.0 // indirect sigs.k8s.io/kustomize/api v0.12.1 // indirect
sigs.k8s.io/randfill v1.0.0 // indirect sigs.k8s.io/kustomize/kyaml v0.13.9 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.7.0 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
) )

1619
go.sum

File diff suppressed because it is too large Load Diff

View File

@ -9,7 +9,7 @@
"externalPackages": [ "externalPackages": [
{ {
"typeMatchPrefix": "^k8s\\.io/apimachinery/pkg/apis/meta/v1\\.Duration$", "typeMatchPrefix": "^k8s\\.io/apimachinery/pkg/apis/meta/v1\\.Duration$",
"docsURLTemplate": "https://pkg.go.dev/k8s.io/apimachinery/pkg/apis/meta/v1#Duration" "docsURLTemplate": "https://godoc.org/k8s.io/apimachinery/pkg/apis/meta/v1#Duration"
}, },
{ {
"typeMatchPrefix": "^k8s\\.io/apiextensions-apiserver/pkg/apis/apiextensions/v1\\.JSON$", "typeMatchPrefix": "^k8s\\.io/apiextensions-apiserver/pkg/apis/apiextensions/v1\\.JSON$",
@ -21,19 +21,15 @@
}, },
{ {
"typeMatchPrefix": "^github.com/fluxcd/pkg/runtime/dependency\\.CrossNamespaceDependencyReference$", "typeMatchPrefix": "^github.com/fluxcd/pkg/runtime/dependency\\.CrossNamespaceDependencyReference$",
"docsURLTemplate": "https://pkg.go.dev/github.com/fluxcd/pkg/runtime/dependency#CrossNamespaceDependencyReference" "docsURLTemplate": "https://godoc.org/github.com/fluxcd/pkg/runtime/dependency#CrossNamespaceDependencyReference"
}, },
{ {
"typeMatchPrefix": "^github.com/fluxcd/pkg/apis/kustomize", "typeMatchPrefix": "^github.com/fluxcd/pkg/apis/kustomize",
"docsURLTemplate": "https://pkg.go.dev/github.com/fluxcd/pkg/apis/kustomize#{{ .TypeIdentifier }}" "docsURLTemplate": "https://godoc.org/github.com/fluxcd/pkg/apis/kustomize#{{ .TypeIdentifier }}"
}, },
{ {
"typeMatchPrefix": "^github.com/fluxcd/pkg/apis/meta", "typeMatchPrefix": "^github.com/fluxcd/pkg/apis/meta",
"docsURLTemplate": "https://pkg.go.dev/github.com/fluxcd/pkg/apis/meta#{{ .TypeIdentifier }}" "docsURLTemplate": "https://godoc.org/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": { "typeDisplayNamePrefixOverrides": {

View File

@ -1,10 +1,5 @@
{{ define "packages" }} {{ define "packages" }}
<h1>Notification API reference <h1>Notification API reference</h1>
{{- with (index .packages 0) -}}
{{ with (index .GoPackages 0 ) -}}
{{ printf " %s" .Name -}}
{{ end -}}
{{ end }}</h1>
{{ with .packages}} {{ with .packages}}
<p>Packages:</p> <p>Packages:</p>

View File

@ -1,5 +1,5 @@
/* /*
Copyright 2023 The Flux authors Copyright 2022 The Flux authors
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,94 +0,0 @@
/*
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
}

View File

@ -1,121 +0,0 @@
/*
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())
}

View File

@ -1,50 +0,0 @@
/*
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)
}

View File

@ -1,165 +0,0 @@
/*
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))
})
}
}

View File

@ -1,98 +0,0 @@
/*
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
}

View File

@ -1,169 +0,0 @@
/*
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())
}
})
}
}

View File

@ -1,48 +0,0 @@
/*
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)
}

View File

@ -1,13 +0,0 @@
---
apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
name: podinfo-two
namespace: "%[1]s"
labels:
app: podinfo-two
spec:
interval: 1m
url: https://github.com/stefanprodan/podinfo
ref:
semver: 6.0.x

View File

@ -1,13 +0,0 @@
---
apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
name: podinfo
namespace: "%[1]s"
labels:
app: podinfo
spec:
interval: 1m
url: https://github.com/stefanprodan/podinfo
ref:
semver: 6.0.x

View File

@ -18,10 +18,7 @@ limitations under the License.
// and their default states. // and their default states.
package features package features
import ( import feathelper "github.com/fluxcd/pkg/runtime/features"
"github.com/fluxcd/pkg/auth"
feathelper "github.com/fluxcd/pkg/runtime/features"
)
const ( const (
// CacheSecretsAndConfigMaps controls whether Secrets and ConfigMaps should // CacheSecretsAndConfigMaps controls whether Secrets and ConfigMaps should
@ -38,10 +35,6 @@ var features = map[string]bool{
CacheSecretsAndConfigMaps: false, CacheSecretsAndConfigMaps: false,
} }
func init() {
auth.SetFeatureGates(features)
}
// FeatureGates contains a list of all supported feature gates and // FeatureGates contains a list of all supported feature gates and
// their default values. // their default values.
func FeatureGates() map[string]bool { func FeatureGates() map[string]bool {

View File

@ -18,15 +18,10 @@ package notifier
import ( import (
"context" "context"
"crypto/tls" "crypto/x509"
"encoding/json"
"fmt" "fmt"
"net/url" "net/url"
"time" "strings"
"github.com/hashicorp/go-retryablehttp"
"golang.org/x/text/cases"
"golang.org/x/text/language"
eventv1 "github.com/fluxcd/pkg/apis/event/v1beta1" eventv1 "github.com/fluxcd/pkg/apis/event/v1beta1"
) )
@ -34,47 +29,16 @@ import (
type Alertmanager struct { type Alertmanager struct {
URL string URL string
ProxyURL string ProxyURL string
TLSConfig *tls.Config CertPool *x509.CertPool
Token string
} }
type AlertManagerAlert struct { type AlertManagerAlert struct {
Status string `json:"status"` Status string `json:"status"`
Labels map[string]string `json:"labels"` Labels map[string]string `json:"labels"`
Annotations map[string]string `json:"annotations"` Annotations map[string]string `json:"annotations"`
StartsAt AlertManagerTime `json:"startsAt"`
EndsAt AlertManagerTime `json:"endsAt,omitempty"`
} }
// AlertManagerTime takes care of representing time.Time as RFC3339. func NewAlertmanager(hookURL string, proxyURL string, certPool *x509.CertPool) (*Alertmanager, error) {
// 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) _, err := url.ParseRequestURI(hookURL)
if err != nil { if err != nil {
return nil, fmt.Errorf("invalid Alertmanager URL %s: '%w'", hookURL, err) return nil, fmt.Errorf("invalid Alertmanager URL %s: '%w'", hookURL, err)
@ -83,8 +47,7 @@ func NewAlertmanager(hookURL string, proxyURL string, tlsConfig *tls.Config, tok
return &Alertmanager{ return &Alertmanager{
URL: hookURL, URL: hookURL,
ProxyURL: proxyURL, ProxyURL: proxyURL,
Token: token, CertPool: certPool,
TLSConfig: tlsConfig,
}, nil }, nil
} }
@ -107,52 +70,28 @@ func (s *Alertmanager) Post(ctx context.Context, event eventv1.Event) error {
if event.Metadata != nil { if event.Metadata != nil {
labels = event.Metadata labels = event.Metadata
} }
labels["alertname"] = "Flux" + event.InvolvedObject.Kind + cases.Title(language.Und).String(event.Reason) labels["alertname"] = "Flux" + event.InvolvedObject.Kind + strings.Title(event.Reason)
labels["severity"] = event.Severity labels["severity"] = event.Severity
labels["reason"] = event.Reason labels["reason"] = event.Reason
labels["timestamp"] = event.Timestamp.String()
labels["kind"] = event.InvolvedObject.Kind labels["kind"] = event.InvolvedObject.Kind
labels["name"] = event.InvolvedObject.Name labels["name"] = event.InvolvedObject.Name
labels["namespace"] = event.InvolvedObject.Namespace labels["namespace"] = event.InvolvedObject.Namespace
labels["reportingcontroller"] = event.ReportingController 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{ payload := []AlertManagerAlert{
{ {
Labels: labels, Labels: labels,
Annotations: annotations, Annotations: annotations,
Status: "firing", Status: "firing",
StartsAt: startsAt,
}, },
} }
var opts []postOption err := postMessage(ctx, s.URL, s.ProxyURL, s.CertPool, payload)
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 := postMessage(ctx, s.URL, payload, opts...); err != nil { if err != nil {
return fmt.Errorf("postMessage failed: %w", err) return fmt.Errorf("postMessage failed: %w", err)
} }
return nil return nil
} }

View File

@ -18,7 +18,7 @@ package notifier
import ( import (
"context" "context"
"crypto/tls" "crypto/x509"
"fmt" "fmt"
"io" "io"
"net/http" "net/http"
@ -43,10 +43,10 @@ func Fuzz_AlertManager(f *testing.F) {
})) }))
defer ts.Close() defer ts.Close()
var tlsConfig tls.Config var cert x509.CertPool
_ = fuzz.NewConsumer(seed).GenerateStruct(&tlsConfig) _ = fuzz.NewConsumer(seed).GenerateStruct(&cert)
alertmanager, err := NewAlertmanager(fmt.Sprintf("%s/%s", ts.URL, urlSuffix), "", &tlsConfig, "") alertmanager, err := NewAlertmanager(fmt.Sprintf("%s/%s", ts.URL, urlSuffix), "", &cert)
if err != nil { if err != nil {
return return
} }

View File

@ -38,7 +38,7 @@ func TestAlertmanager_Post(t *testing.T) {
})) }))
defer ts.Close() defer ts.Close()
alertmanager, err := NewAlertmanager(ts.URL, "", nil, "") alertmanager, err := NewAlertmanager(ts.URL, "", nil)
require.NoError(t, err) require.NoError(t, err)
err = alertmanager.Post(context.TODO(), testEvent()) err = alertmanager.Post(context.TODO(), testEvent())

View File

@ -33,21 +33,16 @@ import (
const genre string = "fluxcd" const genre string = "fluxcd"
type azureDevOpsClient interface { // AzureDevOps is a Azure DevOps notifier.
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 { type AzureDevOps struct {
Project string Project string
Repo string Repo string
CommitStatus string ProviderUID string
Client azureDevOpsClient Client git.Client
} }
// NewAzureDevOps creates and returns a new AzureDevOps notifier. // NewAzureDevOps creates and returns a new AzureDevOps notifier.
func NewAzureDevOps(commitStatus string, addr string, token string, certPool *x509.CertPool) (*AzureDevOps, error) { func NewAzureDevOps(providerUID string, addr string, token string, certPool *x509.CertPool) (*AzureDevOps, error) {
if len(token) == 0 { if len(token) == 0 {
return nil, errors.New("azure devops token cannot be empty") return nil, errors.New("azure devops token cannot be empty")
} }
@ -57,11 +52,6 @@ func NewAzureDevOps(commitStatus string, addr string, token string, certPool *x5
return nil, err return nil, err
} }
// this should never happen
if commitStatus == "" {
return nil, errors.New("commit status cannot be empty")
}
comp := strings.Split(id, "/") comp := strings.Split(id, "/")
if len(comp) != 4 { if len(comp) != 4 {
return nil, fmt.Errorf("invalid repository id %q", id) return nil, fmt.Errorf("invalid repository id %q", id)
@ -84,7 +74,7 @@ func NewAzureDevOps(commitStatus string, addr string, token string, certPool *x5
return &AzureDevOps{ return &AzureDevOps{
Project: proj, Project: proj,
Repo: repo, Repo: repo,
CommitStatus: commitStatus, ProviderUID: providerUID,
Client: gitClient, Client: gitClient,
}, nil }, nil
} }
@ -96,7 +86,7 @@ func (a AzureDevOps) Post(ctx context.Context, event eventv1.Event) error {
return nil return nil
} }
revString, ok := event.GetRevision() revString, ok := event.Metadata[eventv1.MetaRevisionKey]
if !ok { if !ok {
return errors.New("missing revision metadata") return errors.New("missing revision metadata")
} }
@ -110,10 +100,9 @@ func (a AzureDevOps) Post(ctx context.Context, event eventv1.Event) error {
} }
// Check if the exact status is already set // Check if the exact status is already set
g := commitStatusGenre(event) g := genre
_, desc := formatNameAndDescription(event) _, desc := formatNameAndDescription(event)
id := a.CommitStatus id := generateCommitStatusID(a.ProviderUID, event)
createArgs := git.CreateCommitStatusArgs{ createArgs := git.CreateCommitStatusArgs{
Project: &a.Project, Project: &a.Project,
RepositoryId: &a.Repo, RepositoryId: &a.Repo,
@ -134,9 +123,8 @@ func (a AzureDevOps) Post(ctx context.Context, event eventv1.Event) error {
} }
statuses, err := a.Client.GetStatuses(ctx, getArgs) statuses, err := a.Client.GetStatuses(ctx, getArgs)
if err != nil { if err != nil {
return fmt.Errorf("could not list commit statuses: %w", err) return fmt.Errorf("could not list commit statuses: %v", err)
} }
if duplicateAzureDevOpsStatus(statuses, createArgs.GitCommitStatusToCreate) { if duplicateAzureDevOpsStatus(statuses, createArgs.GitCommitStatusToCreate) {
return nil return nil
} }
@ -144,7 +132,7 @@ func (a AzureDevOps) Post(ctx context.Context, event eventv1.Event) error {
// Create a new status // Create a new status
_, err = a.Client.CreateCommitStatus(ctx, createArgs) _, err = a.Client.CreateCommitStatus(ctx, createArgs)
if err != nil { if err != nil {
return fmt.Errorf("could not create commit status: %w", err) return fmt.Errorf("could not create commit status: %v", err)
} }
return nil return nil
} }
@ -184,12 +172,3 @@ func duplicateAzureDevOpsStatus(statuses *[]git.GitStatus, status *git.GitStatus
return false return false
} }
func commitStatusGenre(event eventv1.Event) string {
summary, ok := event.Metadata["summary"]
if ok {
return fmt.Sprintf("%s:%s", genre, summary)
}
return genre
}

Some files were not shown because too many files have changed in this diff Show More