Compare commits

..

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

238 changed files with 5499 additions and 51298 deletions

View File

@ -1,39 +0,0 @@
version: 2
updates:
- package-ecosystem: "gomod"
directory: "/"
labels: ["dependencies"]
schedule:
interval: "daily"
groups:
go-deps:
patterns:
- "*"
allow:
- dependency-type: "direct"
ignore:
# Kubernetes deps are updated by fluxcd/pkg/runtime
- dependency-name: "k8s.io/*"
- dependency-name: "sigs.k8s.io/*"
- dependency-name: "github.com/go-logr/*"
# jsondiff is updated by fluxcd/pkg/ssa
- dependency-name: "github.com/wI2L/jsondiff"
# OCI deps are updated by fluxcd/pkg/oci
- dependency-name: "github.com/google/go-containerregistry*"
- dependency-name: "github.com/opencontainers/*"
# Helm deps are updated by fluxcd/pkg/helmtestserver
- dependency-name: "helm.sh/helm/*"
- dependency-name: "github.com/Masterminds/semver/*"
# Flux APIs are updated at release time
- dependency-name: "github.com/fluxcd/helm-controller/api"
- dependency-name: "github.com/fluxcd/source-controller/api"
- package-ecosystem: "github-actions"
directory: "/"
labels: ["area/ci", "dependencies"]
groups:
ci:
patterns:
- "*"
schedule:
interval: "monthly"

27
.github/labels.yaml vendored
View File

@ -1,27 +0,0 @@
# Configuration file to declaratively configure labels
# Ref: https://github.com/EndBug/label-sync#Config-files
- name: area/drift
description: Drift detection/correction related issues and pull requests
color: '#ff5c00'
- name: area/helm
description: Helm related issues and pull requests
color: '#1673b6'
- name: area/kustomize
description: Kustomize (post-rendering) related issues and pull requests
color: '#00e54d'
- name: area/oci
description: OCI related issues and pull requests
color: '#c739ff'
- 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'

View File

@ -1,34 +0,0 @@
name: backport
on:
pull_request_target:
types: [closed, labeled]
permissions:
contents: read
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@0193454f0c5947491d348f33a275c119f30eb736 # v3.2.1
# 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,25 +0,0 @@
name: fuzz
on:
pull_request:
branches:
- "main"
- "release/**"
permissions:
contents: read # for actions/checkout to fetch code
jobs:
smoketest:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Setup Go
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version: 1.24.x
cache-dependency-path: |
**/go.sum
**/go.mod
- name: Smoke test Fuzzers
run: make fuzz-smoketest

View File

@ -1,30 +1,36 @@
name: e2e
on:
workflow_dispatch:
pull_request:
push:
branches:
- "main"
- "release/**"
permissions:
contents: read # for actions/checkout to fetch code
- main
- "feature/**"
jobs:
kind:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@v2
- name: Setup QEMU
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0
uses: docker/setup-qemu-action@v1
with:
platforms: all
- name: Setup Docker Buildx
id: buildx
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
uses: docker/setup-buildx-action@v1
with:
buildkitd-flags: "--debug"
- name: Restore Go cache
uses: actions/cache@v1
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: Cache Docker layers
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
uses: actions/cache@v2
id: cache
with:
path: /tmp/.buildx-cache
@ -32,24 +38,26 @@ jobs:
restore-keys: |
${{ runner.os }}-buildx-ghcache-
- name: Setup Go
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
uses: actions/setup-go@v2
with:
go-version: 1.24.x
cache-dependency-path: |
**/go.sum
**/go.mod
go-version: 1.16.x
- name: Setup Kubernetes
uses: helm/kind-action@a1b0e391336a6ee6713a0583f8c6240d70863de3 # v1.12.0
uses: engineerd/setup-kind@v0.5.0
with:
version: v0.20.0
cluster_name: kind
node_image: kindest/node:v1.27.3@sha256:3966ac761ae0136263ffdb6cfd4db23ef8a83cba8a463690e98317add2c9ba72
version: v0.11.1
image: kindest/node:v1.21.1@sha256:69860bda5563ac81e3c0057d654b5253219618a22ec3a346306239bba8cfa1a6
- name: Setup Helm
uses: fluxcd/pkg/actions/helm@main
- name: Setup Kustomize
uses: fluxcd/pkg/actions/kustomize@main
- name: Setup Kubebuilder
uses: fluxcd/pkg/actions/kubebuilder@main
- name: Setup Kubectl
uses: fluxcd/pkg/actions/kubectl@main
- name: Run tests
run: make test
env:
KUBEBUILDER_ASSETS: ${{ github.workspace }}/kubebuilder/bin
- name: Check if working tree is dirty
run: |
if [[ $(git diff --stat) != '' ]]; then
@ -62,8 +70,7 @@ jobs:
make docker-build IMG=test/helm-controller:latest \
BUILD_PLATFORMS=linux/amd64 \
BUILD_ARGS="--cache-from=type=local,src=/tmp/.buildx-cache \
--cache-to=type=local,dest=/tmp/.buildx-cache-new,mode=max \
--load"
--cache-to=type=local,dest=/tmp/.buildx-cache-new,mode=max"
- # Temp fix
# https://github.com/docker/build-push-action/issues/252
# https://github.com/moby/buildkit/issues/1896
@ -91,14 +98,6 @@ jobs:
kubectl -n helm-system rollout status deploy/helm-controller --timeout=1m
env:
KUBEBUILDER_ASSETS: ${{ github.workspace }}/kubebuilder/bin
- name: Test samples
run: |
kubectl create ns samples
kubectl -n samples apply -f config/samples
kubectl -n samples wait hr/podinfo-ocirepository --for=condition=ready --timeout=4m
kubectl -n samples wait hr/podinfo-gitrepository --for=condition=ready --timeout=4m
kubectl -n samples wait hr/podinfo-helmrepository --for=condition=ready --timeout=4m
kubectl delete ns samples
- name: Install sources
run: |
kubectl -n helm-system apply -f config/testdata/sources
@ -107,7 +106,6 @@ jobs:
kubectl -n helm-system apply -f config/testdata/podinfo
kubectl -n helm-system wait helmreleases/podinfo --for=condition=ready --timeout=4m
kubectl -n helm-system wait helmreleases/podinfo-git --for=condition=ready --timeout=4m
kubectl -n helm-system wait helmreleases/podinfo-oci --for=condition=ready --timeout=4m
kubectl -n helm-system delete -f config/testdata/podinfo
- name: Run dependency tests
run: |
@ -146,16 +144,6 @@ jobs:
kubectl -n install-create-target-ns get deployment install-create-target-ns-install-create-target-ns-podinfo
kubectl -n helm-system delete -f config/testdata/install-create-target-ns
- name: Run install from helmChart test
run: |
kubectl -n helm-system apply -f config/testdata/install-from-hc-source
kubectl -n helm-system wait helmreleases/podinfo-from-hc --for=condition=ready --timeout=4m
kubectl -n helm-system delete -f config/testdata/install-from-hc-source
- name: Run install from ocirepo test
run: |
kubectl -n helm-system apply -f config/testdata/install-from-ocirepo-source
kubectl -n helm-system wait helmreleases/podinfo-from-ocirepo --for=condition=ready --timeout=4m
kubectl -n helm-system delete -f config/testdata/install-from-ocirepo-source
- name: Run install fail test
run: |
test_name=install-fail
@ -187,7 +175,7 @@ jobs:
kubectl -n helm-system apply -f config/testdata/$test_name
echo -n ">>> Waiting for expected conditions"
count=0
until [ 'true' == "$( kubectl -n helm-system get helmrelease/$test_name -o json | jq '.status.conditions | map( { (.type): .status } ) | add | .Released=="True" and .TestSuccess=="False" and .Ready=="False"' )" ]; do
until [ 'true' == "$( kubectl -n helm-system get helmrelease/$test_name -o json | jq '.status.conditions | map( { (.type): .status } ) | add | .Released=="False" and .TestSuccess=="False" and .Ready=="False"' )" ]; do
echo -n '.'
sleep 5
count=$((count + 1))
@ -231,7 +219,7 @@ jobs:
fi
kubectl -n helm-system delete -f config/testdata/$test_name
- name: Run install fail with remediation test
- name: Run install fail with remedition test
run: |
test_name=install-fail-remediate
kubectl -n helm-system apply -f config/testdata/$test_name
@ -248,22 +236,21 @@ jobs:
done
echo ' done'
# Ensure release was uninstalled.
RELEASE_STATUS=$(helm -n helm-system history $test_name -o json | jq -r 'if length == 1 then .[0].status else empty end')
if [ "$RELEASE_STATUS" != "uninstalled" ]; then
echo -e "Unexpected release status: $RELEASE_STATUS"
# Ensure release does not exist (was uninstalled).
HISTORY=$(helm -n helm-system history $test_name 2>&1; exit 0)
if [ "$HISTORY" != 'Error: release: not found' ]; then
echo -e "Unexpected release history: $HISTORY"
exit 1
fi
kubectl -n helm-system delete -f config/testdata/$test_name
helm -n helm-system delete $test_name
- name: Run install fail with retry test
run: |
test_name=install-fail-retry
kubectl -n helm-system apply -f config/testdata/$test_name
echo -n ">>> Waiting for expected conditions"
count=0
until [ 'true' == "$( kubectl -n helm-system get helmrelease/$test_name -o json | jq '.status.installFailures == 2 and ( .status.conditions | map( { (.type): .status } ) | add | .Released=="False" and .Ready=="False" and .Stalled=="True" )' )" ]; do
until [ 'true' == "$( kubectl -n helm-system get helmrelease/$test_name -o json | jq '.status.installFailures == 2 and ( .status.conditions | map( { (.type): .status } ) | add | .Released=="False" and .Ready=="False" )' )" ]; do
echo -n '.'
sleep 5
count=$((count + 1))
@ -309,7 +296,7 @@ jobs:
kubectl -n helm-system apply -f config/testdata/$test_name/upgrade.yaml
echo -n ">>> Waiting for expected conditions"
count=0
until [ 'true' == "$( kubectl -n helm-system get helmrelease/$test_name -o json | jq '.status.conditions | map( { (.type): .status } ) | add | .Released=="False" and .Ready=="False" and .Stalled=="True"' )" ]; do
until [ 'true' == "$( kubectl -n helm-system get helmrelease/$test_name -o json | jq '.status.conditions | map( { (.type): .status } ) | add | .Released=="False" and .Ready=="False"' )" ]; do
echo -n '.'
sleep 5
count=$((count + 1))
@ -355,7 +342,7 @@ jobs:
kubectl -n helm-system apply -f config/testdata/$test_name/upgrade.yaml
echo -n ">>> Waiting for expected conditions"
count=0
until [ 'true' == "$( kubectl -n helm-system get helmrelease/$test_name -o json | jq '.status.conditions | map( { (.type): .status } ) | add | .Released=="True" and .TestSuccess=="False" and .Ready=="False" and .Stalled=="True"' )" ]; do
until [ 'true' == "$( kubectl -n helm-system get helmrelease/$test_name -o json | jq '.status.conditions | map( { (.type): .status } ) | add | .Released=="False" and .TestSuccess=="False" and .Ready=="False"' )" ]; do
echo -n '.'
sleep 5
count=$((count + 1))
@ -476,45 +463,6 @@ jobs:
fi
kubectl delete -n helm-system -f config/testdata/$test_name/install.yaml
- name: Run upgrade from ocirepo source
run: |
test_name=upgrade-from-ocirepo-source
kubectl -n helm-system apply -f config/testdata/$test_name/install.yaml
echo -n ">>> Waiting for expected conditions"
count=0
until [ 'true' == "$( kubectl -n helm-system get helmrelease/$test_name -o json | jq '.status.conditions | map( { (.type): .status } ) | add | .Released=="True" and .Ready=="True"' )" ]; do
echo -n '.'
sleep 5
count=$((count + 1))
if [[ ${count} -eq 24 ]]; then
echo ' No more retries left!'
exit 1
fi
done
echo ' done'
# Validate release was installed.
REVISION_COUNT=$(helm -n helm-system history -o json $test_name | jq 'length')
if [ "$REVISION_COUNT" != 1 ]; then
echo -e "Unexpected revision count: $REVISION_COUNT"
exit 1
fi
kubectl -n helm-system apply -f config/testdata/$test_name/upgrade.yaml
echo -n ">>> Waiting for expected conditions"
count=0
until [ 'true' == "$( kubectl -n helm-system get helmrelease/$test_name -o json | jq '.status.conditions | map( { (.type): .status } ) | add | .Released=="True" and .Ready=="True"' )" ]; do
echo -n '.'
sleep 5
count=$((count + 1))
if [[ ${count} -eq 24 ]]; then
echo ' No more retries left!'
exit 1
fi
done
echo ' done'
kubectl delete -n helm-system -f config/testdata/$test_name/install.yaml
- name: Run upgrade fail with uninstall remediation strategy test
run: |
test_name=upgrade-fail-remediate-uninstall
@ -589,19 +537,6 @@ jobs:
fi
done
echo ' done'
- name: Run delete-ns tests
run: |
kubectl apply -f config/testdata/delete-ns
kubectl -n delete-ns wait helmreleases/podinfo --for=condition=ready --timeout=2m
kubectl delete ns delete-ns 1>/dev/null 2>&1 &
echo -n ">>> Waiting for namespace to be deleted"
if kubectl wait --for=delete namespace delete-ns --timeout=5m; then
echo ' Namespace deleted successfully'
else
echo ' Timed out waiting for namespace to be deleted'
kubectl get all -n delete-ns
exit 1
fi
- name: Run post-renderer-kustomize test
run: |
kubectl -n helm-system apply -f config/testdata/post-renderer-kustomize
@ -617,7 +552,7 @@ jobs:
exit 1
fi
kubectl -n helm-system delete -f config/testdata/post-renderer-kustomize
- name: Bootstrap CRDs Upgrade Tests
- name: Boostrap CRDs Upgrade Tests
if: ${{ startsWith(github.ref, 'refs/tags/') || startsWith(github.ref, 'refs/heads/') }}
run: |
REF=${{ github.ref }}
@ -654,6 +589,9 @@ jobs:
- name: Debug failure
if: failure()
run: |
which kubectl
kubectl version
helm version
kubectl -n helm-system get helmrepositories -oyaml || true
kubectl -n helm-system get helmcharts -oyaml || true
kubectl -n helm-system get helmreleases -oyaml || true

View File

@ -4,9 +4,6 @@ on:
- cron: '0 0 * * *'
workflow_dispatch:
permissions:
contents: read # for actions/checkout to fetch code
env:
REPOSITORY: ${{ github.repository }}
@ -14,17 +11,18 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@v2
- name: Setup QEMU
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0
uses: docker/setup-qemu-action@v1
with:
platforms: all
- name: Setup Docker Buildx
id: buildx
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
uses: docker/setup-buildx-action@v1
with:
buildkitd-flags: "--debug"
- name: Build multi-arch container image
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
uses: docker/build-push-action@v2
with:
push: false
builder: ${{ steps.buildx.outputs.name }}

View File

@ -7,29 +7,17 @@ on:
inputs:
tag:
description: 'image tag prefix'
default: 'preview'
default: 'rc'
required: true
permissions:
contents: read
env:
CONTROLLER: ${{ github.event.repository.name }}
jobs:
release:
outputs:
hashes: ${{ steps.slsa.outputs.hashes }}
image_url: ${{ steps.slsa.outputs.image_url }}
image_digest: ${{ steps.slsa.outputs.image_digest }}
build-push:
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:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@v2
- name: Setup Kustomize
uses: fluxcd/pkg/actions/kustomize@main
- name: Prepare
@ -39,122 +27,65 @@ jobs:
if [[ $GITHUB_REF == refs/tags/* ]]; then
VERSION=${GITHUB_REF/refs\/tags\//}
fi
echo "BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_OUTPUT
echo "VERSION=${VERSION}" >> $GITHUB_OUTPUT
echo ::set-output name=BUILD_DATE::$(date -u +'%Y-%m-%dT%H:%M:%SZ')
echo ::set-output name=VERSION::${VERSION}
- name: Setup QEMU
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0
uses: docker/setup-qemu-action@v1
with:
platforms: all
- name: Setup Docker Buildx
id: buildx
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
uses: docker/setup-buildx-action@v1
with:
buildkitd-flags: "--debug"
- name: Login to GitHub Container Registry
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
uses: docker/login-action@v1
with:
registry: ghcr.io
username: fluxcdbot
password: ${{ secrets.GHCR_TOKEN }}
- name: Login to Docker Hub
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
uses: docker/login-action@v1
with:
username: fluxcdbot
password: ${{ secrets.DOCKER_FLUXCD_PASSWORD }}
- name: Generate images meta
id: meta
uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0
- name: Publish multi-arch container image
uses: docker/build-push-action@v2
with:
images: |
fluxcd/${{ env.CONTROLLER }}
ghcr.io/fluxcd/${{ env.CONTROLLER }}
tags: |
type=raw,value=${{ steps.prep.outputs.VERSION }}
- name: Publish images
id: build-push
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
with:
sbom: true
provenance: true
push: true
builder: ${{ steps.buildx.outputs.name }}
context: .
file: ./Dockerfile
platforms: linux/amd64,linux/arm/v7,linux/arm64
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
- uses: sigstore/cosign-installer@398d4b0eeef1380460a10c8013a76f728fb906ac # v3.9.1
- name: Sign images
env:
COSIGN_EXPERIMENTAL: 1
tags: |
ghcr.io/fluxcd/${{ env.CONTROLLER }}:${{ steps.prep.outputs.VERSION }}
docker.io/fluxcd/${{ env.CONTROLLER }}:${{ steps.prep.outputs.VERSION }}
labels: |
org.opencontainers.image.title=${{ github.event.repository.name }}
org.opencontainers.image.description=${{ github.event.repository.description }}
org.opencontainers.image.url=${{ github.event.repository.html_url }}
org.opencontainers.image.revision=${{ github.sha }}
org.opencontainers.image.version=${{ steps.prep.outputs.VERSION }}
org.opencontainers.image.created=${{ steps.prep.outputs.BUILD_DATE }}
- name: Check images
run: |
cosign sign --yes fluxcd/${{ env.CONTROLLER }}@${{ steps.build-push.outputs.digest }}
cosign sign --yes ghcr.io/fluxcd/${{ env.CONTROLLER }}@${{ steps.build-push.outputs.digest }}
- name: Generate release artifacts
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 }}
- name: Generate release manifests
if: startsWith(github.ref, 'refs/tags/v')
run: |
mkdir -p config/release
kustomize build ./config/crd > ./config/release/${{ env.CONTROLLER }}.crds.yaml
kustomize build ./config/manager > ./config/release/${{ env.CONTROLLER }}.deployment.yaml
- uses: anchore/sbom-action/download-syft@cee1b8e05ae5b2593a75e197229729eabaa9f8ec # v0.20.2
- name: Create release and SBOM
id: run-goreleaser
- name: Create release
if: startsWith(github.ref, 'refs/tags/v')
uses: goreleaser/goreleaser-action@9c156ee8a17a598857849441385a2041ef570552 # v6.3.0
uses: ncipollo/release-action@v1
with:
version: latest
args: release --clean --skip=validate
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Generate SLSA metadata
id: slsa
env:
ARTIFACTS: "${{ steps.run-goreleaser.outputs.artifacts }}"
run: |
hashes=$(echo -E $ARTIFACTS | jq --raw-output '.[] | {name, "digest": (.extra.Digest // .extra.Checksum)} | select(.digest) | {digest} + {name} | join(" ") | sub("^sha256:";"")' | base64 -w0)
echo "hashes=$hashes" >> $GITHUB_OUTPUT
image_url=fluxcd/${{ env.CONTROLLER }}:${{ steps.prep.outputs.version }}
echo "image_url=$image_url" >> $GITHUB_OUTPUT
image_digest=${{ steps.build-push.outputs.digest }}
echo "image_digest=$image_digest" >> $GITHUB_OUTPUT
release-provenance:
needs: [release]
permissions:
actions: read # for detecting the Github Actions environment.
id-token: write # for creating OIDC tokens for signing.
contents: write # for uploading attestations to GitHub releases.
if: startsWith(github.ref, 'refs/tags/v')
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.1.0
with:
provenance-name: "provenance.intoto.jsonl"
base64-subjects: "${{ needs.release.outputs.hashes }}"
upload-assets: true
dockerhub-provenance:
needs: [release]
permissions:
actions: read # for detecting the Github Actions environment.
id-token: write # for creating OIDC tokens for signing.
packages: write # for uploading attestations.
if: startsWith(github.ref, 'refs/tags/v')
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v2.1.0
with:
image: ${{ needs.release.outputs.image_url }}
digest: ${{ needs.release.outputs.image_digest }}
registry-username: fluxcdbot
secrets:
registry-password: ${{ secrets.DOCKER_FLUXCD_PASSWORD }}
ghcr-provenance:
needs: [release]
permissions:
actions: read # for detecting the Github Actions environment.
id-token: write # for creating OIDC tokens for signing.
packages: write # for uploading attestations.
if: startsWith(github.ref, 'refs/tags/v')
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v2.1.0
with:
image: ghcr.io/${{ needs.release.outputs.image_url }}
digest: ${{ needs.release.outputs.image_digest }}
registry-username: fluxcdbot
secrets:
registry-password: ${{ secrets.GHCR_TOKEN }}
prerelease: true
artifacts: "config/release/*.yaml"
artifactContentType: "text/plain"
body: |
[CHANGELOG](https://github.com/fluxcd/${{ env.CONTROLLER }}/blob/main/CHANGELOG.md)
token: ${{ secrets.GITHUB_TOKEN }}

View File

@ -1,51 +1,55 @@
name: scan
name: Scan
on:
push:
branches: [ "main", "release/**" ]
branches: [ main ]
pull_request:
branches: [ "main", "release/**" ]
branches: [ main ]
schedule:
- cron: '18 10 * * 3'
permissions:
contents: read # for actions/checkout to fetch code
security-events: write # for codeQL to write security events
jobs:
fossa:
name: FOSSA
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@v2
- name: Run FOSSA scan and upload build data
uses: fossa-contrib/fossa-action@3d2ef181b1820d6dcd1972f86a767d18167fa19b # v3.0.1
uses: fossa-contrib/fossa-action@v1
with:
# FOSSA Push-Only API Token
fossa-api-key: 5ee8bf422db1471e0bcf2bcb289185de
github-token: ${{ github.token }}
snyk:
name: Snyk
runs-on: ubuntu-latest
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
steps:
- uses: actions/checkout@v2
- name: Run Snyk to check for vulnerabilities
uses: snyk/actions/golang@master
continue-on-error: true
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
args: --sarif-file-output=snyk.sarif
- name: Upload result to GitHub Code Scanning
uses: github/codeql-action/upload-sarif@v1
with:
sarif_file: snyk.sarif
codeql:
name: CodeQL
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Setup Go
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version: 1.24.x
cache-dependency-path: |
**/go.sum
**/go.mod
- name: Checkout repository
uses: actions/checkout@v2
- name: Initialize CodeQL
uses: github/codeql-action/init@181d5eefc20863364f96762470ba6f862bdef56b # v3.29.2
uses: github/codeql-action/init@v1
with:
languages: go
# xref: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# xref: https://codeql.github.com/codeql-query-help/go/
queries: security-and-quality
- name: Autobuild
uses: github/codeql-action/autobuild@181d5eefc20863364f96762470ba6f862bdef56b # v3.29.2
uses: github/codeql-action/autobuild@v1
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@181d5eefc20863364f96762470ba6f862bdef56b # v3.29.2
uses: github/codeql-action/analyze@v1

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

2
.gitignore vendored
View File

@ -21,5 +21,3 @@ bin
*.swp
*.swo
*~
build/

View File

@ -1,57 +0,0 @@
project_name: helm-controller
builds:
- skip: true
release:
extra_files:
- glob: config/release/*.yaml
prerelease: "auto"
header: |
## Changelog
[{{.Tag}} changelog](https://github.com/fluxcd/{{.ProjectName}}/blob/{{.Tag}}/CHANGELOG.md)
footer: |
## Container images
- `docker.io/fluxcd/{{.ProjectName}}:{{.Tag}}`
- `ghcr.io/fluxcd/{{.ProjectName}}:{{.Tag}}`
Supported architectures: `linux/amd64`, `linux/arm64` and `linux/arm/v7`.
The container images are built on GitHub hosted runners and are signed with cosign and GitHub OIDC.
To verify the images and their provenance (SLSA level 3), please see the [security documentation](https://fluxcd.io/flux/security/).
changelog:
disable: true
checksum:
extra_files:
- glob: config/release/*.yaml
source:
enabled: true
name_template: "{{ .ProjectName }}_{{ .Version }}_source_code"
sboms:
- id: source
artifacts: source
documents:
- "{{ .ProjectName }}_{{ .Version }}_sbom.spdx.json"
# signs the checksum file
# all files (including the sboms) are included in the checksum
# https://goreleaser.com/customization/sign
signs:
- cmd: cosign
env:
- COSIGN_EXPERIMENTAL=1
certificate: "${artifact}.pem"
args:
- sign-blob
- "--yes"
- "--output-certificate=${certificate}"
- "--output-signature=${signature}"
- "${artifact}"
artifacts: checksum
output: true

File diff suppressed because it is too large Load Diff

View File

@ -1,32 +1,17 @@
# Development
> **Note:** Please take a look at <https://fluxcd.io/contributing/flux/>
> **Note:** Please take a look at <https://fluxcd.io/docs/contributing/flux/>
> to find out about how to contribute to Flux and how to interact with the
> Flux Development team.
## Installing required dependencies
There are a number of dependencies required to be able to run the controller and its test suite locally:
- [Install Go](https://golang.org/doc/install)
- [Install Kustomize](https://kubernetes-sigs.github.io/kustomize/installation/)
- [Install Docker](https://docs.docker.com/engine/install/)
- (Optional) [Install Kubebuilder](https://book.kubebuilder.io/quick-start.html#installation)
In addition to the above, the following dependencies are also used by some of the `make` targets:
- `controller-gen` (v0.7.0)
- `gen-crd-api-reference-docs` (v0.3.0)
- `setup-envtest` (latest)
If any of the above dependencies are not present on your system, the first invocation of a `make` target that requires them will install them.
## How to run the test suite
Prerequisites:
* Go >= 1.24
* go >= 1.16
* kubebuilder >= 2.3
* kustomize >= 3.1
You can run the test suite by simply doing
You can run the unit tests by simply doing
```bash
make test
@ -34,13 +19,17 @@ make test
## How to run the controller locally
Install the controller's CRDs on your test cluster:
Install flux on your test cluster:
```sh
make install
flux install
```
Note that `helm-controller` depends on [source-controller](https://github.com/fluxcd/source-controller) to acquire the Helm charts from Helm repositories. If `source-controller` is not running on your test cluster, you need to tell `helm-controller` where to find it.
Scale the in-cluster controller to zero:
```sh
kubectl -n flux-system scale deployment/helm-controller --replicas=0
```
Port forward to source-controller artifacts server:
@ -54,47 +43,8 @@ Export the local address as `SOURCE_CONTROLLER_LOCALHOST`:
export SOURCE_CONTROLLER_LOCALHOST=localhost:8080
```
Alternatively, if your test cluster is already running `source-controller` and `helm-controller`, you need to scale down the in-cluster `helm-controller`:
```
kubectl -n flux-system scale deployment/helm-controller --replicas=0
```
Run the controller locally:
```sh
make run
```
## How to install the controller
### Building the container image
Set the name of the container image to be created from the source code. This will be used when building, pushing and referring to the image on YAML files:
```sh
export IMG=registry-path/helm-controller:latest
```
Build the container image, tagging it as `$(IMG)`:
```sh
make docker-build
```
Push the image into the repository:
```sh
make docker-push
```
**Note**: `make docker-build` will build an image for the `amd64` architecture.
### Deploying into a cluster
Deploy `helm-controller` into the cluster that is configured in the local kubeconfig file (i.e. `~/.kube/config`):
```sh
make deploy
```

View File

@ -1,10 +1,9 @@
ARG GO_VERSION=1.24
ARG XX_VERSION=1.6.1
ARG XX_VERSION=1.0.0-rc.2
FROM --platform=$BUILDPLATFORM tonistiigi/xx:${XX_VERSION} AS xx
# Docker buildkit multi-arch build requires golang alpine
FROM --platform=$BUILDPLATFORM golang:${GO_VERSION}-alpine AS builder
FROM --platform=$BUILDPLATFORM golang:1.16-alpine as builder
# Copy the build utilities.
COPY --from=xx / /
@ -25,19 +24,24 @@ RUN go mod download
# copy source code
COPY main.go main.go
COPY controllers/ controllers/
COPY internal/ internal/
# build without specifing the arch
ENV CGO_ENABLED=0
RUN xx-go build -trimpath -a -o helm-controller main.go
RUN xx-go build -a -o helm-controller main.go
FROM alpine:3.21
FROM alpine:3.13
RUN apk add --no-cache ca-certificates \
&& update-ca-certificates
# link repo to the GitHub Container Registry image
LABEL org.opencontainers.image.source="https://github.com/fluxcd/helm-controller"
RUN apk add --no-cache ca-certificates tini
COPY --from=builder /workspace/helm-controller /usr/local/bin/
USER 65534:65534
RUN addgroup -S controller && adduser -S controller -G controller
ENTRYPOINT [ "helm-controller" ]
USER controller
ENTRYPOINT [ "/sbin/tini", "--", "helm-controller" ]

View File

@ -8,8 +8,6 @@ from the main Flux v2 git repository, as listed in
https://github.com/fluxcd/flux2/blob/main/MAINTAINERS
Retired maintainers:
In alphabetical order:
- Sean Eagan
Thank you for your involvement, and let us not say "farewell" ...
Sean Eagan, AT&T <sean.eagan@att.com> (github: @seaneagan, slack: seaneagan)

153
Makefile
View File

@ -3,56 +3,28 @@ IMG ?= fluxcd/helm-controller:latest
# Produce CRDs that work back to Kubernetes 1.16
CRD_OPTIONS ?= crd:crdVersions=v1
# Repository root based on Git metadata
REPOSITORY_ROOT := $(shell git rev-parse --show-toplevel)
BUILD_DIR := $(REPOSITORY_ROOT)/build
# FUZZ_TIME defines the max amount of time, in Go Duration,
# each fuzzer should run for.
FUZZ_TIME ?= 1m
# If gobin not set, create one on ./build and add to path.
# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
ifeq (,$(shell go env GOBIN))
GOBIN=$(BUILD_DIR)/gobin
GOBIN=$(shell go env GOPATH)/bin
else
GOBIN=$(shell go env GOBIN)
endif
export PATH:=$(GOBIN):${PATH}
# Allows for defining additional Docker buildx arguments, e.g. '--push'.
BUILD_ARGS ?= --load
BUILD_ARGS ?=
# Architectures to build images for.
BUILD_PLATFORMS ?= linux/amd64
# Architecture to use envtest with
ENVTEST_ARCH ?= amd64
# Paths to download the CRD dependency to.
CRD_DEP_ROOT ?= $(BUILD_DIR)/config/crd/bases
# Keep a record of the version of the downloaded source CRDs. It is used to
# detect and download new CRDs when the SOURCE_VER changes.
SOURCE_VER ?= $(shell go list -m all | grep github.com/fluxcd/source-controller/api | awk '{print $$2}')
SOURCE_CRD_VER = $(CRD_DEP_ROOT)/.src-crd-$(SOURCE_VER)
# HelmChart source CRD.
HELMCHART_SOURCE_CRD ?= $(CRD_DEP_ROOT)/source.toolkit.fluxcd.io_helmcharts.yaml
# API (doc) generation utilities
CONTROLLER_GEN_VERSION ?= v0.16.1
GEN_API_REF_DOCS_VERSION ?= e327d0730470cbd61b06300f81c5fcf91c23c113
all: manager
# Run tests
KUBEBUILDER_ASSETS?="$(shell $(ENVTEST) --arch=$(ENVTEST_ARCH) use -i $(ENVTEST_KUBERNETES_VERSION) --bin-dir=$(ENVTEST_ASSETS_DIR) -p path)"
test: tidy generate fmt vet manifests api-docs install-envtest download-crd-deps
KUBEBUILDER_ASSETS=$(KUBEBUILDER_ASSETS) go test ./... -coverprofile cover.out
test: generate fmt vet manifests api-docs
go test ./... -coverprofile cover.out
cd api; go test ./... -coverprofile cover.out
# Build manager binary
manager: generate fmt vet
go build -o $(BUILD_DIR)/bin/manager main.go
go build -o bin/manager main.go
# Run against the configured Kubernetes cluster in ~/.kube/config
run: generate fmt vet manifests
@ -92,12 +64,12 @@ manifests: controller-gen
# Generate API reference documentation
api-docs: gen-crd-api-reference-docs
$(GEN_CRD_API_REFERENCE_DOCS) -api-dir=./api/v2 -config=./hack/api-docs/config.json -template-dir=./hack/api-docs/template -out-file=./docs/api/v2/helm.md
$(API_REF_GEN) -api-dir=./api/v2beta1 -config=./hack/api-docs/config.json -template-dir=./hack/api-docs/template -out-file=./docs/api/helmrelease.md
# Run go mod tidy
tidy:
cd api; rm -f go.sum; go mod tidy -compat=1.23
rm -f go.sum; go mod tidy -compat=1.23
cd api; rm -f go.sum; go mod tidy
rm -f go.sum; go mod tidy
# Run go fmt against code
fmt:
@ -118,90 +90,41 @@ docker-build:
docker buildx build \
--platform=$(BUILD_PLATFORMS) \
-t ${IMG} \
--load \
${BUILD_ARGS} .
# Push the docker image
docker-push:
docker push ${IMG}
# Delete previously downloaded CRDs and record the new version of the source
# CRDs.
$(SOURCE_CRD_VER):
rm -f $(CRD_DEP_ROOT)/.src-crd*
mkdir -p $(CRD_DEP_ROOT)
$(MAKE) cleanup-crd-deps
touch $(SOURCE_CRD_VER)
$(HELMCHART_SOURCE_CRD):
curl -s https://raw.githubusercontent.com/fluxcd/source-controller/${SOURCE_VER}/config/crd/bases/source.toolkit.fluxcd.io_helmcharts.yaml > $(HELMCHART_SOURCE_CRD)
# Download the CRDs the controller depends on
download-crd-deps: $(SOURCE_CRD_VER) $(HELMCHART_SOURCE_CRD)
# Delete the downloaded CRD dependencies.
cleanup-crd-deps:
rm -f $(HELMCHART_SOURCE_CRD)
# Find or download controller-gen
CONTROLLER_GEN = $(GOBIN)/controller-gen
.PHONY: controller-gen
controller-gen: ## Download controller-gen locally if necessary.
$(call go-install-tool,$(CONTROLLER_GEN),sigs.k8s.io/controller-tools/cmd/controller-gen@$(CONTROLLER_GEN_VERSION))
controller-gen:
ifeq (, $(shell which controller-gen))
@{ \
set -e ;\
CONTROLLER_GEN_TMP_DIR=$$(mktemp -d) ;\
cd $$CONTROLLER_GEN_TMP_DIR ;\
go mod init tmp ;\
go get sigs.k8s.io/controller-tools/cmd/controller-gen@v0.5.0 ;\
rm -rf $$CONTROLLER_GEN_TMP_DIR ;\
}
CONTROLLER_GEN=$(GOBIN)/controller-gen
else
CONTROLLER_GEN=$(shell which controller-gen)
endif
# Find or download gen-crd-api-reference-docs
GEN_CRD_API_REFERENCE_DOCS = $(GOBIN)/gen-crd-api-reference-docs
.PHONY: gen-crd-api-reference-docs
gen-crd-api-reference-docs: ## Download gen-crd-api-reference-docs locally if necessary
$(call go-install-tool,$(GEN_CRD_API_REFERENCE_DOCS),github.com/ahmetb/gen-crd-api-reference-docs@$(GEN_API_REF_DOCS_VERSION))
ENVTEST_ASSETS_DIR=$(BUILD_DIR)/testbin
ENVTEST_KUBERNETES_VERSION?=latest
install-envtest: setup-envtest
mkdir -p ${ENVTEST_ASSETS_DIR}
$(ENVTEST) use $(ENVTEST_KUBERNETES_VERSION) --arch=$(ENVTEST_ARCH) --bin-dir=$(ENVTEST_ASSETS_DIR)
ENVTEST = $(GOBIN)/setup-envtest
.PHONY: envtest
setup-envtest: ## Download envtest-setup locally if necessary.
$(call go-install-tool,$(ENVTEST),sigs.k8s.io/controller-runtime/tools/setup-envtest@latest)
# go-install-tool will 'go install' any package $2 and install it to $1.
PROJECT_DIR := $(shell dirname $(abspath $(lastword $(MAKEFILE_LIST))))
define go-install-tool
@[ -f $(1) ] || { \
set -e ;\
TMP_DIR=$$(mktemp -d) ;\
cd $$TMP_DIR ;\
go mod init tmp ;\
echo "Downloading $(2)" ;\
GOBIN=$(GOBIN) go install $(2) ;\
rm -rf $$TMP_DIR ;\
}
endef
# Build fuzzers used by oss-fuzz.
fuzz-build:
rm -rf $(BUILD_DIR)/fuzz/
mkdir -p $(BUILD_DIR)/fuzz/out/
docker build . --pull --tag local-fuzzing:latest -f tests/fuzz/Dockerfile.builder
docker run --rm \
-e FUZZING_LANGUAGE=go -e SANITIZER=address \
-e CIFUZZ_DEBUG='True' -e OSS_FUZZ_PROJECT_NAME=fluxcd \
-v "$(shell go env GOMODCACHE):/root/go/pkg/mod" \
-v "$(BUILD_DIR)/fuzz/out":/out \
local-fuzzing:latest
# Run each fuzzer once to ensure they will work when executed by oss-fuzz.
fuzz-smoketest: fuzz-build
docker run --rm \
-v "$(BUILD_DIR)/fuzz/out":/out \
-v "$(REPOSITORY_ROOT)/tests/fuzz/oss_fuzz_run.sh":/runner.sh \
local-fuzzing:latest \
bash -c "/runner.sh"
# Run fuzz tests for the duration set in FUZZ_TIME.
fuzz-native:
KUBEBUILDER_ASSETS=$(KUBEBUILDER_ASSETS) \
FUZZ_TIME=$(FUZZ_TIME) \
./tests/fuzz/native_go_run.sh
gen-crd-api-reference-docs:
ifeq (, $(shell which gen-crd-api-reference-docs))
@{ \
set -e ;\
API_REF_GEN_TMP_DIR=$$(mktemp -d) ;\
cd $$API_REF_GEN_TMP_DIR ;\
go mod init tmp ;\
go get github.com/ahmetb/gen-crd-api-reference-docs@v0.3.0 ;\
rm -rf $$API_REF_GEN_TMP_DIR ;\
}
API_REF_GEN=$(GOBIN)/gen-crd-api-reference-docs
else
API_REF_GEN=$(shell which gen-crd-api-reference-docs)
endif

View File

@ -4,11 +4,4 @@ resources:
- group: helm
kind: HelmRelease
version: v2beta1
- group: helm
kind: HelmRelease
version: v2beta2
- group: helm
kind: HelmRelease
version: v2
storageVersion: v2
version: "2"

View File

@ -7,7 +7,7 @@
[![release](https://img.shields.io/github/release/fluxcd/helm-controller/all.svg)](https://github.com/fluxcd/helm-controller/releases)
The helm-controller is a Kubernetes operator, allowing one to declaratively
manage Helm chart releases. It is part of a composable [GitOps toolkit](https://fluxcd.io/flux/components)
manage Helm chart releases. It is part of a composable [GitOps toolkit](https://toolkit.fluxcd.io)
and depends on [source-controller][] to acquire the Helm charts from Helm
repositories.
@ -24,7 +24,7 @@ operator.
* Supports `HelmChart` artifacts produced from `HelmRepository`,
`GitRepository` and `Bucket` sources
* Fetches artifacts produced by [source-controller][] from `HelmChart`
and `OCIRepository` objects
objects
* Watches `HelmChart` objects for revision changes (including semver
ranges for charts from `HelmRepository` sources)
* Performs automated Helm actions, including Helm tests, rollbacks and
@ -38,18 +38,16 @@ operator.
[notification-controller][])
* Built-in Kustomize compatible Helm post renderer, providing support
for strategic merge, JSON 6902 and images patches
* Supports detecting and correcting in-cluster changes compared to the desired
state of the Helm release
## Guides
* [Get started with Flux](https://fluxcd.io/flux/get-started/)
* [Manage Helm Releases](https://fluxcd.io/flux/guides/helmreleases/)
* [Setup Notifications](https://fluxcd.io/flux/guides/notifications/)
* [Get started with GitOps Toolkit](https://toolkit.fluxcd.io/get-started/)
* [Manage Helm Releases](https://toolkit.fluxcd.io/guides/helmreleases/)
* [Setup Notifications](https://toolkit.fluxcd.io/guides/notifications/)
## Specifications
* [API](docs/spec/v2/README.md)
* [API](docs/spec/v2beta1/README.md)
* [Controller](docs/spec/README.md)
[source-controller]: https://github.com/fluxcd/source-controller

View File

@ -1,33 +1,12 @@
module github.com/fluxcd/helm-controller/api
go 1.24.0
go 1.16
require (
github.com/fluxcd/pkg/apis/kustomize v1.11.0
github.com/fluxcd/pkg/apis/meta v1.18.0
k8s.io/apiextensions-apiserver v0.33.2
k8s.io/apimachinery v0.33.2
sigs.k8s.io/controller-runtime v0.21.0
sigs.k8s.io/yaml v1.5.0
)
require (
github.com/fxamacker/cbor/v2 v2.8.0 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/spf13/pflag v1.0.6 // indirect
github.com/x448/float16 v0.8.4 // indirect
go.yaml.in/yaml/v2 v2.4.2 // indirect
golang.org/x/net v0.41.0 // indirect
golang.org/x/text v0.27.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
k8s.io/klog/v2 v2.130.1 // indirect
k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e // indirect
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
sigs.k8s.io/randfill v1.0.0 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.7.0 // indirect
github.com/fluxcd/pkg/apis/kustomize v0.1.0
github.com/fluxcd/pkg/apis/meta v0.10.0
github.com/fluxcd/pkg/runtime v0.12.0
k8s.io/apiextensions-apiserver v0.22.1
k8s.io/apimachinery v0.22.1
sigs.k8s.io/controller-runtime v0.9.5
)

View File

@ -1,121 +1,831 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
github.com/Azure/go-ansiterm v0.0.0-20210608223527-2377c96fe795/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
github.com/Azure/go-autorest/autorest v0.11.12/go.mod h1:eipySxLmqSyC5s5k1CLupqet0PSENBEDP93LQ9a8QYw=
github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA=
github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A=
github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M=
github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74=
github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo=
github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA=
github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fluxcd/pkg/apis/kustomize v1.11.0 h1:0IzDgxZkc4v+5SDNCvgZhfwfkdkQLPXCner7TNaJFWE=
github.com/fluxcd/pkg/apis/kustomize v1.11.0/go.mod h1:j302mJGDww8cn9qvMsRQ0LJ1HPAPs/IlX7CSsoJV7BI=
github.com/fluxcd/pkg/apis/meta v1.18.0 h1:ACHrMIjlcioE9GKS7NGk62KX4NshqNewr8sBwMcXABs=
github.com/fluxcd/pkg/apis/meta v1.18.0/go.mod h1:97l3hTwBpJbXBY+wetNbqrUsvES8B1jGioKcBUxmqd8=
github.com/fxamacker/cbor/v2 v2.8.0 h1:fFtUGXUzXPHTIUdne5+zzMPTfffl3RD5qYnkY40vtxU=
github.com/fxamacker/cbor/v2 v2.8.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ=
github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/fluxcd/pkg/apis/kustomize v0.1.0 h1:sauL+KHmZ0zV2ZgpsLMyDzCQudBTtaFzSys+rXn9g9w=
github.com/fluxcd/pkg/apis/kustomize v0.1.0/go.mod h1:gEl+W5cVykCC3RfrCaqe+Pz+j4lKl2aeR4dxsom/zII=
github.com/fluxcd/pkg/apis/meta v0.10.0 h1:N7wVGHC1cyPdT87hrDC7UwCwRwnZdQM46PBSLjG2rlE=
github.com/fluxcd/pkg/apis/meta v0.10.0/go.mod h1:CW9X9ijMTpNe7BwnokiUOrLl/h13miwVr/3abEQLbKE=
github.com/fluxcd/pkg/runtime v0.12.0 h1:BPZZ8bBkimpqGAPXqOf3LTaw+tcw6HgbWyCuzbbsJGs=
github.com/fluxcd/pkg/runtime v0.12.0/go.mod h1:EyaTR2TOYcjL5U//C4yH3bt2tvTgIOSXpVRbWxUn/C4=
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
github.com/go-logr/logr v0.4.0 h1:K7/B1jt6fIBQVd4Owv2MqGQClcgf0R266+7C/QjRcLc=
github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
github.com/go-logr/zapr v0.4.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk=
github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg=
github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
github.com/go-openapi/spec v0.19.5/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk=
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
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/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g=
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg=
github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU=
github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-retryablehttp v0.6.8/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ=
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc=
github.com/moby/term v0.0.0-20210610120745-9d4ed1856297/go.mod h1:vgPCkQMyxTZ7IDy8SXRufE172gr8+K/JE/7hHFxHW3A=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/onsi/ginkgo/v2 v2.22.0 h1:Yed107/8DjTr0lKCNt7Dn8yQ6ybuDRQoMGrNFKzMfHg=
github.com/onsi/ginkgo/v2 v2.22.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=
github.com/onsi/gomega v1.36.1 h1:bJDPBO7ibjxcbHMgSCoo4Yj18UWbKDlLwX1x9sybDcw=
github.com/onsi/gomega v1.36.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E=
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY=
github.com/onsi/gomega v1.14.0 h1:ep6kpPVwmr/nTbklSx2nrLNSIO62DoYAhnPNIMhK8gI=
github.com/onsi/gomega v1.14.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
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/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI=
github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
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.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/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
go.yaml.in/yaml/v3 v3.0.3 h1:bXOww4E/J3f66rav3pX3m8w6jDE4knZjGOw8b5Y6iNE=
go.yaml.in/yaml/v3 v3.0.3/go.mod h1:tBHosrYAkRZjRAOREWbDnBXUf08JOwYq++0QNwQiWzI=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg=
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ=
go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0=
go.etcd.io/etcd/pkg/v3 v3.5.0/go.mod h1:UzJGatBQ1lXChBkQF0AuAtkRQMYnHubxAEYIrC3MSsE=
go.etcd.io/etcd/raft/v3 v3.5.0/go.mod h1:UFOHSIvO/nKwd4lhkwabrTD3cqW5yVyYYf/KlD00Szc=
go.etcd.io/etcd/server/v3 v3.5.0/go.mod h1:3Ah5ruV+M+7RZr0+Y/5mNLwC+eQlni+mQmOVdCRJoS4=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opentelemetry.io/contrib v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0/go.mod h1:oVGt1LRbBOBq1A5BQLlUg9UaU/54aiHw8cgjV3aWZ/E=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.20.0/go.mod h1:2AboqHi0CiIZU0qwhtUfCYD1GeUzvvIXWNkhDt7ZMG4=
go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo=
go.opentelemetry.io/otel/exporters/otlp v0.20.0/go.mod h1:YIieizyaN77rtLJra0buKiNBOm9XQfkPEKBeuhoMwAM=
go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU=
go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw=
go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc=
go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi+bJK+Dr8NQCh0qGhm1KDnNlE=
go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE=
go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/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-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/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-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/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-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
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.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20210520170846-37e1c6afe023 h1:ADo5wSpq2gqaCGQWzk7S5vd//0iyyLeAratkEoG5dLE=
golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/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-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/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-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/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.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/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.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
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.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/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-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/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-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/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-20201224043029-2b0845dc783e/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/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCYdOS8GPY=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
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-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
k8s.io/api v0.33.2 h1:YgwIS5jKfA+BZg//OQhkJNIfie/kmRsO0BmNaVSimvY=
k8s.io/api v0.33.2/go.mod h1:fhrbphQJSM2cXzCWgqU29xLDuks4mu7ti9vveEnpSXs=
k8s.io/apiextensions-apiserver v0.33.2 h1:6gnkIbngnaUflR3XwE1mCefN3YS8yTD631JXQhsU6M8=
k8s.io/apiextensions-apiserver v0.33.2/go.mod h1:IvVanieYsEHJImTKXGP6XCOjTwv2LUMos0YWc9O+QP8=
k8s.io/apimachinery v0.33.2 h1:IHFVhqg59mb8PJWTLi8m1mAoepkUNYmptHsV+Z1m5jY=
k8s.io/apimachinery v0.33.2/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e h1:KqK5c/ghOm8xkHYhlodbp6i6+r+ChV2vuAuVRdFbLro=
k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
sigs.k8s.io/controller-runtime v0.21.0 h1:CYfjpEuicjUecRk+KAeyYh+ouUBn4llGyDYytIGcJS8=
sigs.k8s.io/controller-runtime v0.21.0/go.mod h1:OSg14+F65eWqIu4DceX7k/+QRAbTTvxeQSNSOQpukWM=
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE=
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
sigs.k8s.io/structured-merge-diff/v4 v4.7.0 h1:qPeWmscJcXP0snki5IYF79Z8xrl8ETFxgMd7wez1XkI=
sigs.k8s.io/structured-merge-diff/v4 v4.7.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps=
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
sigs.k8s.io/yaml v1.5.0 h1:M10b2U7aEUY6hRtU870n2VTPgR5RZiL/I6Lcc2F4NUQ=
sigs.k8s.io/yaml v1.5.0/go.mod h1:wZs27Rbxoai4C0f8/9urLZtZtF3avA3gKvGyPdDqTO4=
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/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.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
k8s.io/api v0.21.1/go.mod h1:FstGROTmsSHBarKc8bylzXih8BLNYTiS3TZcsoEDg2s=
k8s.io/api v0.21.3/go.mod h1:hUgeYHUbBp23Ue4qdX9tR8/ANi/g3ehylAqDn9NWVOg=
k8s.io/api v0.22.1 h1:ISu3tD/jRhYfSW8jI/Q1e+lRxkR7w9UwQEZ7FgslrwY=
k8s.io/api v0.22.1/go.mod h1:bh13rkTp3F1XEaLGykbyRD2QaTTzPm0e/BMd8ptFONY=
k8s.io/apiextensions-apiserver v0.21.1/go.mod h1:KESQFCGjqVcVsZ9g0xX5bacMjyX5emuWcS2arzdEouA=
k8s.io/apiextensions-apiserver v0.21.3/go.mod h1:kl6dap3Gd45+21Jnh6utCx8Z2xxLm8LGDkprcd+KbsE=
k8s.io/apiextensions-apiserver v0.22.1 h1:YSJYzlFNFSfUle+yeEXX0lSQyLEoxoPJySRupepb0gE=
k8s.io/apiextensions-apiserver v0.22.1/go.mod h1:HeGmorjtRmRLE+Q8dJu6AYRoZccvCMsghwS8XTUYb2c=
k8s.io/apimachinery v0.21.1/go.mod h1:jbreFvJo3ov9rj7eWT7+sYiRx+qZuCYXwWT1bcDswPY=
k8s.io/apimachinery v0.21.3/go.mod h1:H/IM+5vH9kZRNJ4l3x/fXP/5bOPJaVP/guptnZPeCFI=
k8s.io/apimachinery v0.22.1 h1:DTARnyzmdHMz7bFWFDDm22AM4pLWTQECMpRTFu2d2OM=
k8s.io/apimachinery v0.22.1/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0=
k8s.io/apiserver v0.21.1/go.mod h1:nLLYZvMWn35glJ4/FZRhzLG/3MPxAaZTgV4FJZdr+tY=
k8s.io/apiserver v0.21.3/go.mod h1:eDPWlZG6/cCCMj/JBcEpDoK+I+6i3r9GsChYBHSbAzU=
k8s.io/apiserver v0.22.1/go.mod h1:2mcM6dzSt+XndzVQJX21Gx0/Klo7Aen7i0Ai6tIa400=
k8s.io/client-go v0.21.1/go.mod h1:/kEw4RgW+3xnBGzvp9IWxKSNA+lXn3A7AuH3gdOAzLs=
k8s.io/client-go v0.21.3/go.mod h1:+VPhCgTsaFmGILxR/7E1N0S+ryO010QBeNCv5JwRGYU=
k8s.io/client-go v0.22.1/go.mod h1:BquC5A4UOo4qVDUtoc04/+Nxp1MeHcVc1HJm1KmG8kk=
k8s.io/code-generator v0.21.1/go.mod h1:hUlps5+9QaTrKx+jiM4rmq7YmH8wPOIko64uZCHDh6Q=
k8s.io/code-generator v0.21.3/go.mod h1:K3y0Bv9Cz2cOW2vXUrNZlFbflhuPvuadW6JdnN6gGKo=
k8s.io/code-generator v0.22.1/go.mod h1:eV77Y09IopzeXOJzndrDyCI88UBok2h6WxAlBwpxa+o=
k8s.io/component-base v0.21.1/go.mod h1:NgzFZ2qu4m1juby4TnrmpR8adRk6ka62YdH5DkIIyKA=
k8s.io/component-base v0.21.3/go.mod h1:kkuhtfEHeZM6LkX0saqSK8PbdO7A0HigUngmhhrwfGQ=
k8s.io/component-base v0.22.1/go.mod h1:0D+Bl8rrnsPN9v0dyYvkqFfBeAd4u7n77ze+p8CMiPo=
k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
k8s.io/gengo v0.0.0-20201214224949-b6c5ce23f027/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
k8s.io/klog/v2 v2.8.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec=
k8s.io/klog/v2 v2.9.0 h1:D7HV+n1V57XeZ0m6tdRkfknthUaM06VFbWldOFh8kzM=
k8s.io/klog/v2 v2.9.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec=
k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7/go.mod h1:wXW5VT87nVfh/iLV8FpR2uDvrFyomxbtb1KivDbvPTE=
k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw=
k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
k8s.io/utils v0.0.0-20210527160623-6fdb442a123b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
k8s.io/utils v0.0.0-20210707171843-4b05e18ac7d9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
k8s.io/utils v0.0.0-20210722164352-7f3ee0f31471 h1:DnzUXII7sVg1FJ/4JX6YDRJfLNAC7idRatPwe07suiI=
k8s.io/utils v0.0.0-20210722164352-7f3ee0f31471/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.19/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.22/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
sigs.k8s.io/controller-runtime v0.9.0/go.mod h1:TgkfvrhhEw3PlI0BRL/5xM+89y3/yc0ZDfdbTl84si8=
sigs.k8s.io/controller-runtime v0.9.5 h1:WThcFE6cqctTn2jCZprLICO6BaKZfhsT37uAapTNfxc=
sigs.k8s.io/controller-runtime v0.9.5/go.mod h1:q6PpkM5vqQubEKUKOM6qr06oXGzOBcCby1DA9FbyZeA=
sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
sigs.k8s.io/structured-merge-diff/v4 v4.1.0/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
sigs.k8s.io/structured-merge-diff/v4 v4.1.2 h1:Hr/htKFmJEbtMgS/UD0N+gtgctAqz81t3nu+sPzynno=
sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=

View File

@ -1,57 +0,0 @@
/*
Copyright 2024 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 v2
import "github.com/fluxcd/pkg/apis/meta"
const (
// ForceRequestAnnotation is the annotation used for triggering a one-off forced
// Helm release, even when there are no new changes in the HelmRelease.
// The value is interpreted as a token, and must equal the value of
// meta.ReconcileRequestAnnotation in order to trigger a release.
ForceRequestAnnotation string = meta.ForceRequestAnnotation
// ResetRequestAnnotation is the annotation used for resetting the failure counts
// of a HelmRelease, so that it can be retried again.
// The value is interpreted as a token, and must equal the value of
// meta.ReconcileRequestAnnotation in order to reset the failure counts.
ResetRequestAnnotation string = "reconcile.fluxcd.io/resetAt"
)
// ShouldHandleResetRequest returns true if the HelmRelease has a reset request
// annotation, and the value of the annotation matches the value of the
// meta.ReconcileRequestAnnotation annotation.
//
// To ensure that the reset request is handled only once, the value of
// HelmReleaseStatus.LastHandledResetAt is updated to match the value of the
// reset request annotation (even if the reset request is not handled because
// the value of the meta.ReconcileRequestAnnotation annotation does not match).
func ShouldHandleResetRequest(obj *HelmRelease) bool {
return meta.HandleAnnotationRequest(obj, ResetRequestAnnotation, &obj.Status.LastHandledResetAt)
}
// ShouldHandleForceRequest returns true if the HelmRelease has a force request
// annotation, and the value of the annotation matches the value of the
// meta.ReconcileRequestAnnotation annotation.
//
// To ensure that the force request is handled only once, the value of
// HelmReleaseStatus.LastHandledForceAt is updated to match the value of the
// force request annotation (even if the force request is not handled because
// the value of the meta.ReconcileRequestAnnotation annotation does not match).
func ShouldHandleForceRequest(obj *HelmRelease) bool {
return meta.ShouldHandleForceRequest(obj)
}

View File

@ -1,50 +0,0 @@
/*
Copyright 2024 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 v2
import (
"testing"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/fluxcd/pkg/apis/meta"
)
func TestShouldHandleResetRequest(t *testing.T) {
obj := &HelmRelease{
ObjectMeta: metav1.ObjectMeta{
Annotations: map[string]string{
meta.ReconcileRequestAnnotation: "b",
ResetRequestAnnotation: "b",
},
},
Status: HelmReleaseStatus{
LastHandledResetAt: "a",
ReconcileRequestStatus: meta.ReconcileRequestStatus{
LastHandledReconcileAt: "a",
},
},
}
if !ShouldHandleResetRequest(obj) {
t.Error("ShouldHandleResetRequest() = false")
}
if obj.Status.LastHandledResetAt != "b" {
t.Error("ShouldHandleResetRequest did not update LastHandledResetAt")
}
}

View File

@ -1,82 +0,0 @@
/*
Copyright 2024 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 v2
const (
// ReleasedCondition represents the status of the last release attempt
// (install/upgrade/test) against the latest desired state.
ReleasedCondition string = "Released"
// TestSuccessCondition represents the status of the last test attempt against
// the latest desired state.
TestSuccessCondition string = "TestSuccess"
// RemediatedCondition represents the status of the last remediation attempt
// (uninstall/rollback) due to a failure of the last release attempt against the
// latest desired state.
RemediatedCondition string = "Remediated"
)
const (
// InstallSucceededReason represents the fact that the Helm install for the
// HelmRelease succeeded.
InstallSucceededReason string = "InstallSucceeded"
// InstallFailedReason represents the fact that the Helm install for the
// HelmRelease failed.
InstallFailedReason string = "InstallFailed"
// UpgradeSucceededReason represents the fact that the Helm upgrade for the
// HelmRelease succeeded.
UpgradeSucceededReason string = "UpgradeSucceeded"
// UpgradeFailedReason represents the fact that the Helm upgrade for the
// HelmRelease failed.
UpgradeFailedReason string = "UpgradeFailed"
// TestSucceededReason represents the fact that the Helm tests for the
// HelmRelease succeeded.
TestSucceededReason string = "TestSucceeded"
// TestFailedReason represents the fact that the Helm tests for the HelmRelease
// failed.
TestFailedReason string = "TestFailed"
// RollbackSucceededReason represents the fact that the Helm rollback for the
// HelmRelease succeeded.
RollbackSucceededReason string = "RollbackSucceeded"
// RollbackFailedReason represents the fact that the Helm test for the
// HelmRelease failed.
RollbackFailedReason string = "RollbackFailed"
// UninstallSucceededReason represents the fact that the Helm uninstall for the
// HelmRelease succeeded.
UninstallSucceededReason string = "UninstallSucceeded"
// UninstallFailedReason represents the fact that the Helm uninstall for the
// HelmRelease failed.
UninstallFailedReason string = "UninstallFailed"
// ArtifactFailedReason represents the fact that the artifact download for the
// HelmRelease failed.
ArtifactFailedReason string = "ArtifactFailed"
// DependencyNotReadyReason represents the fact that
// one of the dependencies is not ready.
DependencyNotReadyReason string = "DependencyNotReady"
)

View File

@ -1,20 +0,0 @@
/*
Copyright 2024 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 v2 contains API Schema definitions for the helm v2 API group
// +kubebuilder:object:generate=true
// +groupName=helm.toolkit.fluxcd.io
package v2

View File

@ -1,33 +0,0 @@
/*
Copyright 2024 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 v2
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: "helm.toolkit.fluxcd.io", Version: "v2"}
// 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
)

File diff suppressed because it is too large Load Diff

View File

@ -1,90 +0,0 @@
/*
Copyright 2024 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 v2
// CrossNamespaceObjectReference contains enough information to let you locate
// the typed referenced object at cluster level.
type CrossNamespaceObjectReference struct {
// APIVersion of the referent.
// +optional
APIVersion string `json:"apiVersion,omitempty"`
// Kind of the referent.
// +kubebuilder:validation:Enum=HelmRepository;GitRepository;Bucket
// +required
Kind string `json:"kind,omitempty"`
// Name of the referent.
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=253
// +required
Name string `json:"name"`
// Namespace of the referent.
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=63
// +kubebuilder:validation:Optional
// +optional
Namespace string `json:"namespace,omitempty"`
}
// CrossNamespaceSourceReference contains enough information to let you locate
// the typed referenced object at cluster level.
type CrossNamespaceSourceReference struct {
// APIVersion of the referent.
// +optional
APIVersion string `json:"apiVersion,omitempty"`
// Kind of the referent.
// +kubebuilder:validation:Enum=OCIRepository;HelmChart
// +required
Kind string `json:"kind"`
// Name of the referent.
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=253
// +required
Name string `json:"name"`
// Namespace of the referent, defaults to the namespace of the Kubernetes
// resource object that contains the reference.
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=63
// +kubebuilder:validation:Optional
// +optional
Namespace string `json:"namespace,omitempty"`
}
// DependencyReference defines a HelmRelease dependency on another HelmRelease resource.
type DependencyReference struct {
// Name of the referent.
// +required
Name string `json:"name"`
// Namespace of the referent, defaults to the namespace of the HelmRelease
// resource object that contains the reference.
// +optional
Namespace string `json:"namespace,omitempty"`
// ReadyExpr is a CEL expression that can be used to assess the readiness
// of a dependency. When specified, the built-in readiness check
// is replaced by the logic defined in the CEL expression.
// To make the CEL expression additive to the built-in readiness check,
// the feature gate `AdditiveCELDependencyCheck` must be set to `true`.
// +optional
ReadyExpr string `json:"readyExpr,omitempty"`
}

View File

@ -1,239 +0,0 @@
/*
Copyright 2024 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 v2
import (
"fmt"
"sort"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
const (
// snapshotStatusDeployed indicates that the release the snapshot was taken
// from is currently deployed.
snapshotStatusDeployed = "deployed"
// snapshotStatusSuperseded indicates that the release the snapshot was taken
// from has been superseded by a newer release.
snapshotStatusSuperseded = "superseded"
// snapshotTestPhaseFailed indicates that the test of the release the snapshot
// was taken from has failed.
snapshotTestPhaseFailed = "Failed"
)
// Snapshots is a list of Snapshot objects.
type Snapshots []*Snapshot
// Len returns the number of Snapshots.
func (in Snapshots) Len() int {
return len(in)
}
// SortByVersion sorts the Snapshots by version, in descending order.
func (in Snapshots) SortByVersion() {
sort.Slice(in, func(i, j int) bool {
return in[i].Version > in[j].Version
})
}
// Latest returns the most recent Snapshot.
func (in Snapshots) Latest() *Snapshot {
if len(in) == 0 {
return nil
}
in.SortByVersion()
return in[0]
}
// Previous returns the most recent Snapshot before the Latest that has a
// status of "deployed" or "superseded", or nil if there is no such Snapshot.
// Unless ignoreTests is true, Snapshots with a test in the "Failed" phase are
// ignored.
func (in Snapshots) Previous(ignoreTests bool) *Snapshot {
if len(in) < 2 {
return nil
}
in.SortByVersion()
for i := range in[1:] {
s := in[i+1]
if s.Status == snapshotStatusDeployed || s.Status == snapshotStatusSuperseded {
if ignoreTests || !s.HasTestInPhase(snapshotTestPhaseFailed) {
return s
}
}
}
return nil
}
// Truncate removes all Snapshots up to the Previous deployed Snapshot.
// If there is no previous-deployed Snapshot, the most recent 5 Snapshots are
// retained.
func (in *Snapshots) Truncate(ignoreTests bool) {
if in.Len() < 2 {
return
}
in.SortByVersion()
for i := range (*in)[1:] {
s := (*in)[i+1]
if s.Status == snapshotStatusDeployed || s.Status == snapshotStatusSuperseded {
if ignoreTests || !s.HasTestInPhase(snapshotTestPhaseFailed) {
*in = (*in)[:i+2]
return
}
}
}
if in.Len() > defaultMaxHistory {
// If none of the Snapshots are deployed or superseded, and there
// are more than the defaultMaxHistory, truncate to the most recent
// Snapshots.
*in = (*in)[:defaultMaxHistory]
}
}
// Snapshot captures a point-in-time copy of the status information for a Helm release,
// as managed by the controller.
type Snapshot struct {
// APIVersion is the API version of the Snapshot.
// Provisional: when the calculation method of the Digest field is changed,
// this field will be used to distinguish between the old and new methods.
// +optional
APIVersion string `json:"apiVersion,omitempty"`
// Digest is the checksum of the release object in storage.
// It has the format of `<algo>:<checksum>`.
// +required
Digest string `json:"digest"`
// Name is the name of the release.
// +required
Name string `json:"name"`
// Namespace is the namespace the release is deployed to.
// +required
Namespace string `json:"namespace"`
// Version is the version of the release object in storage.
// +required
Version int `json:"version"`
// Status is the current state of the release.
// +required
Status string `json:"status"`
// ChartName is the chart name of the release object in storage.
// +required
ChartName string `json:"chartName"`
// ChartVersion is the chart version of the release object in
// storage.
// +required
ChartVersion string `json:"chartVersion"`
// AppVersion is the chart app version of the release object in storage.
// +optional
AppVersion string `json:"appVersion,omitempty"`
// ConfigDigest is the checksum of the config (better known as
// "values") of the release object in storage.
// It has the format of `<algo>:<checksum>`.
// +required
ConfigDigest string `json:"configDigest"`
// FirstDeployed is when the release was first deployed.
// +required
FirstDeployed metav1.Time `json:"firstDeployed"`
// LastDeployed is when the release was last deployed.
// +required
LastDeployed metav1.Time `json:"lastDeployed"`
// Deleted is when the release was deleted.
// +optional
Deleted metav1.Time `json:"deleted,omitempty"`
// TestHooks is the list of test hooks for the release as observed to be
// run by the controller.
// +optional
TestHooks *map[string]*TestHookStatus `json:"testHooks,omitempty"`
// OCIDigest is the digest of the OCI artifact associated with the release.
// +optional
OCIDigest string `json:"ociDigest,omitempty"`
}
// FullReleaseName returns the full name of the release in the format
// of '<namespace>/<name>.<version>
func (in *Snapshot) FullReleaseName() string {
if in == nil {
return ""
}
return fmt.Sprintf("%s/%s.v%d", in.Namespace, in.Name, in.Version)
}
// VersionedChartName returns the full name of the chart in the format of
// '<name>@<version>'.
func (in *Snapshot) VersionedChartName() string {
if in == nil {
return ""
}
return fmt.Sprintf("%s@%s", in.ChartName, in.ChartVersion)
}
// HasBeenTested returns true if TestHooks is not nil. This includes an empty
// map, which indicates the chart has no tests.
func (in *Snapshot) HasBeenTested() bool {
return in != nil && in.TestHooks != nil
}
// GetTestHooks returns the TestHooks for the release if not nil.
func (in *Snapshot) GetTestHooks() map[string]*TestHookStatus {
if in == nil || in.TestHooks == nil {
return nil
}
return *in.TestHooks
}
// HasTestInPhase returns true if any of the TestHooks is in the given phase.
func (in *Snapshot) HasTestInPhase(phase string) bool {
if in != nil {
for _, h := range in.GetTestHooks() {
if h.Phase == phase {
return true
}
}
}
return false
}
// SetTestHooks sets the TestHooks for the release.
func (in *Snapshot) SetTestHooks(hooks map[string]*TestHookStatus) {
if in == nil || hooks == nil {
return
}
in.TestHooks = &hooks
}
// Targets returns true if the Snapshot targets the given release data.
func (in *Snapshot) Targets(name, namespace string, version int) bool {
if in != nil {
return in.Name == name && in.Namespace == namespace && in.Version == version
}
return false
}
// TestHookStatus holds the status information for a test hook as observed
// to be run by the controller.
type TestHookStatus struct {
// LastStarted is the time the test hook was last started.
// +optional
LastStarted metav1.Time `json:"lastStarted,omitempty"`
// LastCompleted is the time the test hook last completed.
// +optional
LastCompleted metav1.Time `json:"lastCompleted,omitempty"`
// Phase the test hook was observed to be in.
// +optional
Phase string `json:"phase,omitempty"`
}

View File

@ -1,298 +0,0 @@
/*
Copyright 2024 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 v2
import (
"reflect"
"testing"
)
func TestSnapshots_Sort(t *testing.T) {
tests := []struct {
name string
in Snapshots
want Snapshots
}{
{
name: "sorts by descending version",
in: Snapshots{
{Version: 1},
{Version: 3},
{Version: 2},
},
want: Snapshots{
{Version: 3},
{Version: 2},
{Version: 1},
},
},
{
name: "already sorted",
in: Snapshots{
{Version: 3},
{Version: 2},
{Version: 1},
},
want: Snapshots{
{Version: 3},
{Version: 2},
{Version: 1},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.in.SortByVersion()
if !reflect.DeepEqual(tt.in, tt.want) {
t.Errorf("SortByVersion() got %v, want %v", tt.in, tt.want)
}
})
}
}
func TestSnapshots_Latest(t *testing.T) {
tests := []struct {
name string
in Snapshots
want *Snapshot
}{
{
name: "returns most recent snapshot",
in: Snapshots{
{Version: 1},
{Version: 3},
{Version: 2},
},
want: &Snapshot{Version: 3},
},
{
name: "returns nil if empty",
in: Snapshots{},
want: nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.in.Latest(); !reflect.DeepEqual(got, tt.want) {
t.Errorf("Latest() = %v, want %v", got, tt.want)
}
})
}
}
func TestSnapshots_Previous(t *testing.T) {
tests := []struct {
name string
in Snapshots
ignoreTests bool
want *Snapshot
}{
{
name: "returns previous snapshot",
in: Snapshots{
{Version: 2, Status: "deployed"},
{Version: 3, Status: "failed"},
{Version: 1, Status: "superseded"},
},
want: &Snapshot{Version: 2, Status: "deployed"},
},
{
name: "includes snapshots with failed tests",
in: Snapshots{
{Version: 4, Status: "deployed"},
{Version: 1, Status: "superseded"},
{Version: 2, Status: "superseded"},
{Version: 3, Status: "superseded", TestHooks: &map[string]*TestHookStatus{
"test": {Phase: "Failed"},
}},
},
ignoreTests: true,
want: &Snapshot{Version: 3, Status: "superseded", TestHooks: &map[string]*TestHookStatus{
"test": {Phase: "Failed"},
}},
},
{
name: "ignores snapshots with failed tests",
in: Snapshots{
{Version: 4, Status: "deployed"},
{Version: 1, Status: "superseded"},
{Version: 2, Status: "superseded"},
{Version: 3, Status: "superseded", TestHooks: &map[string]*TestHookStatus{
"test": {Phase: "Failed"},
}},
},
ignoreTests: false,
want: &Snapshot{Version: 2, Status: "superseded"},
},
{
name: "returns nil without previous snapshot",
in: Snapshots{
{Version: 1, Status: "deployed"},
},
want: nil,
},
{
name: "returns nil without snapshot matching criteria",
in: Snapshots{
{Version: 4, Status: "deployed"},
{Version: 3, Status: "superseded", TestHooks: &map[string]*TestHookStatus{
"test": {Phase: "Failed"},
}},
},
ignoreTests: false,
want: nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.in.Previous(tt.ignoreTests); !reflect.DeepEqual(got, tt.want) {
t.Errorf("Previous() = %v, want %v", got, tt.want)
}
})
}
}
func TestSnapshots_Truncate(t *testing.T) {
tests := []struct {
name string
in Snapshots
ignoreTests bool
want Snapshots
}{
{
name: "keeps previous snapshot",
in: Snapshots{
{Version: 1, Status: "superseded"},
{Version: 3, Status: "failed"},
{Version: 2, Status: "superseded"},
{Version: 4, Status: "deployed"},
},
want: Snapshots{
{Version: 4, Status: "deployed"},
{Version: 3, Status: "failed"},
{Version: 2, Status: "superseded"},
},
},
{
name: "ignores snapshots with failed tests",
in: Snapshots{
{Version: 4, Status: "deployed"},
{Version: 3, Status: "superseded", TestHooks: &map[string]*TestHookStatus{
"upgrade-test-fail-podinfo-fault-test-tiz9x": {Phase: "Failed"},
"upgrade-test-fail-podinfo-grpc-test-gddcw": {},
}},
{Version: 2, Status: "superseded", TestHooks: &map[string]*TestHookStatus{
"upgrade-test-fail-podinfo-grpc-test-h0tc2": {
Phase: "Succeeded",
},
"upgrade-test-fail-podinfo-jwt-test-vzusa": {
Phase: "Succeeded",
},
"upgrade-test-fail-podinfo-service-test-b647e": {
Phase: "Succeeded",
},
}},
},
ignoreTests: false,
want: Snapshots{
{Version: 4, Status: "deployed"},
{Version: 3, Status: "superseded", TestHooks: &map[string]*TestHookStatus{
"upgrade-test-fail-podinfo-fault-test-tiz9x": {Phase: "Failed"},
"upgrade-test-fail-podinfo-grpc-test-gddcw": {},
}},
{Version: 2, Status: "superseded", TestHooks: &map[string]*TestHookStatus{
"upgrade-test-fail-podinfo-grpc-test-h0tc2": {
Phase: "Succeeded",
},
"upgrade-test-fail-podinfo-jwt-test-vzusa": {
Phase: "Succeeded",
},
"upgrade-test-fail-podinfo-service-test-b647e": {
Phase: "Succeeded",
},
}},
},
},
{
name: "keeps previous snapshot with failed tests",
in: Snapshots{
{Version: 4, Status: "deployed"},
{Version: 3, Status: "superseded", TestHooks: &map[string]*TestHookStatus{
"upgrade-test-fail-podinfo-fault-test-tiz9x": {Phase: "Failed"},
"upgrade-test-fail-podinfo-grpc-test-gddcw": {},
}},
{Version: 2, Status: "superseded", TestHooks: &map[string]*TestHookStatus{
"upgrade-test-fail-podinfo-grpc-test-h0tc2": {
Phase: "Succeeded",
},
"upgrade-test-fail-podinfo-jwt-test-vzusa": {
Phase: "Succeeded",
},
"upgrade-test-fail-podinfo-service-test-b647e": {
Phase: "Succeeded",
},
}},
{Version: 1, Status: "superseded"},
},
ignoreTests: true,
want: Snapshots{
{Version: 4, Status: "deployed"},
{Version: 3, Status: "superseded", TestHooks: &map[string]*TestHookStatus{
"upgrade-test-fail-podinfo-fault-test-tiz9x": {Phase: "Failed"},
"upgrade-test-fail-podinfo-grpc-test-gddcw": {},
}},
},
},
{
name: "retains most recent snapshots when all have failed",
in: Snapshots{
{Version: 6, Status: "deployed"},
{Version: 5, Status: "failed"},
{Version: 4, Status: "failed"},
{Version: 3, Status: "failed"},
{Version: 2, Status: "failed"},
{Version: 1, Status: "failed"},
},
want: Snapshots{
{Version: 6, Status: "deployed"},
{Version: 5, Status: "failed"},
{Version: 4, Status: "failed"},
{Version: 3, Status: "failed"},
{Version: 2, Status: "failed"},
},
},
{
name: "without previous snapshot",
in: Snapshots{
{Version: 1, Status: "deployed"},
},
want: Snapshots{
{Version: 1, Status: "deployed"},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.in.Truncate(tt.ignoreTests)
if !reflect.DeepEqual(tt.in, tt.want) {
t.Errorf("Truncate() got %v, want %v", tt.in, tt.want)
}
})
}
}

View File

@ -1,774 +0,0 @@
//go:build !ignore_autogenerated
/*
Copyright 2024 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 v2
import (
"github.com/fluxcd/pkg/apis/kustomize"
"github.com/fluxcd/pkg/apis/meta"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
"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 *CommonMetadata) DeepCopyInto(out *CommonMetadata) {
*out = *in
if in.Annotations != nil {
in, out := &in.Annotations, &out.Annotations
*out = make(map[string]string, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
if in.Labels != nil {
in, out := &in.Labels, &out.Labels
*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 CommonMetadata.
func (in *CommonMetadata) DeepCopy() *CommonMetadata {
if in == nil {
return nil
}
out := new(CommonMetadata)
in.DeepCopyInto(out)
return out
}
// 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
}
// 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 *CrossNamespaceSourceReference) DeepCopyInto(out *CrossNamespaceSourceReference) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CrossNamespaceSourceReference.
func (in *CrossNamespaceSourceReference) DeepCopy() *CrossNamespaceSourceReference {
if in == nil {
return nil
}
out := new(CrossNamespaceSourceReference)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *DependencyReference) DeepCopyInto(out *DependencyReference) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DependencyReference.
func (in *DependencyReference) DeepCopy() *DependencyReference {
if in == nil {
return nil
}
out := new(DependencyReference)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *DriftDetection) DeepCopyInto(out *DriftDetection) {
*out = *in
if in.Ignore != nil {
in, out := &in.Ignore, &out.Ignore
*out = make([]IgnoreRule, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DriftDetection.
func (in *DriftDetection) DeepCopy() *DriftDetection {
if in == nil {
return nil
}
out := new(DriftDetection)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Filter) DeepCopyInto(out *Filter) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Filter.
func (in *Filter) DeepCopy() *Filter {
if in == nil {
return nil
}
out := new(Filter)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *HelmChartTemplate) DeepCopyInto(out *HelmChartTemplate) {
*out = *in
if in.ObjectMeta != nil {
in, out := &in.ObjectMeta, &out.ObjectMeta
*out = new(HelmChartTemplateObjectMeta)
(*in).DeepCopyInto(*out)
}
in.Spec.DeepCopyInto(&out.Spec)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmChartTemplate.
func (in *HelmChartTemplate) DeepCopy() *HelmChartTemplate {
if in == nil {
return nil
}
out := new(HelmChartTemplate)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *HelmChartTemplateObjectMeta) DeepCopyInto(out *HelmChartTemplateObjectMeta) {
*out = *in
if in.Labels != nil {
in, out := &in.Labels, &out.Labels
*out = make(map[string]string, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
if in.Annotations != nil {
in, out := &in.Annotations, &out.Annotations
*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 HelmChartTemplateObjectMeta.
func (in *HelmChartTemplateObjectMeta) DeepCopy() *HelmChartTemplateObjectMeta {
if in == nil {
return nil
}
out := new(HelmChartTemplateObjectMeta)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *HelmChartTemplateSpec) DeepCopyInto(out *HelmChartTemplateSpec) {
*out = *in
out.SourceRef = in.SourceRef
if in.Interval != nil {
in, out := &in.Interval, &out.Interval
*out = new(v1.Duration)
**out = **in
}
if in.ValuesFiles != nil {
in, out := &in.ValuesFiles, &out.ValuesFiles
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.Verify != nil {
in, out := &in.Verify, &out.Verify
*out = new(HelmChartTemplateVerification)
(*in).DeepCopyInto(*out)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmChartTemplateSpec.
func (in *HelmChartTemplateSpec) DeepCopy() *HelmChartTemplateSpec {
if in == nil {
return nil
}
out := new(HelmChartTemplateSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *HelmChartTemplateVerification) DeepCopyInto(out *HelmChartTemplateVerification) {
*out = *in
if in.SecretRef != nil {
in, out := &in.SecretRef, &out.SecretRef
*out = new(meta.LocalObjectReference)
**out = **in
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmChartTemplateVerification.
func (in *HelmChartTemplateVerification) DeepCopy() *HelmChartTemplateVerification {
if in == nil {
return nil
}
out := new(HelmChartTemplateVerification)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *HelmRelease) DeepCopyInto(out *HelmRelease) {
*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 HelmRelease.
func (in *HelmRelease) DeepCopy() *HelmRelease {
if in == nil {
return nil
}
out := new(HelmRelease)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *HelmRelease) 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 *HelmReleaseList) DeepCopyInto(out *HelmReleaseList) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]HelmRelease, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmReleaseList.
func (in *HelmReleaseList) DeepCopy() *HelmReleaseList {
if in == nil {
return nil
}
out := new(HelmReleaseList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *HelmReleaseList) 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 *HelmReleaseSpec) DeepCopyInto(out *HelmReleaseSpec) {
*out = *in
if in.Chart != nil {
in, out := &in.Chart, &out.Chart
*out = new(HelmChartTemplate)
(*in).DeepCopyInto(*out)
}
if in.ChartRef != nil {
in, out := &in.ChartRef, &out.ChartRef
*out = new(CrossNamespaceSourceReference)
**out = **in
}
out.Interval = in.Interval
if in.KubeConfig != nil {
in, out := &in.KubeConfig, &out.KubeConfig
*out = new(meta.KubeConfigReference)
(*in).DeepCopyInto(*out)
}
if in.DependsOn != nil {
in, out := &in.DependsOn, &out.DependsOn
*out = make([]DependencyReference, len(*in))
copy(*out, *in)
}
if in.Timeout != nil {
in, out := &in.Timeout, &out.Timeout
*out = new(v1.Duration)
**out = **in
}
if in.MaxHistory != nil {
in, out := &in.MaxHistory, &out.MaxHistory
*out = new(int)
**out = **in
}
if in.PersistentClient != nil {
in, out := &in.PersistentClient, &out.PersistentClient
*out = new(bool)
**out = **in
}
if in.DriftDetection != nil {
in, out := &in.DriftDetection, &out.DriftDetection
*out = new(DriftDetection)
(*in).DeepCopyInto(*out)
}
if in.Install != nil {
in, out := &in.Install, &out.Install
*out = new(Install)
(*in).DeepCopyInto(*out)
}
if in.Upgrade != nil {
in, out := &in.Upgrade, &out.Upgrade
*out = new(Upgrade)
(*in).DeepCopyInto(*out)
}
if in.Test != nil {
in, out := &in.Test, &out.Test
*out = new(Test)
(*in).DeepCopyInto(*out)
}
if in.Rollback != nil {
in, out := &in.Rollback, &out.Rollback
*out = new(Rollback)
(*in).DeepCopyInto(*out)
}
if in.Uninstall != nil {
in, out := &in.Uninstall, &out.Uninstall
*out = new(Uninstall)
(*in).DeepCopyInto(*out)
}
if in.ValuesFrom != nil {
in, out := &in.ValuesFrom, &out.ValuesFrom
*out = make([]meta.ValuesReference, len(*in))
copy(*out, *in)
}
if in.Values != nil {
in, out := &in.Values, &out.Values
*out = new(apiextensionsv1.JSON)
(*in).DeepCopyInto(*out)
}
if in.CommonMetadata != nil {
in, out := &in.CommonMetadata, &out.CommonMetadata
*out = new(CommonMetadata)
(*in).DeepCopyInto(*out)
}
if in.PostRenderers != nil {
in, out := &in.PostRenderers, &out.PostRenderers
*out = make([]PostRenderer, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmReleaseSpec.
func (in *HelmReleaseSpec) DeepCopy() *HelmReleaseSpec {
if in == nil {
return nil
}
out := new(HelmReleaseSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *HelmReleaseStatus) DeepCopyInto(out *HelmReleaseStatus) {
*out = *in
if in.Conditions != nil {
in, out := &in.Conditions, &out.Conditions
*out = make([]v1.Condition, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.History != nil {
in, out := &in.History, &out.History
*out = make(Snapshots, len(*in))
for i := range *in {
if (*in)[i] != nil {
in, out := &(*in)[i], &(*out)[i]
*out = new(Snapshot)
(*in).DeepCopyInto(*out)
}
}
}
if in.LastAttemptedReleaseActionDuration != nil {
in, out := &in.LastAttemptedReleaseActionDuration, &out.LastAttemptedReleaseActionDuration
*out = new(v1.Duration)
**out = **in
}
out.ReconcileRequestStatus = in.ReconcileRequestStatus
out.ForceRequestStatus = in.ForceRequestStatus
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmReleaseStatus.
func (in *HelmReleaseStatus) DeepCopy() *HelmReleaseStatus {
if in == nil {
return nil
}
out := new(HelmReleaseStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *IgnoreRule) DeepCopyInto(out *IgnoreRule) {
*out = *in
if in.Paths != nil {
in, out := &in.Paths, &out.Paths
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.Target != nil {
in, out := &in.Target, &out.Target
*out = new(kustomize.Selector)
**out = **in
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IgnoreRule.
func (in *IgnoreRule) DeepCopy() *IgnoreRule {
if in == nil {
return nil
}
out := new(IgnoreRule)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Install) DeepCopyInto(out *Install) {
*out = *in
if in.Timeout != nil {
in, out := &in.Timeout, &out.Timeout
*out = new(v1.Duration)
**out = **in
}
if in.Remediation != nil {
in, out := &in.Remediation, &out.Remediation
*out = new(InstallRemediation)
(*in).DeepCopyInto(*out)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Install.
func (in *Install) DeepCopy() *Install {
if in == nil {
return nil
}
out := new(Install)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *InstallRemediation) DeepCopyInto(out *InstallRemediation) {
*out = *in
if in.IgnoreTestFailures != nil {
in, out := &in.IgnoreTestFailures, &out.IgnoreTestFailures
*out = new(bool)
**out = **in
}
if in.RemediateLastFailure != nil {
in, out := &in.RemediateLastFailure, &out.RemediateLastFailure
*out = new(bool)
**out = **in
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InstallRemediation.
func (in *InstallRemediation) DeepCopy() *InstallRemediation {
if in == nil {
return nil
}
out := new(InstallRemediation)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Kustomize) DeepCopyInto(out *Kustomize) {
*out = *in
if in.Patches != nil {
in, out := &in.Patches, &out.Patches
*out = make([]kustomize.Patch, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.Images != nil {
in, out := &in.Images, &out.Images
*out = make([]kustomize.Image, len(*in))
copy(*out, *in)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Kustomize.
func (in *Kustomize) DeepCopy() *Kustomize {
if in == nil {
return nil
}
out := new(Kustomize)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *PostRenderer) DeepCopyInto(out *PostRenderer) {
*out = *in
if in.Kustomize != nil {
in, out := &in.Kustomize, &out.Kustomize
*out = new(Kustomize)
(*in).DeepCopyInto(*out)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PostRenderer.
func (in *PostRenderer) DeepCopy() *PostRenderer {
if in == nil {
return nil
}
out := new(PostRenderer)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Rollback) DeepCopyInto(out *Rollback) {
*out = *in
if in.Timeout != nil {
in, out := &in.Timeout, &out.Timeout
*out = new(v1.Duration)
**out = **in
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Rollback.
func (in *Rollback) DeepCopy() *Rollback {
if in == nil {
return nil
}
out := new(Rollback)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Snapshot) DeepCopyInto(out *Snapshot) {
*out = *in
in.FirstDeployed.DeepCopyInto(&out.FirstDeployed)
in.LastDeployed.DeepCopyInto(&out.LastDeployed)
in.Deleted.DeepCopyInto(&out.Deleted)
if in.TestHooks != nil {
in, out := &in.TestHooks, &out.TestHooks
*out = new(map[string]*TestHookStatus)
if **in != nil {
in, out := *in, *out
*out = make(map[string]*TestHookStatus, len(*in))
for key, val := range *in {
var outVal *TestHookStatus
if val == nil {
(*out)[key] = nil
} else {
inVal := (*in)[key]
in, out := &inVal, &outVal
*out = new(TestHookStatus)
(*in).DeepCopyInto(*out)
}
(*out)[key] = outVal
}
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Snapshot.
func (in *Snapshot) DeepCopy() *Snapshot {
if in == nil {
return nil
}
out := new(Snapshot)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in Snapshots) DeepCopyInto(out *Snapshots) {
{
in := &in
*out = make(Snapshots, len(*in))
for i := range *in {
if (*in)[i] != nil {
in, out := &(*in)[i], &(*out)[i]
*out = new(Snapshot)
(*in).DeepCopyInto(*out)
}
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Snapshots.
func (in Snapshots) DeepCopy() Snapshots {
if in == nil {
return nil
}
out := new(Snapshots)
in.DeepCopyInto(out)
return *out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Test) DeepCopyInto(out *Test) {
*out = *in
if in.Timeout != nil {
in, out := &in.Timeout, &out.Timeout
*out = new(v1.Duration)
**out = **in
}
if in.Filters != nil {
in, out := &in.Filters, &out.Filters
*out = new([]Filter)
if **in != nil {
in, out := *in, *out
*out = make([]Filter, len(*in))
copy(*out, *in)
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Test.
func (in *Test) DeepCopy() *Test {
if in == nil {
return nil
}
out := new(Test)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TestHookStatus) DeepCopyInto(out *TestHookStatus) {
*out = *in
in.LastStarted.DeepCopyInto(&out.LastStarted)
in.LastCompleted.DeepCopyInto(&out.LastCompleted)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestHookStatus.
func (in *TestHookStatus) DeepCopy() *TestHookStatus {
if in == nil {
return nil
}
out := new(TestHookStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Uninstall) DeepCopyInto(out *Uninstall) {
*out = *in
if in.Timeout != nil {
in, out := &in.Timeout, &out.Timeout
*out = new(v1.Duration)
**out = **in
}
if in.DeletionPropagation != nil {
in, out := &in.DeletionPropagation, &out.DeletionPropagation
*out = new(string)
**out = **in
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Uninstall.
func (in *Uninstall) DeepCopy() *Uninstall {
if in == nil {
return nil
}
out := new(Uninstall)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Upgrade) DeepCopyInto(out *Upgrade) {
*out = *in
if in.Timeout != nil {
in, out := &in.Timeout, &out.Timeout
*out = new(v1.Duration)
**out = **in
}
if in.Remediation != nil {
in, out := &in.Remediation, &out.Remediation
*out = new(UpgradeRemediation)
(*in).DeepCopyInto(*out)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Upgrade.
func (in *Upgrade) DeepCopy() *Upgrade {
if in == nil {
return nil
}
out := new(Upgrade)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *UpgradeRemediation) DeepCopyInto(out *UpgradeRemediation) {
*out = *in
if in.IgnoreTestFailures != nil {
in, out := &in.IgnoreTestFailures, &out.IgnoreTestFailures
*out = new(bool)
**out = **in
}
if in.RemediateLastFailure != nil {
in, out := &in.RemediateLastFailure, &out.RemediateLastFailure
*out = new(bool)
**out = **in
}
if in.Strategy != nil {
in, out := &in.Strategy, &out.Strategy
*out = new(RemediationStrategy)
**out = **in
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UpgradeRemediation.
func (in *UpgradeRemediation) DeepCopy() *UpgradeRemediation {
if in == nil {
return nil
}
out := new(UpgradeRemediation)
in.DeepCopyInto(out)
return out
}

View File

@ -83,16 +83,4 @@ const (
// GetLastReleaseFailedReason represents the fact that observing the last
// release failed.
GetLastReleaseFailedReason string = "GetLastReleaseFailed"
// DependencyNotReadyReason represents the fact that
// one of the dependencies is not ready.
DependencyNotReadyReason string = "DependencyNotReady"
// ReconciliationSucceededReason represents the fact that
// the reconciliation succeeded.
ReconciliationSucceededReason string = "ReconciliationSucceeded"
// ReconciliationFailedReason represents the fact that
// the reconciliation failed.
ReconciliationFailedReason string = "ReconciliationFailed"
)

View File

@ -15,9 +15,6 @@ limitations under the License.
*/
// Package v2beta1 contains API Schema definitions for the helm v2beta1 API group
//
// Deprecated: v2beta1 is no longer supported, use v2 instead.
//
// +kubebuilder:object:generate=true
// +groupName=helm.toolkit.fluxcd.io
package v2beta1

View File

@ -22,15 +22,12 @@ import (
"time"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
apimeta "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"github.com/fluxcd/pkg/apis/kustomize"
"github.com/fluxcd/pkg/apis/meta"
v2 "github.com/fluxcd/helm-controller/api/v2"
"github.com/fluxcd/helm-controller/api/v2beta2"
"github.com/fluxcd/pkg/runtime/dependency"
)
const HelmReleaseKind = "HelmRelease"
@ -38,11 +35,6 @@ const HelmReleaseFinalizer = "finalizers.fluxcd.io"
// Kustomize Helm PostRenderer specification.
type Kustomize struct {
// Strategic merge and JSON patches, defined as inline YAML objects,
// capable of targeting objects based on kind, label and annotation selectors.
// +optional
Patches []kustomize.Patch `json:"patches,omitempty"`
// Strategic merge patches, defined as inline YAML objects.
// +optional
PatchesStrategicMerge []apiextensionsv1.JSON `json:"patchesStrategicMerge,omitempty"`
@ -67,36 +59,19 @@ type PostRenderer struct {
// HelmReleaseSpec defines the desired state of a Helm release.
type HelmReleaseSpec struct {
// Chart defines the template of the v1beta2.HelmChart that should be created
// Chart defines the template of the v1beta1.HelmChart that should be created
// for this HelmRelease.
// +required
Chart *HelmChartTemplate `json:"chart,omitempty"`
// ChartRef holds a reference to a source controller resource containing the
// Helm chart artifact.
//
// Note: this field is provisional to the v2 API, and not actively used
// by v2beta1 HelmReleases.
// +optional
ChartRef *v2.CrossNamespaceSourceReference `json:"chartRef,omitempty"`
Chart HelmChartTemplate `json:"chart"`
// Interval at which to reconcile the Helm release.
// This interval is approximate and may be subject to jitter to ensure
// efficient use of resources.
// +kubebuilder:validation:Type=string
// +kubebuilder:validation:Pattern="^([0-9]+(\\.[0-9]+)?(ms|s|m|h))+$"
// +required
Interval metav1.Duration `json:"interval"`
// KubeConfig for reconciling the HelmRelease on a remote cluster.
// When used in combination with HelmReleaseSpec.ServiceAccountName,
// forces the controller to act on behalf of that Service Account at the
// target cluster.
// If the --default-service-account flag is set, its value will be used as
// a controller level fallback for when HelmReleaseSpec.ServiceAccountName
// is empty.
// When specified, KubeConfig takes precedence over ServiceAccountName.
// +optional
KubeConfig *meta.KubeConfigReference `json:"kubeConfig,omitempty"`
KubeConfig *KubeConfig `json:"kubeConfig,omitempty"`
// Suspend tells the controller to suspend reconciliation for this HelmRelease,
// it does not apply to already started reconciliations. Defaults to false.
@ -127,16 +102,14 @@ type HelmReleaseSpec struct {
// +optional
StorageNamespace string `json:"storageNamespace,omitempty"`
// DependsOn may contain a meta.NamespacedObjectReference slice with
// DependsOn may contain a dependency.CrossNamespaceDependencyReference slice with
// references to HelmRelease resources that must be ready before this HelmRelease
// can be reconciled.
// +optional
DependsOn []meta.NamespacedObjectReference `json:"dependsOn,omitempty"`
DependsOn []dependency.CrossNamespaceDependencyReference `json:"dependsOn,omitempty"`
// Timeout is the time to wait for any individual Kubernetes operation (like Jobs
// for hooks) during the performance of a Helm action. Defaults to '5m0s'.
// +kubebuilder:validation:Type=string
// +kubebuilder:validation:Pattern="^([0-9]+(\\.[0-9]+)?(ms|s|m|h))+$"
// +optional
Timeout *metav1.Duration `json:"timeout,omitempty"`
@ -150,30 +123,6 @@ type HelmReleaseSpec struct {
// +optional
ServiceAccountName string `json:"serviceAccountName,omitempty"`
// PersistentClient tells the controller to use a persistent Kubernetes
// client for this release. When enabled, the client will be reused for the
// duration of the reconciliation, instead of being created and destroyed
// for each (step of a) Helm action.
//
// This can improve performance, but may cause issues with some Helm charts
// that for example do create Custom Resource Definitions during installation
// outside Helm's CRD lifecycle hooks, which are then not observed to be
// available by e.g. post-install hooks.
//
// If not set, it defaults to true.
//
// +optional
PersistentClient *bool `json:"persistentClient,omitempty"`
// DriftDetection holds the configuration for detecting and handling
// differences between the manifest in the Helm storage and the resources
// currently existing in the cluster.
//
// Note: this field is provisional to the v2beta2 API, and not actively used
// by v2beta1 HelmReleases.
// +optional
DriftDetection *v2beta2.DriftDetection `json:"driftDetection,omitempty"`
// Install holds the configuration for Helm install actions for this HelmRelease.
// +optional
Install *Install `json:"install,omitempty"`
@ -252,57 +201,48 @@ func (in HelmReleaseSpec) GetUninstall() Uninstall {
return *in.Uninstall
}
// HelmChartTemplate defines the template from which the controller will
// generate a v1beta2.HelmChart object in the same namespace as the referenced
// v1beta2.Source.
type HelmChartTemplate struct {
// ObjectMeta holds the template for metadata like labels and annotations.
// +optional
ObjectMeta *HelmChartTemplateObjectMeta `json:"metadata,omitempty"`
// KubeConfig references a Kubernetes secret that contains a kubeconfig file.
type KubeConfig struct {
// SecretRef holds the name to a secret that contains a 'value' key with
// the kubeconfig file as the value. It must be in the same namespace as
// the HelmRelease.
// It is recommended that the kubeconfig is self-contained, and the secret
// is regularly updated if credentials such as a cloud-access-token expire.
// Cloud specific `cmd-path` auth helpers will not function without adding
// binaries and credentials to the Pod that is responsible for reconciling
// the HelmRelease.
// +required
SecretRef meta.LocalObjectReference `json:"secretRef,omitempty"`
}
// Spec holds the template for the v1beta2.HelmChartSpec for this HelmRelease.
// HelmChartTemplate defines the template from which the controller will
// generate a v1beta1.HelmChart object in the same namespace as the referenced
// v1beta1.Source.
type HelmChartTemplate struct {
// Spec holds the template for the v1beta1.HelmChartSpec for this HelmRelease.
// +required
Spec HelmChartTemplateSpec `json:"spec"`
}
// HelmChartTemplateObjectMeta defines the template for the ObjectMeta of a
// v1beta2.HelmChart.
type HelmChartTemplateObjectMeta struct {
// Map of string keys and values that can be used to organize and categorize
// (scope and select) objects.
// More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/
// +optional
Labels map[string]string `json:"labels,omitempty"`
// Annotations is an unstructured key value map stored with a resource that may be
// set by external tools to store and retrieve arbitrary metadata. They are not
// queryable and should be preserved when modifying objects.
// More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/
// +optional
Annotations map[string]string `json:"annotations,omitempty"`
}
// HelmChartTemplateSpec defines the template from which the controller will
// generate a v1beta2.HelmChartSpec object.
// generate a v1beta1.HelmChartSpec object.
type HelmChartTemplateSpec struct {
// The name or path the Helm chart is available at in the SourceRef.
// +required
Chart string `json:"chart"`
// Version semver expression, ignored for charts from v1beta2.GitRepository and
// v1beta2.Bucket sources. Defaults to latest when omitted.
// Version semver expression, ignored for charts from v1beta1.GitRepository and
// v1beta1.Bucket sources. Defaults to latest when omitted.
// +kubebuilder:default:=*
// +optional
Version string `json:"version,omitempty"`
// The name and namespace of the v1beta2.Source the chart is available at.
// The name and namespace of the v1beta1.Source the chart is available at.
// +required
SourceRef CrossNamespaceObjectReference `json:"sourceRef"`
// Interval at which to check the v1beta2.Source for updates. Defaults to
// Interval at which to check the v1beta1.Source for updates. Defaults to
// 'HelmReleaseSpec.Interval'.
// +kubebuilder:validation:Type=string
// +kubebuilder:validation:Pattern="^([0-9]+(\\.[0-9]+)?(ms|s|m|h))+$"
// +optional
Interval *metav1.Duration `json:"interval,omitempty"`
@ -329,17 +269,9 @@ type HelmChartTemplateSpec struct {
// +optional
// +deprecated
ValuesFile string `json:"valuesFile,omitempty"`
// Verify contains the secret name containing the trusted public keys
// used to verify the signature and specifies which provider to use to check
// whether OCI image is authentic.
// This field is only supported for OCI sources.
// Chart dependencies, which are not bundled in the umbrella chart artifact, are not verified.
// +optional
Verify *HelmChartTemplateVerification `json:"verify,omitempty"`
}
// GetInterval returns the configured interval for the v1beta2.HelmChart,
// GetInterval returns the configured interval for the v1beta1.HelmChart,
// or the given default.
func (in HelmChartTemplate) GetInterval(defaultInterval metav1.Duration) metav1.Duration {
if in.Spec.Interval == nil {
@ -349,7 +281,7 @@ func (in HelmChartTemplate) GetInterval(defaultInterval metav1.Duration) metav1.
}
// GetNamespace returns the namespace targeted namespace for the
// v1beta2.HelmChart, or the given default.
// v1beta1.HelmChart, or the given default.
func (in HelmChartTemplate) GetNamespace(defaultNamespace string) string {
if in.Spec.SourceRef.Namespace == "" {
return defaultNamespace
@ -357,19 +289,6 @@ func (in HelmChartTemplate) GetNamespace(defaultNamespace string) string {
return in.Spec.SourceRef.Namespace
}
// HelmChartTemplateVerification verifies the authenticity of an OCI Helm chart.
type HelmChartTemplateVerification struct {
// Provider specifies the technology used to sign the OCI Helm chart.
// +kubebuilder:validation:Enum=cosign
// +kubebuilder:default:=cosign
Provider string `json:"provider"`
// SecretRef specifies the Kubernetes Secret containing the
// trusted public keys.
// +optional
SecretRef *meta.LocalObjectReference `json:"secretRef,omitempty"`
}
// DeploymentAction defines a consistent interface for Install and Upgrade.
// +kubebuilder:object:generate=false
type DeploymentAction interface {
@ -396,8 +315,6 @@ type Install struct {
// Timeout is the time to wait for any individual Kubernetes operation (like
// Jobs for hooks) during the performance of a Helm install action. Defaults to
// 'HelmReleaseSpec.Timeout'.
// +kubebuilder:validation:Type=string
// +kubebuilder:validation:Pattern="^([0-9]+(\\.[0-9]+)?(ms|s|m|h))+$"
// +optional
Timeout *metav1.Duration `json:"timeout,omitempty"`
@ -574,8 +491,6 @@ type Upgrade struct {
// Timeout is the time to wait for any individual Kubernetes operation (like
// Jobs for hooks) during the performance of a Helm upgrade action. Defaults to
// 'HelmReleaseSpec.Timeout'.
// +kubebuilder:validation:Type=string
// +kubebuilder:validation:Pattern="^([0-9]+(\\.[0-9]+)?(ms|s|m|h))+$"
// +optional
Timeout *metav1.Duration `json:"timeout,omitempty"`
@ -757,8 +672,6 @@ type Test struct {
// Timeout is the time to wait for any individual Kubernetes operation during
// the performance of a Helm test action. Defaults to 'HelmReleaseSpec.Timeout'.
// +kubebuilder:validation:Type=string
// +kubebuilder:validation:Pattern="^([0-9]+(\\.[0-9]+)?(ms|s|m|h))+$"
// +optional
Timeout *metav1.Duration `json:"timeout,omitempty"`
@ -784,8 +697,6 @@ type Rollback struct {
// Timeout is the time to wait for any individual Kubernetes operation (like
// Jobs for hooks) during the performance of a Helm rollback action. Defaults to
// 'HelmReleaseSpec.Timeout'.
// +kubebuilder:validation:Type=string
// +kubebuilder:validation:Pattern="^([0-9]+(\\.[0-9]+)?(ms|s|m|h))+$"
// +optional
Timeout *metav1.Duration `json:"timeout,omitempty"`
@ -832,8 +743,6 @@ type Uninstall struct {
// Timeout is the time to wait for any individual Kubernetes operation (like
// Jobs for hooks) during the performance of a Helm uninstall action. Defaults
// to 'HelmReleaseSpec.Timeout'.
// +kubebuilder:validation:Type=string
// +kubebuilder:validation:Pattern="^([0-9]+(\\.[0-9]+)?(ms|s|m|h))+$"
// +optional
Timeout *metav1.Duration `json:"timeout,omitempty"`
@ -845,18 +754,6 @@ type Uninstall struct {
// release as deleted, but retain the release history.
// +optional
KeepHistory bool `json:"keepHistory,omitempty"`
// DisableWait disables waiting for all the resources to be deleted after
// a Helm uninstall is performed.
// +optional
DisableWait bool `json:"disableWait,omitempty"`
// DeletionPropagation specifies the deletion propagation policy when
// a Helm uninstall is performed.
// +kubebuilder:default=background
// +kubebuilder:validation:Enum=background;foreground;orphan
// +optional
DeletionPropagation *string `json:"deletionPropagation,omitempty"`
}
// GetTimeout returns the configured timeout for the Helm uninstall action, or
@ -868,26 +765,12 @@ func (in Uninstall) GetTimeout(defaultTimeout metav1.Duration) metav1.Duration {
return *in.Timeout
}
// GetDeletionPropagation returns the configured deletion propagation policy
// for the Helm uninstall action, or 'background'.
func (in Uninstall) GetDeletionPropagation() string {
if in.DeletionPropagation == nil {
return "background"
}
return *in.DeletionPropagation
}
// HelmReleaseStatus defines the observed state of a HelmRelease.
type HelmReleaseStatus struct {
// ObservedGeneration is the last observed generation.
// +optional
ObservedGeneration int64 `json:"observedGeneration,omitempty"`
// ObservedPostRenderersDigest is the digest for the post-renderers of
// the last successful reconciliation attempt.
// +optional
ObservedPostRenderersDigest string `json:"observedPostRenderersDigest,omitempty"`
meta.ReconcileRequestStatus `json:",inline"`
// Conditions holds the conditions for the HelmRelease.
@ -930,62 +813,6 @@ type HelmReleaseStatus struct {
// state. It is reset after a successful reconciliation.
// +optional
UpgradeFailures int64 `json:"upgradeFailures,omitempty"`
// StorageNamespace is the namespace of the Helm release storage for the
// current release.
//
// Note: this field is provisional to the v2beta2 API, and not actively used
// by v2beta1 HelmReleases.
// +optional
StorageNamespace string `json:"storageNamespace,omitempty"`
// History holds the history of Helm releases performed for this HelmRelease
// up to the last successfully completed release.
//
// Note: this field is provisional to the v2beta2 API, and not actively used
// by v2beta1 HelmReleases.
// +optional
History v2.Snapshots `json:"history,omitempty"`
// LastAttemptedGeneration is the last generation the controller attempted
// to reconcile.
//
// Note: this field is provisional to the v2beta2 API, and not actively used
// by v2beta1 HelmReleases.
// +optional
LastAttemptedGeneration int64 `json:"lastAttemptedGeneration,omitempty"`
// LastAttemptedConfigDigest is the digest for the config (better known as
// "values") of the last reconciliation attempt.
//
// Note: this field is provisional to the v2beta2 API, and not actively used
// by v2beta1 HelmReleases.
// +optional
LastAttemptedConfigDigest string `json:"lastAttemptedConfigDigest,omitempty"`
// LastAttemptedReleaseAction is the last release action performed for this
// HelmRelease. It is used to determine the active remediation strategy.
//
// Note: this field is provisional to the v2beta2 API, and not actively used
// by v2beta1 HelmReleases.
// +optional
LastAttemptedReleaseAction string `json:"lastAttemptedReleaseAction,omitempty"`
// LastHandledForceAt holds the value of the most recent force request
// value, so a change of the annotation value can be detected.
//
// Note: this field is provisional to the v2beta2 API, and not actively used
// by v2beta1 HelmReleases.
// +optional
LastHandledForceAt string `json:"lastHandledForceAt,omitempty"`
// LastHandledResetAt holds the value of the most recent reset request
// value, so a change of the annotation value can be detected.
//
// Note: this field is provisional to the v2beta2 API, and not actively used
// by v2beta1 HelmReleases.
// +optional
LastHandledResetAt string `json:"lastHandledResetAt,omitempty"`
}
// GetHelmChart returns the namespace and name of the HelmChart.
@ -993,10 +820,8 @@ func (in HelmReleaseStatus) GetHelmChart() (string, string) {
if in.HelmChart == "" {
return "", ""
}
if split := strings.Split(in.HelmChart, string(types.Separator)); len(split) > 1 {
return split[0], split[1]
}
return "", ""
split := strings.Split(in.HelmChart, string(types.Separator))
return split[0], split[1]
}
// HelmReleaseProgressing resets any failures and registers progress toward
@ -1004,39 +829,23 @@ func (in HelmReleaseStatus) GetHelmChart() (string, string) {
// 'Unknown' for meta.ProgressingReason.
func HelmReleaseProgressing(hr HelmRelease) HelmRelease {
hr.Status.Conditions = []metav1.Condition{}
newCondition := metav1.Condition{
Type: meta.ReadyCondition,
Status: metav1.ConditionUnknown,
Reason: meta.ProgressingReason,
Message: "Reconciliation in progress",
}
apimeta.SetStatusCondition(hr.GetStatusConditions(), newCondition)
meta.SetResourceCondition(&hr, meta.ReadyCondition, metav1.ConditionUnknown, meta.ProgressingReason,
"Reconciliation in progress")
resetFailureCounts(&hr)
return hr
}
// HelmReleaseNotReady registers a failed reconciliation of the given HelmRelease.
func HelmReleaseNotReady(hr HelmRelease, reason, message string) HelmRelease {
newCondition := metav1.Condition{
Type: meta.ReadyCondition,
Status: metav1.ConditionFalse,
Reason: reason,
Message: message,
}
apimeta.SetStatusCondition(hr.GetStatusConditions(), newCondition)
meta.SetResourceCondition(&hr, meta.ReadyCondition, metav1.ConditionFalse, reason, message)
hr.Status.Failures++
return hr
}
// HelmReleaseReady registers a successful reconciliation of the given HelmRelease.
func HelmReleaseReady(hr HelmRelease) HelmRelease {
newCondition := metav1.Condition{
Type: meta.ReadyCondition,
Status: metav1.ConditionTrue,
Reason: ReconciliationSucceededReason,
Message: "Release reconciliation succeeded",
}
apimeta.SetStatusCondition(hr.GetStatusConditions(), newCondition)
meta.SetResourceCondition(&hr, meta.ReadyCondition, metav1.ConditionTrue, meta.ReconciliationSucceededReason,
"Release reconciliation succeeded")
hr.Status.LastAppliedRevision = hr.Status.LastAttemptedRevision
resetFailureCounts(&hr)
return hr
@ -1044,8 +853,6 @@ func HelmReleaseReady(hr HelmRelease) HelmRelease {
// HelmReleaseAttempted registers an attempt of the given HelmRelease with the given state.
// and returns the modified HelmRelease and a boolean indicating a state change.
//
// Deprecated: in favor of HelmReleaseChanged and HelmReleaseRecordAttempt.
func HelmReleaseAttempted(hr HelmRelease, revision string, releaseRevision int, valuesChecksum string) (HelmRelease, bool) {
changed := hr.Status.LastAttemptedRevision != revision ||
hr.Status.LastReleaseRevision != releaseRevision ||
@ -1057,31 +864,6 @@ func HelmReleaseAttempted(hr HelmRelease, revision string, releaseRevision int,
return hr, changed
}
// HelmReleaseChanged returns if the HelmRelease has changed compared to the
// provided values.
func HelmReleaseChanged(hr HelmRelease, revision string, releaseRevision int, valuesChecksums ...string) bool {
return hr.Status.LastAttemptedRevision != revision ||
hr.Status.LastReleaseRevision != releaseRevision ||
!inStringSlice(hr.Status.LastAttemptedValuesChecksum, valuesChecksums)
}
// HelmReleaseRecordAttempt returns an attempt of the given HelmRelease with the
// given state in the Status of the provided object.
func HelmReleaseRecordAttempt(hr *HelmRelease, revision string, releaseRevision int, valuesChecksum string) {
hr.Status.LastAttemptedRevision = revision
hr.Status.LastReleaseRevision = releaseRevision
hr.Status.LastAttemptedValuesChecksum = valuesChecksum
}
func inStringSlice(str string, s []string) bool {
for _, v := range s {
if str == v {
return true
}
}
return false
}
func resetFailureCounts(hr *HelmRelease) {
hr.Status.Failures = 0
hr.Status.InstallFailures = 0
@ -1095,9 +877,13 @@ const (
)
// +genclient
// +genclient:Namespaced
// +kubebuilder:object:root=true
// +kubebuilder:resource:shortName=hr
// +kubebuilder:skipversion
// +kubebuilder:subresource:status
// +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="Age",type="date",JSONPath=".metadata.creationTimestamp",description=""
// HelmRelease is the Schema for the helmreleases API
type HelmRelease struct {
@ -1109,12 +895,6 @@ type HelmRelease struct {
Status HelmReleaseStatus `json:"status,omitempty"`
}
// GetRequeueAfter returns the duration after which the HelmRelease
// must be reconciled again.
func (in HelmRelease) GetRequeueAfter() time.Duration {
return in.Spec.Interval.Duration
}
// GetValues unmarshals the raw values to a map[string]interface{} and returns
// the result.
func (in HelmRelease) GetValues() map[string]interface{} {
@ -1176,33 +956,16 @@ func (in HelmRelease) GetMaxHistory() int {
return *in.Spec.MaxHistory
}
// UsePersistentClient returns the configured PersistentClient, or the default
// of true.
func (in HelmRelease) UsePersistentClient() bool {
if in.Spec.PersistentClient == nil {
return true
}
return *in.Spec.PersistentClient
// GetDependsOn returns the types.NamespacedName of the HelmRelease, and a
// dependency.CrossNamespaceDependencyReference slice it depends on.
func (in HelmRelease) GetDependsOn() (types.NamespacedName, []dependency.CrossNamespaceDependencyReference) {
return types.NamespacedName{
Namespace: in.Namespace,
Name: in.Namespace,
}, in.Spec.DependsOn
}
// GetDependsOn returns the list of dependencies across-namespaces.
func (in HelmRelease) GetDependsOn() []meta.NamespacedObjectReference {
return in.Spec.DependsOn
}
// GetConditions returns the status conditions of the object.
func (in HelmRelease) GetConditions() []metav1.Condition {
return in.Status.Conditions
}
// SetConditions sets the status conditions on the object.
func (in *HelmRelease) SetConditions(conditions []metav1.Condition) {
in.Status.Conditions = conditions
}
// GetStatusConditions returns a pointer to the Status.Conditions slice.
//
// Deprecated: use GetConditions instead.
// GetStatusConditions returns a pointer to the Status.Conditions slice
func (in *HelmRelease) GetStatusConditions() *[]metav1.Condition {
return &in.Status.Conditions
}

View File

@ -59,18 +59,12 @@ type ValuesReference struct {
// ValuesKey is the data key where the values.yaml or a specific value can be
// found at. Defaults to 'values.yaml'.
// When set, must be a valid Data Key, consisting of alphanumeric characters,
// '-', '_' or '.'.
// +kubebuilder:validation:MaxLength=253
// +kubebuilder:validation:Pattern=`^[\-._a-zA-Z0-9]+$`
// +optional
ValuesKey string `json:"valuesKey,omitempty"`
// TargetPath is the YAML dot notation path the value should be merged at. When
// set, the ValuesKey is expected to be a single flat value. Defaults to 'None',
// which results in the values getting merged at the root.
// +kubebuilder:validation:MaxLength=250
// +kubebuilder:validation:Pattern=`^([a-zA-Z0-9_\-.\\\/]|\[[0-9]{1,5}\])+$`
// +optional
TargetPath string `json:"targetPath,omitempty"`

View File

@ -1,7 +1,7 @@
//go:build !ignore_autogenerated
// +build !ignore_autogenerated
/*
Copyright 2024 The Flux authors
Copyright 2021 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.
@ -21,10 +21,8 @@ limitations under the License.
package v2beta1
import (
"github.com/fluxcd/helm-controller/api/v2"
"github.com/fluxcd/helm-controller/api/v2beta2"
"github.com/fluxcd/pkg/apis/kustomize"
"github.com/fluxcd/pkg/apis/meta"
"github.com/fluxcd/pkg/runtime/dependency"
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
@ -48,11 +46,6 @@ func (in *CrossNamespaceObjectReference) DeepCopy() *CrossNamespaceObjectReferen
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *HelmChartTemplate) DeepCopyInto(out *HelmChartTemplate) {
*out = *in
if in.ObjectMeta != nil {
in, out := &in.ObjectMeta, &out.ObjectMeta
*out = new(HelmChartTemplateObjectMeta)
(*in).DeepCopyInto(*out)
}
in.Spec.DeepCopyInto(&out.Spec)
}
@ -66,35 +59,6 @@ func (in *HelmChartTemplate) DeepCopy() *HelmChartTemplate {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *HelmChartTemplateObjectMeta) DeepCopyInto(out *HelmChartTemplateObjectMeta) {
*out = *in
if in.Labels != nil {
in, out := &in.Labels, &out.Labels
*out = make(map[string]string, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
if in.Annotations != nil {
in, out := &in.Annotations, &out.Annotations
*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 HelmChartTemplateObjectMeta.
func (in *HelmChartTemplateObjectMeta) DeepCopy() *HelmChartTemplateObjectMeta {
if in == nil {
return nil
}
out := new(HelmChartTemplateObjectMeta)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *HelmChartTemplateSpec) DeepCopyInto(out *HelmChartTemplateSpec) {
*out = *in
@ -109,11 +73,6 @@ func (in *HelmChartTemplateSpec) DeepCopyInto(out *HelmChartTemplateSpec) {
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.Verify != nil {
in, out := &in.Verify, &out.Verify
*out = new(HelmChartTemplateVerification)
(*in).DeepCopyInto(*out)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmChartTemplateSpec.
@ -126,26 +85,6 @@ func (in *HelmChartTemplateSpec) DeepCopy() *HelmChartTemplateSpec {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *HelmChartTemplateVerification) DeepCopyInto(out *HelmChartTemplateVerification) {
*out = *in
if in.SecretRef != nil {
in, out := &in.SecretRef, &out.SecretRef
*out = new(meta.LocalObjectReference)
**out = **in
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmChartTemplateVerification.
func (in *HelmChartTemplateVerification) DeepCopy() *HelmChartTemplateVerification {
if in == nil {
return nil
}
out := new(HelmChartTemplateVerification)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *HelmRelease) DeepCopyInto(out *HelmRelease) {
*out = *in
@ -208,25 +147,16 @@ func (in *HelmReleaseList) DeepCopyObject() runtime.Object {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *HelmReleaseSpec) DeepCopyInto(out *HelmReleaseSpec) {
*out = *in
if in.Chart != nil {
in, out := &in.Chart, &out.Chart
*out = new(HelmChartTemplate)
(*in).DeepCopyInto(*out)
}
if in.ChartRef != nil {
in, out := &in.ChartRef, &out.ChartRef
*out = new(v2.CrossNamespaceSourceReference)
**out = **in
}
in.Chart.DeepCopyInto(&out.Chart)
out.Interval = in.Interval
if in.KubeConfig != nil {
in, out := &in.KubeConfig, &out.KubeConfig
*out = new(meta.KubeConfigReference)
(*in).DeepCopyInto(*out)
*out = new(KubeConfig)
**out = **in
}
if in.DependsOn != nil {
in, out := &in.DependsOn, &out.DependsOn
*out = make([]meta.NamespacedObjectReference, len(*in))
*out = make([]dependency.CrossNamespaceDependencyReference, len(*in))
copy(*out, *in)
}
if in.Timeout != nil {
@ -239,16 +169,6 @@ func (in *HelmReleaseSpec) DeepCopyInto(out *HelmReleaseSpec) {
*out = new(int)
**out = **in
}
if in.PersistentClient != nil {
in, out := &in.PersistentClient, &out.PersistentClient
*out = new(bool)
**out = **in
}
if in.DriftDetection != nil {
in, out := &in.DriftDetection, &out.DriftDetection
*out = new(v2beta2.DriftDetection)
(*in).DeepCopyInto(*out)
}
if in.Install != nil {
in, out := &in.Install, &out.Install
*out = new(Install)
@ -314,17 +234,6 @@ func (in *HelmReleaseStatus) DeepCopyInto(out *HelmReleaseStatus) {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.History != nil {
in, out := &in.History, &out.History
*out = make(v2.Snapshots, len(*in))
for i := range *in {
if (*in)[i] != nil {
in, out := &(*in)[i], &(*out)[i]
*out = new(v2.Snapshot)
(*in).DeepCopyInto(*out)
}
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmReleaseStatus.
@ -387,16 +296,25 @@ func (in *InstallRemediation) DeepCopy() *InstallRemediation {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *KubeConfig) DeepCopyInto(out *KubeConfig) {
*out = *in
out.SecretRef = in.SecretRef
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeConfig.
func (in *KubeConfig) DeepCopy() *KubeConfig {
if in == nil {
return nil
}
out := new(KubeConfig)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Kustomize) DeepCopyInto(out *Kustomize) {
*out = *in
if in.Patches != nil {
in, out := &in.Patches, &out.Patches
*out = make([]kustomize.Patch, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.PatchesStrategicMerge != nil {
in, out := &in.PatchesStrategicMerge, &out.PatchesStrategicMerge
*out = make([]v1.JSON, len(*in))
@ -496,11 +414,6 @@ func (in *Uninstall) DeepCopyInto(out *Uninstall) {
*out = new(metav1.Duration)
**out = **in
}
if in.DeletionPropagation != nil {
in, out := &in.DeletionPropagation, &out.DeletionPropagation
*out = new(string)
**out = **in
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Uninstall.

View File

@ -1,84 +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 v2beta2
import "github.com/fluxcd/pkg/apis/meta"
const (
// ForceRequestAnnotation is the annotation used for triggering a one-off forced
// Helm release, even when there are no new changes in the HelmRelease.
// The value is interpreted as a token, and must equal the value of
// meta.ReconcileRequestAnnotation in order to trigger a release.
ForceRequestAnnotation string = "reconcile.fluxcd.io/forceAt"
// ResetRequestAnnotation is the annotation used for resetting the failure counts
// of a HelmRelease, so that it can be retried again.
// The value is interpreted as a token, and must equal the value of
// meta.ReconcileRequestAnnotation in order to reset the failure counts.
ResetRequestAnnotation string = "reconcile.fluxcd.io/resetAt"
)
// ShouldHandleResetRequest returns true if the HelmRelease has a reset request
// annotation, and the value of the annotation matches the value of the
// meta.ReconcileRequestAnnotation annotation.
//
// To ensure that the reset request is handled only once, the value of
// HelmReleaseStatus.LastHandledResetAt is updated to match the value of the
// reset request annotation (even if the reset request is not handled because
// the value of the meta.ReconcileRequestAnnotation annotation does not match).
func ShouldHandleResetRequest(obj *HelmRelease) bool {
return handleRequest(obj, ResetRequestAnnotation, &obj.Status.LastHandledResetAt)
}
// ShouldHandleForceRequest returns true if the HelmRelease has a force request
// annotation, and the value of the annotation matches the value of the
// meta.ReconcileRequestAnnotation annotation.
//
// To ensure that the force request is handled only once, the value of
// HelmReleaseStatus.LastHandledForceAt is updated to match the value of the
// force request annotation (even if the force request is not handled because
// the value of the meta.ReconcileRequestAnnotation annotation does not match).
func ShouldHandleForceRequest(obj *HelmRelease) bool {
return handleRequest(obj, ForceRequestAnnotation, &obj.Status.LastHandledForceAt)
}
// handleRequest returns true if the HelmRelease has a request annotation, and
// the value of the annotation matches the value of the meta.ReconcileRequestAnnotation
// annotation.
//
// The lastHandled argument is used to ensure that the request is handled only
// once, and is updated to match the value of the request annotation (even if
// the request is not handled because the value of the meta.ReconcileRequestAnnotation
// annotation does not match).
func handleRequest(obj *HelmRelease, annotation string, lastHandled *string) bool {
requestAt, requestOk := obj.GetAnnotations()[annotation]
reconcileAt, reconcileOk := meta.ReconcileAnnotationValue(obj.GetAnnotations())
var lastHandledRequest string
if requestOk {
lastHandledRequest = *lastHandled
*lastHandled = requestAt
}
if requestOk && reconcileOk && requestAt == reconcileAt {
lastHandledReconcile := obj.Status.GetLastHandledReconcileRequest()
if lastHandledReconcile != reconcileAt && lastHandledRequest != requestAt {
return true
}
}
return false
}

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 v2beta2
import (
"testing"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/fluxcd/pkg/apis/meta"
)
func TestShouldHandleResetRequest(t *testing.T) {
t.Run("should handle reset request", func(t *testing.T) {
obj := &HelmRelease{
ObjectMeta: metav1.ObjectMeta{
Annotations: map[string]string{
meta.ReconcileRequestAnnotation: "b",
ResetRequestAnnotation: "b",
},
},
Status: HelmReleaseStatus{
LastHandledResetAt: "a",
ReconcileRequestStatus: meta.ReconcileRequestStatus{
LastHandledReconcileAt: "a",
},
},
}
if !ShouldHandleResetRequest(obj) {
t.Error("ShouldHandleResetRequest() = false")
}
if obj.Status.LastHandledResetAt != "b" {
t.Error("ShouldHandleResetRequest did not update LastHandledResetAt")
}
})
}
func TestShouldHandleForceRequest(t *testing.T) {
t.Run("should handle force request", func(t *testing.T) {
obj := &HelmRelease{
ObjectMeta: metav1.ObjectMeta{
Annotations: map[string]string{
meta.ReconcileRequestAnnotation: "b",
ForceRequestAnnotation: "b",
},
},
Status: HelmReleaseStatus{
LastHandledForceAt: "a",
ReconcileRequestStatus: meta.ReconcileRequestStatus{
LastHandledReconcileAt: "a",
},
},
}
if !ShouldHandleForceRequest(obj) {
t.Error("ShouldHandleForceRequest() = false")
}
if obj.Status.LastHandledForceAt != "b" {
t.Error("ShouldHandleForceRequest did not update LastHandledForceAt")
}
})
}
func Test_handleRequest(t *testing.T) {
const requestAnnotation = "requestAnnotation"
tests := []struct {
name string
annotations map[string]string
lastHandledReconcile string
lastHandledRequest string
want bool
expectLastHandledRequest string
}{
{
name: "valid request and reconcile annotations",
annotations: map[string]string{
meta.ReconcileRequestAnnotation: "b",
requestAnnotation: "b",
},
want: true,
expectLastHandledRequest: "b",
},
{
name: "mismatched annotations",
annotations: map[string]string{
meta.ReconcileRequestAnnotation: "b",
requestAnnotation: "c",
},
want: false,
expectLastHandledRequest: "c",
},
{
name: "reconcile matches previous request",
annotations: map[string]string{
meta.ReconcileRequestAnnotation: "b",
requestAnnotation: "b",
},
lastHandledReconcile: "a",
lastHandledRequest: "b",
want: false,
expectLastHandledRequest: "b",
},
{
name: "request matches previous reconcile",
annotations: map[string]string{
meta.ReconcileRequestAnnotation: "b",
requestAnnotation: "b",
},
lastHandledReconcile: "b",
lastHandledRequest: "a",
want: false,
expectLastHandledRequest: "b",
},
{
name: "missing annotations",
annotations: map[string]string{},
lastHandledRequest: "a",
want: false,
expectLastHandledRequest: "a",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
obj := &HelmRelease{
ObjectMeta: metav1.ObjectMeta{
Annotations: tt.annotations,
},
Status: HelmReleaseStatus{
ReconcileRequestStatus: meta.ReconcileRequestStatus{
LastHandledReconcileAt: tt.lastHandledReconcile,
},
},
}
lastHandled := tt.lastHandledRequest
result := handleRequest(obj, requestAnnotation, &lastHandled)
if result != tt.want {
t.Errorf("handleRequest() = %v, want %v", result, tt.want)
}
if lastHandled != tt.expectLastHandledRequest {
t.Errorf("lastHandledRequest = %v, want %v", lastHandled, tt.expectLastHandledRequest)
}
})
}
}

View File

@ -1,98 +0,0 @@
/*
Copyright 2022 The Flux authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v2beta2
const (
// ReleasedCondition represents the status of the last release attempt
// (install/upgrade/test) against the latest desired state.
ReleasedCondition string = "Released"
// TestSuccessCondition represents the status of the last test attempt against
// the latest desired state.
TestSuccessCondition string = "TestSuccess"
// RemediatedCondition represents the status of the last remediation attempt
// (uninstall/rollback) due to a failure of the last release attempt against the
// latest desired state.
RemediatedCondition string = "Remediated"
)
const (
// InstallSucceededReason represents the fact that the Helm install for the
// HelmRelease succeeded.
InstallSucceededReason string = "InstallSucceeded"
// InstallFailedReason represents the fact that the Helm install for the
// HelmRelease failed.
InstallFailedReason string = "InstallFailed"
// UpgradeSucceededReason represents the fact that the Helm upgrade for the
// HelmRelease succeeded.
UpgradeSucceededReason string = "UpgradeSucceeded"
// UpgradeFailedReason represents the fact that the Helm upgrade for the
// HelmRelease failed.
UpgradeFailedReason string = "UpgradeFailed"
// TestSucceededReason represents the fact that the Helm tests for the
// HelmRelease succeeded.
TestSucceededReason string = "TestSucceeded"
// TestFailedReason represents the fact that the Helm tests for the HelmRelease
// failed.
TestFailedReason string = "TestFailed"
// RollbackSucceededReason represents the fact that the Helm rollback for the
// HelmRelease succeeded.
RollbackSucceededReason string = "RollbackSucceeded"
// RollbackFailedReason represents the fact that the Helm test for the
// HelmRelease failed.
RollbackFailedReason string = "RollbackFailed"
// UninstallSucceededReason represents the fact that the Helm uninstall for the
// HelmRelease succeeded.
UninstallSucceededReason string = "UninstallSucceeded"
// UninstallFailedReason represents the fact that the Helm uninstall for the
// HelmRelease failed.
UninstallFailedReason string = "UninstallFailed"
// ArtifactFailedReason represents the fact that the artifact download for the
// HelmRelease failed.
ArtifactFailedReason string = "ArtifactFailed"
// InitFailedReason represents the fact that the initialization of the Helm
// configuration failed.
InitFailedReason string = "InitFailed"
// GetLastReleaseFailedReason represents the fact that observing the last
// release failed.
GetLastReleaseFailedReason string = "GetLastReleaseFailed"
// DependencyNotReadyReason represents the fact that
// one of the dependencies is not ready.
DependencyNotReadyReason string = "DependencyNotReady"
// ReconciliationSucceededReason represents the fact that
// the reconciliation succeeded.
ReconciliationSucceededReason string = "ReconciliationSucceeded"
// ReconciliationFailedReason represents the fact that
// the reconciliation failed.
ReconciliationFailedReason string = "ReconciliationFailed"
)

View File

@ -1,20 +0,0 @@
/*
Copyright 2022 The Flux authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Package v2beta2 contains API Schema definitions for the helm v2beta2 API group
// +kubebuilder:object:generate=true
// +groupName=helm.toolkit.fluxcd.io
package v2beta2

View File

@ -1,33 +0,0 @@
/*
Copyright 2022 The Flux authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v2beta2
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: "helm.toolkit.fluxcd.io", Version: "v2beta2"}
// 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
)

File diff suppressed because it is too large Load Diff

View File

@ -1,115 +0,0 @@
/*
Copyright 2022 The Flux authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v2beta2
// CrossNamespaceObjectReference contains enough information to let you locate
// the typed referenced object at cluster level.
type CrossNamespaceObjectReference struct {
// APIVersion of the referent.
// +optional
APIVersion string `json:"apiVersion,omitempty"`
// Kind of the referent.
// +kubebuilder:validation:Enum=HelmRepository;GitRepository;Bucket
// +required
Kind string `json:"kind,omitempty"`
// Name of the referent.
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=253
// +required
Name string `json:"name"`
// Namespace of the referent.
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=63
// +kubebuilder:validation:Optional
// +optional
Namespace string `json:"namespace,omitempty"`
}
// CrossNamespaceSourceReference contains enough information to let you locate
// the typed referenced object at cluster level.
type CrossNamespaceSourceReference struct {
// APIVersion of the referent.
// +optional
APIVersion string `json:"apiVersion,omitempty"`
// Kind of the referent.
// +kubebuilder:validation:Enum=OCIRepository;HelmChart
// +required
Kind string `json:"kind"`
// Name of the referent.
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=253
// +required
Name string `json:"name"`
// Namespace of the referent, defaults to the namespace of the Kubernetes
// resource object that contains the reference.
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=63
// +kubebuilder:validation:Optional
// +optional
Namespace string `json:"namespace,omitempty"`
}
// ValuesReference contains a reference to a resource containing Helm values,
// and optionally the key they can be found at.
type ValuesReference struct {
// Kind of the values referent, valid values are ('Secret', 'ConfigMap').
// +kubebuilder:validation:Enum=Secret;ConfigMap
// +required
Kind string `json:"kind"`
// Name of the values referent. Should reside in the same namespace as the
// referring resource.
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=253
// +required
Name string `json:"name"`
// ValuesKey is the data key where the values.yaml or a specific value can be
// found at. Defaults to 'values.yaml'.
// +kubebuilder:validation:MaxLength=253
// +kubebuilder:validation:Pattern=`^[\-._a-zA-Z0-9]+$`
// +optional
ValuesKey string `json:"valuesKey,omitempty"`
// TargetPath is the YAML dot notation path the value should be merged at. When
// set, the ValuesKey is expected to be a single flat value. Defaults to 'None',
// which results in the values getting merged at the root.
// +kubebuilder:validation:MaxLength=250
// +kubebuilder:validation:Pattern=`^([a-zA-Z0-9_\-.\\\/]|\[[0-9]{1,5}\])+$`
// +optional
TargetPath string `json:"targetPath,omitempty"`
// Optional marks this ValuesReference as optional. When set, a not found error
// for the values reference is ignored, but any ValuesKey, TargetPath or
// transient error will still result in a reconciliation failure.
// +optional
Optional bool `json:"optional,omitempty"`
}
// GetValuesKey returns the defined ValuesKey, or the default ('values.yaml').
func (in ValuesReference) GetValuesKey() string {
if in.ValuesKey == "" {
return "values.yaml"
}
return in.ValuesKey
}

View File

@ -1,236 +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 v2beta2
import (
"fmt"
"sort"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
const (
// snapshotStatusDeployed indicates that the release the snapshot was taken
// from is currently deployed.
snapshotStatusDeployed = "deployed"
// snapshotStatusSuperseded indicates that the release the snapshot was taken
// from has been superseded by a newer release.
snapshotStatusSuperseded = "superseded"
// snapshotTestPhaseFailed indicates that the test of the release the snapshot
// was taken from has failed.
snapshotTestPhaseFailed = "Failed"
)
// Snapshots is a list of Snapshot objects.
type Snapshots []*Snapshot
// Len returns the number of Snapshots.
func (in Snapshots) Len() int {
return len(in)
}
// SortByVersion sorts the Snapshots by version, in descending order.
func (in Snapshots) SortByVersion() {
sort.Slice(in, func(i, j int) bool {
return in[i].Version > in[j].Version
})
}
// Latest returns the most recent Snapshot.
func (in Snapshots) Latest() *Snapshot {
if len(in) == 0 {
return nil
}
in.SortByVersion()
return in[0]
}
// Previous returns the most recent Snapshot before the Latest that has a
// status of "deployed" or "superseded", or nil if there is no such Snapshot.
// Unless ignoreTests is true, Snapshots with a test in the "Failed" phase are
// ignored.
func (in Snapshots) Previous(ignoreTests bool) *Snapshot {
if len(in) < 2 {
return nil
}
in.SortByVersion()
for i := range in[1:] {
s := in[i+1]
if s.Status == snapshotStatusDeployed || s.Status == snapshotStatusSuperseded {
if ignoreTests || !s.HasTestInPhase(snapshotTestPhaseFailed) {
return s
}
}
}
return nil
}
// Truncate removes all Snapshots up to the Previous deployed Snapshot.
// If there is no previous-deployed Snapshot, the most recent 5 Snapshots are
// retained.
func (in *Snapshots) Truncate(ignoreTests bool) {
if in.Len() < 2 {
return
}
in.SortByVersion()
for i := range (*in)[1:] {
s := (*in)[i+1]
if s.Status == snapshotStatusDeployed || s.Status == snapshotStatusSuperseded {
if ignoreTests || !s.HasTestInPhase(snapshotTestPhaseFailed) {
*in = (*in)[:i+2]
return
}
}
}
if in.Len() > defaultMaxHistory {
// If none of the Snapshots are deployed or superseded, and there
// are more than the defaultMaxHistory, truncate to the most recent
// Snapshots.
*in = (*in)[:defaultMaxHistory]
}
}
// Snapshot captures a point-in-time copy of the status information for a Helm release,
// as managed by the controller.
type Snapshot struct {
// APIVersion is the API version of the Snapshot.
// Provisional: when the calculation method of the Digest field is changed,
// this field will be used to distinguish between the old and new methods.
// +optional
APIVersion string `json:"apiVersion,omitempty"`
// Digest is the checksum of the release object in storage.
// It has the format of `<algo>:<checksum>`.
// +required
Digest string `json:"digest"`
// Name is the name of the release.
// +required
Name string `json:"name"`
// Namespace is the namespace the release is deployed to.
// +required
Namespace string `json:"namespace"`
// Version is the version of the release object in storage.
// +required
Version int `json:"version"`
// Status is the current state of the release.
// +required
Status string `json:"status"`
// ChartName is the chart name of the release object in storage.
// +required
ChartName string `json:"chartName"`
// ChartVersion is the chart version of the release object in
// storage.
// +required
ChartVersion string `json:"chartVersion"`
// ConfigDigest is the checksum of the config (better known as
// "values") of the release object in storage.
// It has the format of `<algo>:<checksum>`.
// +required
ConfigDigest string `json:"configDigest"`
// FirstDeployed is when the release was first deployed.
// +required
FirstDeployed metav1.Time `json:"firstDeployed"`
// LastDeployed is when the release was last deployed.
// +required
LastDeployed metav1.Time `json:"lastDeployed"`
// Deleted is when the release was deleted.
// +optional
Deleted metav1.Time `json:"deleted,omitempty"`
// TestHooks is the list of test hooks for the release as observed to be
// run by the controller.
// +optional
TestHooks *map[string]*TestHookStatus `json:"testHooks,omitempty"`
// OCIDigest is the digest of the OCI artifact associated with the release.
// +optional
OCIDigest string `json:"ociDigest,omitempty"`
}
// FullReleaseName returns the full name of the release in the format
// of '<namespace>/<name>.<version>
func (in *Snapshot) FullReleaseName() string {
if in == nil {
return ""
}
return fmt.Sprintf("%s/%s.v%d", in.Namespace, in.Name, in.Version)
}
// VersionedChartName returns the full name of the chart in the format of
// '<name>@<version>'.
func (in *Snapshot) VersionedChartName() string {
if in == nil {
return ""
}
return fmt.Sprintf("%s@%s", in.ChartName, in.ChartVersion)
}
// HasBeenTested returns true if TestHooks is not nil. This includes an empty
// map, which indicates the chart has no tests.
func (in *Snapshot) HasBeenTested() bool {
return in != nil && in.TestHooks != nil
}
// GetTestHooks returns the TestHooks for the release if not nil.
func (in *Snapshot) GetTestHooks() map[string]*TestHookStatus {
if in == nil || in.TestHooks == nil {
return nil
}
return *in.TestHooks
}
// HasTestInPhase returns true if any of the TestHooks is in the given phase.
func (in *Snapshot) HasTestInPhase(phase string) bool {
if in != nil {
for _, h := range in.GetTestHooks() {
if h.Phase == phase {
return true
}
}
}
return false
}
// SetTestHooks sets the TestHooks for the release.
func (in *Snapshot) SetTestHooks(hooks map[string]*TestHookStatus) {
if in == nil || hooks == nil {
return
}
in.TestHooks = &hooks
}
// Targets returns true if the Snapshot targets the given release data.
func (in *Snapshot) Targets(name, namespace string, version int) bool {
if in != nil {
return in.Name == name && in.Namespace == namespace && in.Version == version
}
return false
}
// TestHookStatus holds the status information for a test hook as observed
// to be run by the controller.
type TestHookStatus struct {
// LastStarted is the time the test hook was last started.
// +optional
LastStarted metav1.Time `json:"lastStarted,omitempty"`
// LastCompleted is the time the test hook last completed.
// +optional
LastCompleted metav1.Time `json:"lastCompleted,omitempty"`
// Phase the test hook was observed to be in.
// +optional
Phase string `json:"phase,omitempty"`
}

View File

@ -1,298 +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 v2beta2
import (
"reflect"
"testing"
)
func TestSnapshots_Sort(t *testing.T) {
tests := []struct {
name string
in Snapshots
want Snapshots
}{
{
name: "sorts by descending version",
in: Snapshots{
{Version: 1},
{Version: 3},
{Version: 2},
},
want: Snapshots{
{Version: 3},
{Version: 2},
{Version: 1},
},
},
{
name: "already sorted",
in: Snapshots{
{Version: 3},
{Version: 2},
{Version: 1},
},
want: Snapshots{
{Version: 3},
{Version: 2},
{Version: 1},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.in.SortByVersion()
if !reflect.DeepEqual(tt.in, tt.want) {
t.Errorf("SortByVersion() got %v, want %v", tt.in, tt.want)
}
})
}
}
func TestSnapshots_Latest(t *testing.T) {
tests := []struct {
name string
in Snapshots
want *Snapshot
}{
{
name: "returns most recent snapshot",
in: Snapshots{
{Version: 1},
{Version: 3},
{Version: 2},
},
want: &Snapshot{Version: 3},
},
{
name: "returns nil if empty",
in: Snapshots{},
want: nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.in.Latest(); !reflect.DeepEqual(got, tt.want) {
t.Errorf("Latest() = %v, want %v", got, tt.want)
}
})
}
}
func TestSnapshots_Previous(t *testing.T) {
tests := []struct {
name string
in Snapshots
ignoreTests bool
want *Snapshot
}{
{
name: "returns previous snapshot",
in: Snapshots{
{Version: 2, Status: "deployed"},
{Version: 3, Status: "failed"},
{Version: 1, Status: "superseded"},
},
want: &Snapshot{Version: 2, Status: "deployed"},
},
{
name: "includes snapshots with failed tests",
in: Snapshots{
{Version: 4, Status: "deployed"},
{Version: 1, Status: "superseded"},
{Version: 2, Status: "superseded"},
{Version: 3, Status: "superseded", TestHooks: &map[string]*TestHookStatus{
"test": {Phase: "Failed"},
}},
},
ignoreTests: true,
want: &Snapshot{Version: 3, Status: "superseded", TestHooks: &map[string]*TestHookStatus{
"test": {Phase: "Failed"},
}},
},
{
name: "ignores snapshots with failed tests",
in: Snapshots{
{Version: 4, Status: "deployed"},
{Version: 1, Status: "superseded"},
{Version: 2, Status: "superseded"},
{Version: 3, Status: "superseded", TestHooks: &map[string]*TestHookStatus{
"test": {Phase: "Failed"},
}},
},
ignoreTests: false,
want: &Snapshot{Version: 2, Status: "superseded"},
},
{
name: "returns nil without previous snapshot",
in: Snapshots{
{Version: 1, Status: "deployed"},
},
want: nil,
},
{
name: "returns nil without snapshot matching criteria",
in: Snapshots{
{Version: 4, Status: "deployed"},
{Version: 3, Status: "superseded", TestHooks: &map[string]*TestHookStatus{
"test": {Phase: "Failed"},
}},
},
ignoreTests: false,
want: nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.in.Previous(tt.ignoreTests); !reflect.DeepEqual(got, tt.want) {
t.Errorf("Previous() = %v, want %v", got, tt.want)
}
})
}
}
func TestSnapshots_Truncate(t *testing.T) {
tests := []struct {
name string
in Snapshots
ignoreTests bool
want Snapshots
}{
{
name: "keeps previous snapshot",
in: Snapshots{
{Version: 1, Status: "superseded"},
{Version: 3, Status: "failed"},
{Version: 2, Status: "superseded"},
{Version: 4, Status: "deployed"},
},
want: Snapshots{
{Version: 4, Status: "deployed"},
{Version: 3, Status: "failed"},
{Version: 2, Status: "superseded"},
},
},
{
name: "ignores snapshots with failed tests",
in: Snapshots{
{Version: 4, Status: "deployed"},
{Version: 3, Status: "superseded", TestHooks: &map[string]*TestHookStatus{
"upgrade-test-fail-podinfo-fault-test-tiz9x": {Phase: "Failed"},
"upgrade-test-fail-podinfo-grpc-test-gddcw": {},
}},
{Version: 2, Status: "superseded", TestHooks: &map[string]*TestHookStatus{
"upgrade-test-fail-podinfo-grpc-test-h0tc2": {
Phase: "Succeeded",
},
"upgrade-test-fail-podinfo-jwt-test-vzusa": {
Phase: "Succeeded",
},
"upgrade-test-fail-podinfo-service-test-b647e": {
Phase: "Succeeded",
},
}},
},
ignoreTests: false,
want: Snapshots{
{Version: 4, Status: "deployed"},
{Version: 3, Status: "superseded", TestHooks: &map[string]*TestHookStatus{
"upgrade-test-fail-podinfo-fault-test-tiz9x": {Phase: "Failed"},
"upgrade-test-fail-podinfo-grpc-test-gddcw": {},
}},
{Version: 2, Status: "superseded", TestHooks: &map[string]*TestHookStatus{
"upgrade-test-fail-podinfo-grpc-test-h0tc2": {
Phase: "Succeeded",
},
"upgrade-test-fail-podinfo-jwt-test-vzusa": {
Phase: "Succeeded",
},
"upgrade-test-fail-podinfo-service-test-b647e": {
Phase: "Succeeded",
},
}},
},
},
{
name: "keeps previous snapshot with failed tests",
in: Snapshots{
{Version: 4, Status: "deployed"},
{Version: 3, Status: "superseded", TestHooks: &map[string]*TestHookStatus{
"upgrade-test-fail-podinfo-fault-test-tiz9x": {Phase: "Failed"},
"upgrade-test-fail-podinfo-grpc-test-gddcw": {},
}},
{Version: 2, Status: "superseded", TestHooks: &map[string]*TestHookStatus{
"upgrade-test-fail-podinfo-grpc-test-h0tc2": {
Phase: "Succeeded",
},
"upgrade-test-fail-podinfo-jwt-test-vzusa": {
Phase: "Succeeded",
},
"upgrade-test-fail-podinfo-service-test-b647e": {
Phase: "Succeeded",
},
}},
{Version: 1, Status: "superseded"},
},
ignoreTests: true,
want: Snapshots{
{Version: 4, Status: "deployed"},
{Version: 3, Status: "superseded", TestHooks: &map[string]*TestHookStatus{
"upgrade-test-fail-podinfo-fault-test-tiz9x": {Phase: "Failed"},
"upgrade-test-fail-podinfo-grpc-test-gddcw": {},
}},
},
},
{
name: "retains most recent snapshots when all have failed",
in: Snapshots{
{Version: 6, Status: "deployed"},
{Version: 5, Status: "failed"},
{Version: 4, Status: "failed"},
{Version: 3, Status: "failed"},
{Version: 2, Status: "failed"},
{Version: 1, Status: "failed"},
},
want: Snapshots{
{Version: 6, Status: "deployed"},
{Version: 5, Status: "failed"},
{Version: 4, Status: "failed"},
{Version: 3, Status: "failed"},
{Version: 2, Status: "failed"},
},
},
{
name: "without previous snapshot",
in: Snapshots{
{Version: 1, Status: "deployed"},
},
want: Snapshots{
{Version: 1, Status: "deployed"},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.in.Truncate(tt.ignoreTests)
if !reflect.DeepEqual(tt.in, tt.want) {
t.Errorf("Truncate() got %v, want %v", tt.in, tt.want)
}
})
}
}

View File

@ -1,749 +0,0 @@
//go:build !ignore_autogenerated
/*
Copyright 2024 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 v2beta2
import (
"github.com/fluxcd/helm-controller/api/v2"
"github.com/fluxcd/pkg/apis/kustomize"
"github.com/fluxcd/pkg/apis/meta"
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
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
}
// 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 *CrossNamespaceSourceReference) DeepCopyInto(out *CrossNamespaceSourceReference) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CrossNamespaceSourceReference.
func (in *CrossNamespaceSourceReference) DeepCopy() *CrossNamespaceSourceReference {
if in == nil {
return nil
}
out := new(CrossNamespaceSourceReference)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *DriftDetection) DeepCopyInto(out *DriftDetection) {
*out = *in
if in.Ignore != nil {
in, out := &in.Ignore, &out.Ignore
*out = make([]IgnoreRule, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DriftDetection.
func (in *DriftDetection) DeepCopy() *DriftDetection {
if in == nil {
return nil
}
out := new(DriftDetection)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Filter) DeepCopyInto(out *Filter) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Filter.
func (in *Filter) DeepCopy() *Filter {
if in == nil {
return nil
}
out := new(Filter)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *HelmChartTemplate) DeepCopyInto(out *HelmChartTemplate) {
*out = *in
if in.ObjectMeta != nil {
in, out := &in.ObjectMeta, &out.ObjectMeta
*out = new(HelmChartTemplateObjectMeta)
(*in).DeepCopyInto(*out)
}
in.Spec.DeepCopyInto(&out.Spec)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmChartTemplate.
func (in *HelmChartTemplate) DeepCopy() *HelmChartTemplate {
if in == nil {
return nil
}
out := new(HelmChartTemplate)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *HelmChartTemplateObjectMeta) DeepCopyInto(out *HelmChartTemplateObjectMeta) {
*out = *in
if in.Labels != nil {
in, out := &in.Labels, &out.Labels
*out = make(map[string]string, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
if in.Annotations != nil {
in, out := &in.Annotations, &out.Annotations
*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 HelmChartTemplateObjectMeta.
func (in *HelmChartTemplateObjectMeta) DeepCopy() *HelmChartTemplateObjectMeta {
if in == nil {
return nil
}
out := new(HelmChartTemplateObjectMeta)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *HelmChartTemplateSpec) DeepCopyInto(out *HelmChartTemplateSpec) {
*out = *in
out.SourceRef = in.SourceRef
if in.Interval != nil {
in, out := &in.Interval, &out.Interval
*out = new(metav1.Duration)
**out = **in
}
if in.ValuesFiles != nil {
in, out := &in.ValuesFiles, &out.ValuesFiles
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.Verify != nil {
in, out := &in.Verify, &out.Verify
*out = new(HelmChartTemplateVerification)
(*in).DeepCopyInto(*out)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmChartTemplateSpec.
func (in *HelmChartTemplateSpec) DeepCopy() *HelmChartTemplateSpec {
if in == nil {
return nil
}
out := new(HelmChartTemplateSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *HelmChartTemplateVerification) DeepCopyInto(out *HelmChartTemplateVerification) {
*out = *in
if in.SecretRef != nil {
in, out := &in.SecretRef, &out.SecretRef
*out = new(meta.LocalObjectReference)
**out = **in
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmChartTemplateVerification.
func (in *HelmChartTemplateVerification) DeepCopy() *HelmChartTemplateVerification {
if in == nil {
return nil
}
out := new(HelmChartTemplateVerification)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *HelmRelease) DeepCopyInto(out *HelmRelease) {
*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 HelmRelease.
func (in *HelmRelease) DeepCopy() *HelmRelease {
if in == nil {
return nil
}
out := new(HelmRelease)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *HelmRelease) 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 *HelmReleaseList) DeepCopyInto(out *HelmReleaseList) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]HelmRelease, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmReleaseList.
func (in *HelmReleaseList) DeepCopy() *HelmReleaseList {
if in == nil {
return nil
}
out := new(HelmReleaseList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *HelmReleaseList) 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 *HelmReleaseSpec) DeepCopyInto(out *HelmReleaseSpec) {
*out = *in
if in.Chart != nil {
in, out := &in.Chart, &out.Chart
*out = new(HelmChartTemplate)
(*in).DeepCopyInto(*out)
}
if in.ChartRef != nil {
in, out := &in.ChartRef, &out.ChartRef
*out = new(CrossNamespaceSourceReference)
**out = **in
}
out.Interval = in.Interval
if in.KubeConfig != nil {
in, out := &in.KubeConfig, &out.KubeConfig
*out = new(meta.KubeConfigReference)
(*in).DeepCopyInto(*out)
}
if in.DependsOn != nil {
in, out := &in.DependsOn, &out.DependsOn
*out = make([]meta.NamespacedObjectReference, len(*in))
copy(*out, *in)
}
if in.Timeout != nil {
in, out := &in.Timeout, &out.Timeout
*out = new(metav1.Duration)
**out = **in
}
if in.MaxHistory != nil {
in, out := &in.MaxHistory, &out.MaxHistory
*out = new(int)
**out = **in
}
if in.PersistentClient != nil {
in, out := &in.PersistentClient, &out.PersistentClient
*out = new(bool)
**out = **in
}
if in.DriftDetection != nil {
in, out := &in.DriftDetection, &out.DriftDetection
*out = new(DriftDetection)
(*in).DeepCopyInto(*out)
}
if in.Install != nil {
in, out := &in.Install, &out.Install
*out = new(Install)
(*in).DeepCopyInto(*out)
}
if in.Upgrade != nil {
in, out := &in.Upgrade, &out.Upgrade
*out = new(Upgrade)
(*in).DeepCopyInto(*out)
}
if in.Test != nil {
in, out := &in.Test, &out.Test
*out = new(Test)
(*in).DeepCopyInto(*out)
}
if in.Rollback != nil {
in, out := &in.Rollback, &out.Rollback
*out = new(Rollback)
(*in).DeepCopyInto(*out)
}
if in.Uninstall != nil {
in, out := &in.Uninstall, &out.Uninstall
*out = new(Uninstall)
(*in).DeepCopyInto(*out)
}
if in.ValuesFrom != nil {
in, out := &in.ValuesFrom, &out.ValuesFrom
*out = make([]ValuesReference, len(*in))
copy(*out, *in)
}
if in.Values != nil {
in, out := &in.Values, &out.Values
*out = new(v1.JSON)
(*in).DeepCopyInto(*out)
}
if in.PostRenderers != nil {
in, out := &in.PostRenderers, &out.PostRenderers
*out = make([]PostRenderer, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmReleaseSpec.
func (in *HelmReleaseSpec) DeepCopy() *HelmReleaseSpec {
if in == nil {
return nil
}
out := new(HelmReleaseSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *HelmReleaseStatus) DeepCopyInto(out *HelmReleaseStatus) {
*out = *in
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])
}
}
if in.History != nil {
in, out := &in.History, &out.History
*out = make(v2.Snapshots, len(*in))
for i := range *in {
if (*in)[i] != nil {
in, out := &(*in)[i], &(*out)[i]
*out = new(v2.Snapshot)
(*in).DeepCopyInto(*out)
}
}
}
out.ReconcileRequestStatus = in.ReconcileRequestStatus
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmReleaseStatus.
func (in *HelmReleaseStatus) DeepCopy() *HelmReleaseStatus {
if in == nil {
return nil
}
out := new(HelmReleaseStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *IgnoreRule) DeepCopyInto(out *IgnoreRule) {
*out = *in
if in.Paths != nil {
in, out := &in.Paths, &out.Paths
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.Target != nil {
in, out := &in.Target, &out.Target
*out = new(kustomize.Selector)
**out = **in
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IgnoreRule.
func (in *IgnoreRule) DeepCopy() *IgnoreRule {
if in == nil {
return nil
}
out := new(IgnoreRule)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Install) DeepCopyInto(out *Install) {
*out = *in
if in.Timeout != nil {
in, out := &in.Timeout, &out.Timeout
*out = new(metav1.Duration)
**out = **in
}
if in.Remediation != nil {
in, out := &in.Remediation, &out.Remediation
*out = new(InstallRemediation)
(*in).DeepCopyInto(*out)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Install.
func (in *Install) DeepCopy() *Install {
if in == nil {
return nil
}
out := new(Install)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *InstallRemediation) DeepCopyInto(out *InstallRemediation) {
*out = *in
if in.IgnoreTestFailures != nil {
in, out := &in.IgnoreTestFailures, &out.IgnoreTestFailures
*out = new(bool)
**out = **in
}
if in.RemediateLastFailure != nil {
in, out := &in.RemediateLastFailure, &out.RemediateLastFailure
*out = new(bool)
**out = **in
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InstallRemediation.
func (in *InstallRemediation) DeepCopy() *InstallRemediation {
if in == nil {
return nil
}
out := new(InstallRemediation)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Kustomize) DeepCopyInto(out *Kustomize) {
*out = *in
if in.Patches != nil {
in, out := &in.Patches, &out.Patches
*out = make([]kustomize.Patch, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.PatchesStrategicMerge != nil {
in, out := &in.PatchesStrategicMerge, &out.PatchesStrategicMerge
*out = make([]v1.JSON, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.PatchesJSON6902 != nil {
in, out := &in.PatchesJSON6902, &out.PatchesJSON6902
*out = make([]kustomize.JSON6902Patch, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.Images != nil {
in, out := &in.Images, &out.Images
*out = make([]kustomize.Image, len(*in))
copy(*out, *in)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Kustomize.
func (in *Kustomize) DeepCopy() *Kustomize {
if in == nil {
return nil
}
out := new(Kustomize)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *PostRenderer) DeepCopyInto(out *PostRenderer) {
*out = *in
if in.Kustomize != nil {
in, out := &in.Kustomize, &out.Kustomize
*out = new(Kustomize)
(*in).DeepCopyInto(*out)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PostRenderer.
func (in *PostRenderer) DeepCopy() *PostRenderer {
if in == nil {
return nil
}
out := new(PostRenderer)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Rollback) DeepCopyInto(out *Rollback) {
*out = *in
if in.Timeout != nil {
in, out := &in.Timeout, &out.Timeout
*out = new(metav1.Duration)
**out = **in
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Rollback.
func (in *Rollback) DeepCopy() *Rollback {
if in == nil {
return nil
}
out := new(Rollback)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Snapshot) DeepCopyInto(out *Snapshot) {
*out = *in
in.FirstDeployed.DeepCopyInto(&out.FirstDeployed)
in.LastDeployed.DeepCopyInto(&out.LastDeployed)
in.Deleted.DeepCopyInto(&out.Deleted)
if in.TestHooks != nil {
in, out := &in.TestHooks, &out.TestHooks
*out = new(map[string]*TestHookStatus)
if **in != nil {
in, out := *in, *out
*out = make(map[string]*TestHookStatus, len(*in))
for key, val := range *in {
var outVal *TestHookStatus
if val == nil {
(*out)[key] = nil
} else {
inVal := (*in)[key]
in, out := &inVal, &outVal
*out = new(TestHookStatus)
(*in).DeepCopyInto(*out)
}
(*out)[key] = outVal
}
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Snapshot.
func (in *Snapshot) DeepCopy() *Snapshot {
if in == nil {
return nil
}
out := new(Snapshot)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in Snapshots) DeepCopyInto(out *Snapshots) {
{
in := &in
*out = make(Snapshots, len(*in))
for i := range *in {
if (*in)[i] != nil {
in, out := &(*in)[i], &(*out)[i]
*out = new(Snapshot)
(*in).DeepCopyInto(*out)
}
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Snapshots.
func (in Snapshots) DeepCopy() Snapshots {
if in == nil {
return nil
}
out := new(Snapshots)
in.DeepCopyInto(out)
return *out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Test) DeepCopyInto(out *Test) {
*out = *in
if in.Timeout != nil {
in, out := &in.Timeout, &out.Timeout
*out = new(metav1.Duration)
**out = **in
}
if in.Filters != nil {
in, out := &in.Filters, &out.Filters
*out = new([]Filter)
if **in != nil {
in, out := *in, *out
*out = make([]Filter, len(*in))
copy(*out, *in)
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Test.
func (in *Test) DeepCopy() *Test {
if in == nil {
return nil
}
out := new(Test)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TestHookStatus) DeepCopyInto(out *TestHookStatus) {
*out = *in
in.LastStarted.DeepCopyInto(&out.LastStarted)
in.LastCompleted.DeepCopyInto(&out.LastCompleted)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestHookStatus.
func (in *TestHookStatus) DeepCopy() *TestHookStatus {
if in == nil {
return nil
}
out := new(TestHookStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Uninstall) DeepCopyInto(out *Uninstall) {
*out = *in
if in.Timeout != nil {
in, out := &in.Timeout, &out.Timeout
*out = new(metav1.Duration)
**out = **in
}
if in.DeletionPropagation != nil {
in, out := &in.DeletionPropagation, &out.DeletionPropagation
*out = new(string)
**out = **in
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Uninstall.
func (in *Uninstall) DeepCopy() *Uninstall {
if in == nil {
return nil
}
out := new(Uninstall)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Upgrade) DeepCopyInto(out *Upgrade) {
*out = *in
if in.Timeout != nil {
in, out := &in.Timeout, &out.Timeout
*out = new(metav1.Duration)
**out = **in
}
if in.Remediation != nil {
in, out := &in.Remediation, &out.Remediation
*out = new(UpgradeRemediation)
(*in).DeepCopyInto(*out)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Upgrade.
func (in *Upgrade) DeepCopy() *Upgrade {
if in == nil {
return nil
}
out := new(Upgrade)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *UpgradeRemediation) DeepCopyInto(out *UpgradeRemediation) {
*out = *in
if in.IgnoreTestFailures != nil {
in, out := &in.IgnoreTestFailures, &out.IgnoreTestFailures
*out = new(bool)
**out = **in
}
if in.RemediateLastFailure != nil {
in, out := &in.RemediateLastFailure, &out.RemediateLastFailure
*out = new(bool)
**out = **in
}
if in.Strategy != nil {
in, out := &in.Strategy, &out.Strategy
*out = new(RemediationStrategy)
**out = **in
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UpgradeRemediation.
func (in *UpgradeRemediation) DeepCopy() *UpgradeRemediation {
if in == nil {
return nil
}
out := new(UpgradeRemediation)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ValuesReference) DeepCopyInto(out *ValuesReference) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ValuesReference.
func (in *ValuesReference) DeepCopy() *ValuesReference {
if in == nil {
return nil
}
out := new(ValuesReference)
in.DeepCopyInto(out)
return out
}

File diff suppressed because it is too large Load Diff

View File

@ -2,8 +2,8 @@ apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: helm-system
resources:
- https://github.com/fluxcd/source-controller/releases/download/v1.6.0/source-controller.crds.yaml
- https://github.com/fluxcd/source-controller/releases/download/v1.6.0/source-controller.deployment.yaml
- https://github.com/fluxcd/source-controller/releases/download/v0.16.0/source-controller.crds.yaml
- https://github.com/fluxcd/source-controller/releases/download/v0.16.0/source-controller.deployment.yaml
- ../crd
- ../rbac
- ../manager

View File

@ -18,10 +18,6 @@ spec:
prometheus.io/port: "8080"
spec:
terminationGracePeriodSeconds: 600
securityContext:
# Required for AWS IAM Role bindings
# https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts-technical-overview.html
fsGroup: 1337
containers:
- name: manager
image: fluxcd/helm-controller
@ -29,15 +25,9 @@ spec:
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
runAsNonRoot: true
capabilities:
drop: ["ALL"]
seccompProfile:
type: RuntimeDefault
ports:
- containerPort: 8080
name: http-prom
protocol: TCP
- containerPort: 9440
name: healthz
protocol: TCP

View File

@ -5,4 +5,4 @@ resources:
images:
- name: fluxcd/helm-controller
newName: fluxcd/helm-controller
newTag: v1.3.0
newTag: v0.12.2

View File

@ -1,7 +1,9 @@
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
creationTimestamp: null
name: manager-role
rules:
- apiGroups:
@ -45,7 +47,6 @@ rules:
- source.toolkit.fluxcd.io
resources:
- helmcharts
- ocirepositories
verbs:
- get
- list
@ -54,6 +55,5 @@ rules:
- source.toolkit.fluxcd.io
resources:
- helmcharts/status
- ocirepositories/status
verbs:
- get

View File

@ -1,13 +0,0 @@
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: podinfo-ocirepository
spec:
interval: 5m
chartRef:
kind: OCIRepository
name: podinfo
test:
enable: true
values:
replicaCount: 2

View File

@ -1,4 +1,4 @@
apiVersion: helm.toolkit.fluxcd.io/v2
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: podinfo-gitrepository
@ -10,3 +10,9 @@ spec:
sourceRef:
kind: GitRepository
name: podinfo
interval: 1m
upgrade:
remediation:
remediateLastFailure: true
test:
enable: true

View File

@ -1,4 +1,4 @@
apiVersion: helm.toolkit.fluxcd.io/v2
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: podinfo-helmrepository
@ -7,8 +7,13 @@ spec:
chart:
spec:
chart: podinfo
version: '>=6.0.0 <7.0.0'
version: '>=4.0.0 <5.0.0'
sourceRef:
kind: HelmRepository
name: podinfo
interval: 10m
interval: 1m
upgrade:
remediation:
remediateLastFailure: true
test:
enable: true

View File

@ -1,9 +0,0 @@
apiVersion: source.toolkit.fluxcd.io/v1
kind: OCIRepository
metadata:
name: podinfo
spec:
interval: 1m
url: oci://ghcr.io/stefanprodan/charts/podinfo
ref:
semver: 6.x

View File

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

View File

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

View File

@ -1,5 +1,5 @@
---
apiVersion: source.toolkit.fluxcd.io/v1
apiVersion: source.toolkit.fluxcd.io/v1beta1
kind: GitRepository
metadata:
name: this
@ -11,6 +11,6 @@ spec:
{{- if .Values.branch }}
branch: "{{ .Values.branch }}"
{{- end}}
{{- if .Values.tag }}
{{- if .Values.branch }}
tag: "{{ .Values.tag }}"
{{- end}}
{{- end}}

View File

@ -1,5 +1,5 @@
---
apiVersion: helm.toolkit.fluxcd.io/v2beta2
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: crds-upgrade-test

View File

@ -1,5 +1,5 @@
---
apiVersion: helm.toolkit.fluxcd.io/v2beta2
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: crds-upgrade-test

View File

@ -1,5 +1,5 @@
---
apiVersion: helm.toolkit.fluxcd.io/v2beta2
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: crds-upgrade-test

View File

@ -1,68 +0,0 @@
apiVersion: v1
kind: Namespace
metadata:
name: delete-ns
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: gotk-reconciler
namespace: delete-ns
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: gotk-reconciler
namespace: delete-ns
rules:
- apiGroups:
- ""
resources:
- '*'
verbs:
- '*'
- apiGroups:
- apps
resources:
- '*'
verbs:
- '*'
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: gotk-reconciler
namespace: delete-ns
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: gotk-reconciler
subjects:
- kind: ServiceAccount
name: gotk-reconciler
namespace: delete-ns
---
apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: HelmRepository
metadata:
name: podinfo
namespace: delete-ns
spec:
interval: 1m
url: https://stefanprodan.github.io/podinfo
---
apiVersion: helm.toolkit.fluxcd.io/v2beta2
kind: HelmRelease
metadata:
name: podinfo
namespace: delete-ns
spec:
serviceAccountName: gotk-reconciler
interval: 5m
chart:
spec:
chart: podinfo
version: 6.3.5
sourceRef:
kind: HelmRepository
name: podinfo

View File

@ -1,4 +1,4 @@
apiVersion: helm.toolkit.fluxcd.io/v2beta2
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: backend
@ -7,7 +7,7 @@ spec:
chart:
spec:
chart: podinfo
version: '>=6.0.0 <7.0.0'
version: '>=4.0.0 <5.0.0'
sourceRef:
kind: HelmRepository
name: podinfo

View File

@ -1,4 +1,4 @@
apiVersion: helm.toolkit.fluxcd.io/v2beta2
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: frontend
@ -7,7 +7,7 @@ spec:
chart:
spec:
chart: podinfo
version: '>=6.0.0 <7.0.0'
version: '>=4.0.0 <5.0.0'
sourceRef:
kind: HelmRepository
name: podinfo

View File

@ -42,7 +42,7 @@ subjects:
name: gotk-reconciler
namespace: impersonation
---
apiVersion: source.toolkit.fluxcd.io/v1beta2
apiVersion: source.toolkit.fluxcd.io/v1beta1
kind: HelmRepository
metadata:
name: podinfo
@ -51,7 +51,7 @@ spec:
interval: 1m
url: https://stefanprodan.github.io/podinfo
---
apiVersion: helm.toolkit.fluxcd.io/v2beta2
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: podinfo
@ -62,12 +62,12 @@ spec:
chart:
spec:
chart: podinfo
version: 6.3.5
version: 5.0.3
sourceRef:
kind: HelmRepository
name: podinfo
---
apiVersion: helm.toolkit.fluxcd.io/v2beta2
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: podinfo-fail
@ -78,7 +78,7 @@ spec:
chart:
spec:
chart: podinfo
version: 6.3.5
version: 5.0.3
sourceRef:
kind: HelmRepository
name: podinfo

View File

@ -1,4 +1,4 @@
apiVersion: helm.toolkit.fluxcd.io/v2beta2
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: install-create-target-ns
@ -9,7 +9,7 @@ spec:
chart:
spec:
chart: podinfo
version: '>=6.0.0 <7.0.0'
version: '>=4.0.0 <5.0.0'
sourceRef:
kind: HelmRepository
name: podinfo

View File

@ -1,22 +1,20 @@
apiVersion: helm.toolkit.fluxcd.io/v2beta2
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: install-fail-remediate
spec:
interval: 30s
interval: 5m
chart:
spec:
chart: podinfo
version: '>=6.0.0 <7.0.0'
version: '>=4.0.0 <5.0.0'
sourceRef:
kind: HelmRepository
name: podinfo
interval: 10m
interval: 1m
install:
remediation:
remediateLastFailure: true
uninstall:
keepHistory: true
values:
resources:
requests:

View File

@ -1,17 +1,17 @@
apiVersion: helm.toolkit.fluxcd.io/v2beta2
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: install-fail-retry
spec:
interval: 30s
interval: 5m
chart:
spec:
chart: podinfo
version: '>=6.0.0 <7.0.0'
version: '>=4.0.0 <5.0.0'
sourceRef:
kind: HelmRepository
name: podinfo
interval: 10m
interval: 1m
install:
remediation:
retries: 1

View File

@ -1,17 +1,17 @@
apiVersion: helm.toolkit.fluxcd.io/v2beta2
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: install-fail
spec:
interval: 30s
interval: 5m
chart:
spec:
chart: podinfo
version: '>=6.0.0 <7.0.0'
version: '>=4.0.0 <5.0.0'
sourceRef:
kind: HelmRepository
name: podinfo
interval: 10m
interval: 1m
values:
resources:
requests:

View File

@ -1,29 +0,0 @@
---
apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: HelmChart
metadata:
name: podinfo-hc
spec:
chart: podinfo
version: '6.2.1'
sourceRef:
kind: HelmRepository
name: podinfo-oci
interval: 30s
verify:
provider: cosign
---
apiVersion: helm.toolkit.fluxcd.io/v2beta2
kind: HelmRelease
metadata:
name: podinfo-from-hc
spec:
chartRef:
kind: HelmChart
name: podinfo-hc
interval: 30s
values:
resources:
requests:
cpu: 100m
memory: 64Mi

View File

@ -1,25 +0,0 @@
---
apiVersion: source.toolkit.fluxcd.io/v1
kind: OCIRepository
metadata:
name: podinfo-ocirepo
spec:
interval: 30s
url: oci://ghcr.io/stefanprodan/charts/podinfo
ref:
tag: 6.6.0
---
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: podinfo-from-ocirepo
spec:
chartRef:
kind: OCIRepository
name: podinfo-ocirepo
interval: 30s
values:
resources:
requests:
cpu: 100m
memory: 64Mi

View File

@ -1,17 +1,17 @@
apiVersion: helm.toolkit.fluxcd.io/v2beta2
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: install-test-fail-ignore
spec:
interval: 30s
interval: 5m
chart:
spec:
chart: podinfo
version: '>=6.0.0 <7.0.0'
version: '>=4.0.0 <5.0.0'
sourceRef:
kind: HelmRepository
name: podinfo
interval: 10m
interval: 1m
test:
enable: true
ignoreFailures: true

View File

@ -1,17 +1,17 @@
apiVersion: helm.toolkit.fluxcd.io/v2beta2
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: install-test-fail
spec:
interval: 30s
interval: 5m
chart:
spec:
chart: podinfo
version: '>=6.0.0 <7.0.0'
version: '>=4.0.0 <5.0.0'
sourceRef:
kind: HelmRepository
name: podinfo
interval: 10m
interval: 1m
test:
enable: true
values:

View File

@ -1,4 +1,4 @@
apiVersion: helm.toolkit.fluxcd.io/v2beta2
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: podinfo-git

View File

@ -1,21 +0,0 @@
apiVersion: helm.toolkit.fluxcd.io/v2beta2
kind: HelmRelease
metadata:
name: podinfo-oci
spec:
interval: 5m
chart:
spec:
chart: podinfo
version: '6.2.1'
sourceRef:
kind: HelmRepository
name: podinfo-oci
interval: 1m
verify:
provider: cosign
values:
resources:
requests:
cpu: 100m
memory: 64Mi

View File

@ -1,4 +1,4 @@
apiVersion: helm.toolkit.fluxcd.io/v2beta2
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: podinfo
@ -7,7 +7,7 @@ spec:
chart:
spec:
chart: podinfo
version: '>=6.0.0 <7.0.0'
version: '>=4.0.0 <5.0.0'
sourceRef:
kind: HelmRepository
name: podinfo

View File

@ -1,4 +1,4 @@
apiVersion: helm.toolkit.fluxcd.io/v2beta2
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: post-renderer-kustomize
@ -7,7 +7,7 @@ spec:
chart:
spec:
chart: podinfo
version: '>=6.0.0 <6.9.0'
version: '>=4.0.0 <5.0.0'
sourceRef:
kind: HelmRepository
name: podinfo
@ -16,20 +16,20 @@ spec:
fullnameOverride: mypodinfo
postRenderers:
- kustomize:
patches:
- patch: |
kind: Deployment
apiVersion: apps/v1
metadata:
name: mypodinfo
labels:
xxxx: yyyy
patchesStrategicMerge:
- kind: Deployment
apiVersion: apps/v1
metadata:
name: mypodinfo
labels:
xxxx: yyyy
patchesJson6902:
- target:
group: apps
version: v1
kind: Deployment
name: mypodinfo
patch: |
- op: add
path: /metadata/labels/yyyy
value: xxxx
patch:
- op: add
path: /metadata/labels/yyyy
value: xxxx

View File

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

View File

@ -1,4 +1,4 @@
apiVersion: source.toolkit.fluxcd.io/v1beta2
apiVersion: source.toolkit.fluxcd.io/v1beta1
kind: HelmRepository
metadata:
name: podinfo

View File

@ -1,8 +0,0 @@
apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: HelmRepository
metadata:
name: podinfo-oci
spec:
interval: 1m
url: oci://ghcr.io/stefanprodan/charts
type: "oci"

View File

@ -1,4 +1,4 @@
apiVersion: helm.toolkit.fluxcd.io/v2beta2
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: status-defaults
@ -7,7 +7,7 @@ spec:
chart:
spec:
chart: podinfo
version: '>=6.0.0 <7.0.0'
version: '>=4.0.0 <5.0.0'
sourceRef:
kind: HelmRepository
name: podinfo

View File

@ -1,4 +1,4 @@
apiVersion: helm.toolkit.fluxcd.io/v2beta2
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: targetnamespace
@ -7,7 +7,7 @@ spec:
chart:
spec:
chart: podinfo
version: '>=6.0.0 <7.0.0'
version: '>=4.0.0 <5.0.0'
sourceRef:
kind: HelmRepository
name: podinfo

View File

@ -1,17 +1,17 @@
apiVersion: helm.toolkit.fluxcd.io/v2beta2
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: upgrade-fail-remediate-uninstall
spec:
interval: 30s
interval: 5m
chart:
spec:
chart: podinfo
version: '>=6.0.0 <7.0.0'
version: '>=4.0.0 <5.0.0'
sourceRef:
kind: HelmRepository
name: podinfo
interval: 10m
interval: 1m
values:
resources:
requests:

View File

@ -1,17 +1,17 @@
apiVersion: helm.toolkit.fluxcd.io/v2beta2
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: upgrade-fail-remediate-uninstall
spec:
interval: 30s
interval: 5m
chart:
spec:
chart: podinfo
version: '>=6.0.0 <7.0.0'
version: '>=4.0.0 <5.0.0'
sourceRef:
kind: HelmRepository
name: podinfo
interval: 10m
interval: 1m
upgrade:
remediation:
remediateLastFailure: true

View File

@ -1,17 +1,17 @@
apiVersion: helm.toolkit.fluxcd.io/v2beta2
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: upgrade-fail-remediate
spec:
interval: 30s
interval: 5m
chart:
spec:
chart: podinfo
version: '>=6.0.0 <7.0.0'
version: '>=4.0.0 <5.0.0'
sourceRef:
kind: HelmRepository
name: podinfo
interval: 10m
interval: 1m
values:
resources:
requests:

View File

@ -1,17 +1,17 @@
apiVersion: helm.toolkit.fluxcd.io/v2beta2
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: upgrade-fail-remediate
spec:
interval: 30s
interval: 5m
chart:
spec:
chart: podinfo
version: '>=6.0.0 <7.0.0'
version: '>=4.0.0 <5.0.0'
sourceRef:
kind: HelmRepository
name: podinfo
interval: 10m
interval: 1m
upgrade:
remediation:
remediateLastFailure: true

View File

@ -1,17 +1,17 @@
apiVersion: helm.toolkit.fluxcd.io/v2beta2
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: upgrade-fail-retry
spec:
interval: 30s
interval: 5m
chart:
spec:
chart: podinfo
version: '>=6.0.0 <7.0.0'
version: '>=4.0.0 <5.0.0'
sourceRef:
kind: HelmRepository
name: podinfo
interval: 10m
interval: 1m
values:
resources:
requests:

View File

@ -1,17 +1,17 @@
apiVersion: helm.toolkit.fluxcd.io/v2beta2
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: upgrade-fail-retry
spec:
interval: 30s
interval: 5m
chart:
spec:
chart: podinfo
version: '>=6.0.0 <7.0.0'
version: '>=4.0.0 <5.0.0'
sourceRef:
kind: HelmRepository
name: podinfo
interval: 10m
interval: 1m
upgrade:
remediation:
retries: 1

View File

@ -1,17 +1,17 @@
apiVersion: helm.toolkit.fluxcd.io/v2beta2
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: upgrade-fail
spec:
interval: 30s
interval: 5m
chart:
spec:
chart: podinfo
version: '>=6.0.0 <7.0.0'
version: '>=4.0.0 <5.0.0'
sourceRef:
kind: HelmRepository
name: podinfo
interval: 10m
interval: 1m
values:
resources:
requests:

View File

@ -1,17 +1,17 @@
apiVersion: helm.toolkit.fluxcd.io/v2beta2
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: upgrade-fail
spec:
interval: 30s
interval: 5m
chart:
spec:
chart: podinfo
version: '>=6.0.0 <7.0.0'
version: '>=4.0.0 <5.0.0'
sourceRef:
kind: HelmRepository
name: podinfo
interval: 10m
interval: 1m
values:
resources:
requests:

View File

@ -1,25 +0,0 @@
---
apiVersion: source.toolkit.fluxcd.io/v1
kind: OCIRepository
metadata:
name: upgrade-from-ocirepo-source
spec:
interval: 30s
url: oci://ghcr.io/stefanprodan/charts/podinfo
ref:
digest: "sha256:cdd538a0167e4b51152b71a477e51eb6737553510ce8797dbcc537e1342311bb"
---
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: upgrade-from-ocirepo-source
spec:
chartRef:
kind: OCIRepository
name: upgrade-from-ocirepo-source
interval: 30s
values:
resources:
requests:
cpu: 100m
memory: 64Mi

View File

@ -1,10 +0,0 @@
---
apiVersion: source.toolkit.fluxcd.io/v1
kind: OCIRepository
metadata:
name: upgrade-from-ocirepo-source
spec:
interval: 30s
url: oci://ghcr.io/stefanprodan/charts/podinfo
ref:
digest: "sha256:0cc9a8446c95009ef382f5eade883a67c257f77d50f84e78ecef2aac9428d1e5"

View File

@ -1,17 +1,17 @@
apiVersion: helm.toolkit.fluxcd.io/v2beta2
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: upgrade-test-fail
spec:
interval: 30s
interval: 5m
chart:
spec:
chart: podinfo
version: '>=6.0.0 <7.0.0'
version: '>=4.0.0 <5.0.0'
sourceRef:
kind: HelmRepository
name: podinfo
interval: 10m
interval: 1m
values:
resources:
requests:

View File

@ -1,17 +1,17 @@
apiVersion: helm.toolkit.fluxcd.io/v2beta2
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: upgrade-test-fail
spec:
interval: 30s
interval: 5m
chart:
spec:
chart: podinfo
version: '>=6.0.0 <7.0.0'
version: '>=4.0.0 <5.0.0'
sourceRef:
kind: HelmRepository
name: podinfo
interval: 10m
interval: 1m
test:
enable: true
values:

View File

@ -1,4 +1,4 @@
apiVersion: helm.toolkit.fluxcd.io/v2beta2
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: valuesfrom
@ -7,11 +7,11 @@ spec:
chart:
spec:
chart: podinfo
version: '>=6.0.0 <7.0.0'
version: '>=4.0.0 <5.0.0'
sourceRef:
kind: HelmRepository
name: podinfo
interval: 10m
interval: 1m
valuesFrom:
- kind: ConfigMap
name: valuesfrom-config

View File

@ -0,0 +1,796 @@
/*
Copyright 2020 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"
"errors"
"fmt"
"strings"
"time"
"github.com/go-logr/logr"
"github.com/hashicorp/go-retryablehttp"
"helm.sh/helm/v3/pkg/chart"
"helm.sh/helm/v3/pkg/chartutil"
"helm.sh/helm/v3/pkg/storage/driver"
"helm.sh/helm/v3/pkg/strvals"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
apimeta "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/client-go/rest"
kuberecorder "k8s.io/client-go/tools/record"
"k8s.io/client-go/tools/reference"
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/reconcile"
"sigs.k8s.io/controller-runtime/pkg/source"
"github.com/fluxcd/pkg/apis/meta"
"github.com/fluxcd/pkg/runtime/events"
"github.com/fluxcd/pkg/runtime/metrics"
"github.com/fluxcd/pkg/runtime/predicates"
"github.com/fluxcd/pkg/runtime/transform"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
v2 "github.com/fluxcd/helm-controller/api/v2beta1"
"github.com/fluxcd/helm-controller/internal/kube"
"github.com/fluxcd/helm-controller/internal/runner"
"github.com/fluxcd/helm-controller/internal/util"
)
// +kubebuilder:rbac:groups=helm.toolkit.fluxcd.io,resources=helmreleases,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=helm.toolkit.fluxcd.io,resources=helmreleases/status,verbs=get;update;patch
// +kubebuilder:rbac:groups=helm.toolkit.fluxcd.io,resources=helmreleases/finalizers,verbs=get;create;update;patch;delete
// +kubebuilder:rbac:groups=source.toolkit.fluxcd.io,resources=helmcharts,verbs=get;list;watch
// +kubebuilder:rbac:groups=source.toolkit.fluxcd.io,resources=helmcharts/status,verbs=get
// +kubebuilder:rbac:groups="",resources=events,verbs=create;patch
// HelmReleaseReconciler reconciles a HelmRelease object
type HelmReleaseReconciler struct {
client.Client
httpClient *retryablehttp.Client
Config *rest.Config
Scheme *runtime.Scheme
requeueDependency time.Duration
EventRecorder kuberecorder.EventRecorder
ExternalEventRecorder *events.Recorder
MetricsRecorder *metrics.Recorder
}
func (r *HelmReleaseReconciler) SetupWithManager(mgr ctrl.Manager, opts HelmReleaseReconcilerOptions) error {
// Index the HelmRelease by the HelmChart references they point at
if err := mgr.GetFieldIndexer().IndexField(context.TODO(), &v2.HelmRelease{}, v2.SourceIndexKey,
func(o client.Object) []string {
hr := o.(*v2.HelmRelease)
return []string{
fmt.Sprintf("%s/%s", hr.Spec.Chart.GetNamespace(hr.GetNamespace()), hr.GetHelmChartName()),
}
},
); err != nil {
return err
}
r.requeueDependency = opts.DependencyRequeueInterval
// Configure the retryable http client used for fetching artifacts.
// By default it retries 10 times within a 3.5 minutes window.
httpClient := retryablehttp.NewClient()
httpClient.RetryWaitMin = 5 * time.Second
httpClient.RetryWaitMax = 30 * time.Second
httpClient.RetryMax = opts.HTTPRetry
httpClient.Logger = nil
r.httpClient = httpClient
return ctrl.NewControllerManagedBy(mgr).
For(&v2.HelmRelease{}, builder.WithPredicates(
predicate.Or(predicate.GenerationChangedPredicate{}, predicates.ReconcileRequestedPredicate{}),
)).
Watches(
&source.Kind{Type: &sourcev1.HelmChart{}},
handler.EnqueueRequestsFromMapFunc(r.requestsForHelmChartChange),
builder.WithPredicates(SourceRevisionChangePredicate{}),
).
WithOptions(controller.Options{MaxConcurrentReconciles: opts.MaxConcurrentReconciles}).
Complete(r)
}
// ConditionError represents an error with a status condition reason attached.
type ConditionError struct {
Reason string
Err error
}
func (c ConditionError) Error() string {
return c.Err.Error()
}
func (r *HelmReleaseReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
start := time.Now()
log := logr.FromContext(ctx)
var hr v2.HelmRelease
if err := r.Get(ctx, req.NamespacedName, &hr); err != nil {
return ctrl.Result{}, client.IgnoreNotFound(err)
}
// record suspension metrics
defer r.recordSuspension(ctx, hr)
// Add our finalizer if it does not exist
if !controllerutil.ContainsFinalizer(&hr, v2.HelmReleaseFinalizer) {
controllerutil.AddFinalizer(&hr, v2.HelmReleaseFinalizer)
if err := r.Update(ctx, &hr); err != nil {
log.Error(err, "unable to register finalizer")
return ctrl.Result{}, err
}
}
// Examine if the object is under deletion
if !hr.ObjectMeta.DeletionTimestamp.IsZero() {
return r.reconcileDelete(ctx, hr)
}
// Return early if the HelmRelease is suspended.
if hr.Spec.Suspend {
log.Info("Reconciliation is suspended for this object")
return ctrl.Result{}, nil
}
hr, result, err := r.reconcile(ctx, hr)
// Update status after reconciliation.
if updateStatusErr := r.patchStatus(ctx, &hr); updateStatusErr != nil {
log.Error(updateStatusErr, "unable to update status after reconciliation")
return ctrl.Result{Requeue: true}, updateStatusErr
}
// Record ready status
r.recordReadiness(ctx, hr)
// Log reconciliation duration
durationMsg := fmt.Sprintf("reconcilation finished in %s", time.Now().Sub(start).String())
if result.RequeueAfter > 0 {
durationMsg = fmt.Sprintf("%s, next run in %s", durationMsg, result.RequeueAfter.String())
}
log.Info(durationMsg)
return result, err
}
func (r *HelmReleaseReconciler) reconcile(ctx context.Context, hr v2.HelmRelease) (v2.HelmRelease, ctrl.Result, error) {
reconcileStart := time.Now()
log := logr.FromContext(ctx)
// Record the value of the reconciliation request, if any
if v, ok := meta.ReconcileAnnotationValue(hr.GetAnnotations()); ok {
hr.Status.SetLastHandledReconcileRequest(v)
}
// Observe HelmRelease generation.
if hr.Status.ObservedGeneration != hr.Generation {
hr.Status.ObservedGeneration = hr.Generation
hr = v2.HelmReleaseProgressing(hr)
if updateStatusErr := r.patchStatus(ctx, &hr); updateStatusErr != nil {
log.Error(updateStatusErr, "unable to update status after generation update")
return hr, ctrl.Result{Requeue: true}, updateStatusErr
}
// Record progressing status
r.recordReadiness(ctx, hr)
}
// Record reconciliation duration
if r.MetricsRecorder != nil {
objRef, err := reference.GetReference(r.Scheme, &hr)
if err != nil {
return hr, ctrl.Result{Requeue: true}, err
}
defer r.MetricsRecorder.RecordDuration(*objRef, reconcileStart)
}
// Reconcile chart based on the HelmChartTemplate
hc, reconcileErr := r.reconcileChart(ctx, &hr)
if reconcileErr != nil {
msg := fmt.Sprintf("chart reconciliation failed: %s", reconcileErr.Error())
r.event(ctx, hr, hr.Status.LastAttemptedRevision, events.EventSeverityError, msg)
return v2.HelmReleaseNotReady(hr, v2.ArtifactFailedReason, msg), ctrl.Result{Requeue: true}, reconcileErr
}
// Check chart readiness
if hc.Generation != hc.Status.ObservedGeneration || !apimeta.IsStatusConditionTrue(hc.Status.Conditions, meta.ReadyCondition) {
msg := fmt.Sprintf("HelmChart '%s/%s' is not ready", hc.GetNamespace(), hc.GetName())
r.event(ctx, hr, hr.Status.LastAttemptedRevision, events.EventSeverityInfo, msg)
log.Info(msg)
// Do not requeue immediately, when the artifact is created
// the watcher should trigger a reconciliation.
return v2.HelmReleaseNotReady(hr, v2.ArtifactFailedReason, msg), ctrl.Result{RequeueAfter: hc.Spec.Interval.Duration}, nil
}
// Check dependencies
if len(hr.Spec.DependsOn) > 0 {
if err := r.checkDependencies(hr); err != nil {
msg := fmt.Sprintf("dependencies do not meet ready condition (%s), retrying in %s",
err.Error(), r.requeueDependency.String())
r.event(ctx, hr, hc.GetArtifact().Revision, events.EventSeverityInfo, msg)
log.Info(msg)
// Exponential backoff would cause execution to be prolonged too much,
// instead we requeue on a fixed interval.
return v2.HelmReleaseNotReady(hr,
meta.DependencyNotReadyReason, err.Error()), ctrl.Result{RequeueAfter: r.requeueDependency}, nil
}
log.Info("all dependencies are ready, proceeding with release")
}
// Compose values
values, err := r.composeValues(ctx, hr)
if err != nil {
r.event(ctx, hr, hr.Status.LastAttemptedRevision, events.EventSeverityError, err.Error())
return v2.HelmReleaseNotReady(hr, v2.InitFailedReason, err.Error()), ctrl.Result{Requeue: true}, nil
}
// Load chart from artifact
chart, err := r.loadHelmChart(hc)
if err != nil {
r.event(ctx, hr, hr.Status.LastAttemptedRevision, events.EventSeverityError, err.Error())
return v2.HelmReleaseNotReady(hr, v2.ArtifactFailedReason, err.Error()), ctrl.Result{Requeue: true}, nil
}
// Reconcile Helm release
reconciledHr, reconcileErr := r.reconcileRelease(ctx, *hr.DeepCopy(), chart, values)
if reconcileErr != nil {
r.event(ctx, hr, hc.GetArtifact().Revision, events.EventSeverityError,
fmt.Sprintf("reconciliation failed: %s", reconcileErr.Error()))
}
return reconciledHr, ctrl.Result{RequeueAfter: hr.Spec.Interval.Duration}, reconcileErr
}
type HelmReleaseReconcilerOptions struct {
MaxConcurrentReconciles int
HTTPRetry int
DependencyRequeueInterval time.Duration
}
func (r *HelmReleaseReconciler) reconcileRelease(ctx context.Context,
hr v2.HelmRelease, chart *chart.Chart, values chartutil.Values) (v2.HelmRelease, error) {
log := logr.FromContext(ctx)
// Initialize Helm action runner
getter, err := r.getRESTClientGetter(ctx, hr)
if err != nil {
return v2.HelmReleaseNotReady(hr, v2.InitFailedReason, err.Error()), err
}
run, err := runner.NewRunner(getter, hr.GetStorageNamespace(), log)
if err != nil {
return v2.HelmReleaseNotReady(hr, v2.InitFailedReason, "failed to initialize Helm action runner"), err
}
// Determine last release revision.
rel, observeLastReleaseErr := run.ObserveLastRelease(hr)
if observeLastReleaseErr != nil {
err = fmt.Errorf("failed to get last release revision: %w", observeLastReleaseErr)
return v2.HelmReleaseNotReady(hr, v2.GetLastReleaseFailedReason, "failed to get last release revision"), err
}
// Register the current release attempt.
revision := chart.Metadata.Version
releaseRevision := util.ReleaseRevision(rel)
valuesChecksum := util.ValuesChecksum(values)
hr, hasNewState := v2.HelmReleaseAttempted(hr, revision, releaseRevision, valuesChecksum)
if hasNewState {
hr = v2.HelmReleaseProgressing(hr)
if updateStatusErr := r.patchStatus(ctx, &hr); updateStatusErr != nil {
log.Error(updateStatusErr, "unable to update status after state update")
return hr, updateStatusErr
}
// Record progressing status
r.recordReadiness(ctx, hr)
}
// Check status of any previous release attempt.
released := apimeta.FindStatusCondition(hr.Status.Conditions, v2.ReleasedCondition)
if released != nil {
switch released.Status {
// Succeed if the previous release attempt succeeded.
case metav1.ConditionTrue:
return v2.HelmReleaseReady(hr), nil
case metav1.ConditionFalse:
// Fail if the previous release attempt remediation failed.
remediated := apimeta.FindStatusCondition(hr.Status.Conditions, v2.RemediatedCondition)
if remediated != nil && remediated.Status == metav1.ConditionFalse {
err = fmt.Errorf("previous release attempt remediation failed")
return v2.HelmReleaseNotReady(hr, remediated.Reason, remediated.Message), err
}
}
// Fail if install retries are exhausted.
if hr.Spec.GetInstall().GetRemediation().RetriesExhausted(hr) {
err = fmt.Errorf("install retries exhausted")
return v2.HelmReleaseNotReady(hr, released.Reason, err.Error()), err
}
// Fail if there is a release and upgrade retries are exhausted.
// This avoids failing after an upgrade uninstall remediation strategy.
if rel != nil && hr.Spec.GetUpgrade().GetRemediation().RetriesExhausted(hr) {
err = fmt.Errorf("upgrade retries exhausted")
return v2.HelmReleaseNotReady(hr, released.Reason, err.Error()), err
}
}
// Deploy the release.
var deployAction v2.DeploymentAction
if rel == nil {
r.event(ctx, hr, revision, events.EventSeverityInfo, "Helm install has started")
deployAction = hr.Spec.GetInstall()
rel, err = run.Install(hr, chart, values)
err = r.handleHelmActionResult(ctx, &hr, revision, err, deployAction.GetDescription(),
v2.ReleasedCondition, v2.InstallSucceededReason, v2.InstallFailedReason)
} else {
r.event(ctx, hr, revision, events.EventSeverityInfo, "Helm upgrade has started")
deployAction = hr.Spec.GetUpgrade()
rel, err = run.Upgrade(hr, chart, values)
err = r.handleHelmActionResult(ctx, &hr, revision, err, deployAction.GetDescription(),
v2.ReleasedCondition, v2.UpgradeSucceededReason, v2.UpgradeFailedReason)
}
remediation := deployAction.GetRemediation()
// If there is a new release revision...
if util.ReleaseRevision(rel) > releaseRevision {
// Ensure release is not marked remediated.
apimeta.RemoveStatusCondition(&hr.Status.Conditions, v2.RemediatedCondition)
// If new release revision is successful and tests are enabled, run them.
if err == nil && hr.Spec.GetTest().Enable {
_, testErr := run.Test(hr)
testErr = r.handleHelmActionResult(ctx, &hr, revision, testErr, "test",
v2.TestSuccessCondition, v2.TestSucceededReason, v2.TestFailedReason)
// Propagate any test error if not marked ignored.
if testErr != nil && !remediation.MustIgnoreTestFailures(hr.Spec.GetTest().IgnoreFailures) {
testsPassing := apimeta.FindStatusCondition(hr.Status.Conditions, v2.TestSuccessCondition)
meta.SetResourceCondition(&hr, v2.ReleasedCondition, metav1.ConditionFalse, testsPassing.Reason, testsPassing.Message)
err = testErr
}
}
}
if err != nil {
// Increment failure count for deployment action.
remediation.IncrementFailureCount(&hr)
// Remediate deployment failure if necessary.
if !remediation.RetriesExhausted(hr) || remediation.MustRemediateLastFailure() {
if util.ReleaseRevision(rel) <= releaseRevision {
log.Info(fmt.Sprintf("skipping remediation, no new release revision created"))
} else {
var remediationErr error
switch remediation.GetStrategy() {
case v2.RollbackRemediationStrategy:
rollbackErr := run.Rollback(hr)
remediationErr = r.handleHelmActionResult(ctx, &hr, revision, rollbackErr, "rollback",
v2.RemediatedCondition, v2.RollbackSucceededReason, v2.RollbackFailedReason)
case v2.UninstallRemediationStrategy:
uninstallErr := run.Uninstall(hr)
remediationErr = r.handleHelmActionResult(ctx, &hr, revision, uninstallErr, "uninstall",
v2.RemediatedCondition, v2.UninstallSucceededReason, v2.UninstallFailedReason)
}
if remediationErr != nil {
err = remediationErr
}
}
// Determine release after remediation.
rel, observeLastReleaseErr = run.ObserveLastRelease(hr)
if observeLastReleaseErr != nil {
err = &ConditionError{
Reason: v2.GetLastReleaseFailedReason,
Err: errors.New("failed to get last release revision after remediation"),
}
}
}
}
hr.Status.LastReleaseRevision = util.ReleaseRevision(rel)
if err != nil {
reason := meta.ReconciliationFailedReason
if condErr := (*ConditionError)(nil); errors.As(err, &condErr) {
reason = condErr.Reason
}
return v2.HelmReleaseNotReady(hr, reason, err.Error()), err
}
return v2.HelmReleaseReady(hr), nil
}
func (r *HelmReleaseReconciler) checkDependencies(hr v2.HelmRelease) error {
for _, d := range hr.Spec.DependsOn {
if d.Namespace == "" {
d.Namespace = hr.GetNamespace()
}
dName := types.NamespacedName(d)
var dHr v2.HelmRelease
err := r.Get(context.Background(), dName, &dHr)
if err != nil {
return fmt.Errorf("unable to get '%s' dependency: %w", dName, err)
}
if len(dHr.Status.Conditions) == 0 || dHr.Generation != dHr.Status.ObservedGeneration {
return fmt.Errorf("dependency '%s' is not ready", dName)
}
if !apimeta.IsStatusConditionTrue(dHr.Status.Conditions, meta.ReadyCondition) {
return fmt.Errorf("dependency '%s' is not ready", dName)
}
}
return nil
}
func (r *HelmReleaseReconciler) getRESTClientGetter(ctx context.Context, hr v2.HelmRelease) (genericclioptions.RESTClientGetter, error) {
if hr.Spec.KubeConfig == nil {
// impersonate service account if specified
if hr.Spec.ServiceAccountName != "" {
token, err := r.getServiceAccountToken(ctx, hr)
if err != nil {
return nil, fmt.Errorf("could not impersonate ServiceAccount '%s': %w", hr.Spec.ServiceAccountName, err)
}
config := *r.Config
config.BearerToken = token
return kube.NewInClusterRESTClientGetter(&config, hr.GetReleaseNamespace()), nil
}
return kube.NewInClusterRESTClientGetter(r.Config, hr.GetReleaseNamespace()), nil
}
secretName := types.NamespacedName{
Namespace: hr.GetNamespace(),
Name: hr.Spec.KubeConfig.SecretRef.Name,
}
var secret corev1.Secret
if err := r.Get(ctx, secretName, &secret); err != nil {
return nil, fmt.Errorf("could not find KubeConfig secret '%s': %w", secretName, err)
}
var kubeConfig []byte
for k, _ := range secret.Data {
if k == "value" || k == "value.yaml" {
kubeConfig = secret.Data[k]
break
}
}
if len(kubeConfig) == 0 {
return nil, fmt.Errorf("KubeConfig secret '%s' does not contain a 'value' key", secretName)
}
return kube.NewMemoryRESTClientGetter(kubeConfig, hr.GetReleaseNamespace()), nil
}
func (r *HelmReleaseReconciler) getServiceAccountToken(ctx context.Context, hr v2.HelmRelease) (string, error) {
namespacedName := types.NamespacedName{
Namespace: hr.Namespace,
Name: hr.Spec.ServiceAccountName,
}
var serviceAccount corev1.ServiceAccount
err := r.Client.Get(ctx, namespacedName, &serviceAccount)
if err != nil {
return "", err
}
secretName := types.NamespacedName{
Namespace: hr.Namespace,
Name: hr.Spec.ServiceAccountName,
}
for _, secret := range serviceAccount.Secrets {
if strings.HasPrefix(secret.Name, fmt.Sprintf("%s-token", serviceAccount.Name)) {
secretName.Name = secret.Name
break
}
}
var secret corev1.Secret
err = r.Client.Get(ctx, secretName, &secret)
if err != nil {
return "", err
}
var token string
if data, ok := secret.Data["token"]; ok {
token = string(data)
} else {
return "", fmt.Errorf("the service account secret '%s' does not containt a token", secretName.String())
}
return token, nil
}
// composeValues attempts to resolve all v2beta1.ValuesReference resources
// and merges them as defined. Referenced resources are only retrieved once
// to ensure a single version is taken into account during the merge.
func (r *HelmReleaseReconciler) composeValues(ctx context.Context, hr v2.HelmRelease) (chartutil.Values, error) {
result := chartutil.Values{}
configMaps := make(map[string]*corev1.ConfigMap)
secrets := make(map[string]*corev1.Secret)
for _, v := range hr.Spec.ValuesFrom {
namespacedName := types.NamespacedName{Namespace: hr.Namespace, Name: v.Name}
var valuesData []byte
switch v.Kind {
case "ConfigMap":
resource, ok := configMaps[namespacedName.String()]
if !ok {
// The resource may not exist, but we want to act on a single version
// of the resource in case the values reference is marked as optional.
configMaps[namespacedName.String()] = nil
resource = &corev1.ConfigMap{}
if err := r.Get(ctx, namespacedName, resource); err != nil {
if apierrors.IsNotFound(err) {
if v.Optional {
(logr.FromContext(ctx)).
Info(fmt.Sprintf("could not find optional %s '%s'", v.Kind, namespacedName))
continue
}
return nil, fmt.Errorf("could not find %s '%s'", v.Kind, namespacedName)
}
return nil, err
}
configMaps[namespacedName.String()] = resource
}
if resource == nil {
if v.Optional {
(logr.FromContext(ctx)).Info(fmt.Sprintf("could not find optional %s '%s'", v.Kind, namespacedName))
continue
}
return nil, fmt.Errorf("could not find %s '%s'", v.Kind, namespacedName)
}
if data, ok := resource.Data[v.GetValuesKey()]; !ok {
return nil, fmt.Errorf("missing key '%s' in %s '%s'", v.GetValuesKey(), v.Kind, namespacedName)
} else {
valuesData = []byte(data)
}
case "Secret":
resource, ok := secrets[namespacedName.String()]
if !ok {
// The resource may not exist, but we want to act on a single version
// of the resource in case the values reference is marked as optional.
secrets[namespacedName.String()] = nil
resource = &corev1.Secret{}
if err := r.Get(ctx, namespacedName, resource); err != nil {
if apierrors.IsNotFound(err) {
if v.Optional {
(logr.FromContext(ctx)).
Info(fmt.Sprintf("could not find optional %s '%s'", v.Kind, namespacedName))
continue
}
return nil, fmt.Errorf("could not find %s '%s'", v.Kind, namespacedName)
}
return nil, err
}
secrets[namespacedName.String()] = resource
}
if resource == nil {
if v.Optional {
(logr.FromContext(ctx)).Info(fmt.Sprintf("could not find optional %s '%s'", v.Kind, namespacedName))
continue
}
return nil, fmt.Errorf("could not find %s '%s'", v.Kind, namespacedName)
}
if data, ok := resource.Data[v.GetValuesKey()]; !ok {
return nil, fmt.Errorf("missing key '%s' in %s '%s'", v.GetValuesKey(), v.Kind, namespacedName)
} else {
valuesData = data
}
default:
return nil, fmt.Errorf("unsupported ValuesReference kind '%s'", v.Kind)
}
switch v.TargetPath {
case "":
values, err := chartutil.ReadValues(valuesData)
if err != nil {
return nil, fmt.Errorf("unable to read values from key '%s' in %s '%s': %w", v.GetValuesKey(), v.Kind, namespacedName, err)
}
result = transform.MergeMaps(result, values)
default:
// TODO(hidde): this is a bit of hack, as it mimics the way the option string is passed
// to Helm from a CLI perspective. Given the parser is however not publicly accessible
// while it contains all logic around parsing the target path, it is a fair trade-off.
stringValuesData := string(valuesData)
const singleQuote = "'"
const doubleQuote = "\""
var err error
if (strings.HasPrefix(stringValuesData, singleQuote) && strings.HasSuffix(stringValuesData, singleQuote)) || (strings.HasPrefix(stringValuesData, doubleQuote) && strings.HasSuffix(stringValuesData, doubleQuote)) {
stringValuesData = strings.Trim(stringValuesData, singleQuote+doubleQuote)
singleValue := v.TargetPath + "=" + stringValuesData
err = strvals.ParseIntoString(singleValue, result)
} else {
singleValue := v.TargetPath + "=" + stringValuesData
err = strvals.ParseInto(singleValue, result)
}
if err != nil {
return nil, fmt.Errorf("unable to merge value from key '%s' in %s '%s' into target path '%s': %w", v.GetValuesKey(), v.Kind, namespacedName, v.TargetPath, err)
}
}
}
return transform.MergeMaps(result, hr.GetValues()), nil
}
// reconcileDelete deletes the v1beta1.HelmChart of the v2beta1.HelmRelease,
// and uninstalls the Helm release if the resource has not been suspended.
func (r *HelmReleaseReconciler) reconcileDelete(ctx context.Context, hr v2.HelmRelease) (ctrl.Result, error) {
r.recordReadiness(ctx, hr)
// Delete the HelmChart that belongs to this resource.
if err := r.deleteHelmChart(ctx, &hr); err != nil {
return ctrl.Result{}, err
}
// Only uninstall the Helm Release if the resource is not suspended.
if !hr.Spec.Suspend {
getter, err := r.getRESTClientGetter(ctx, hr)
if err != nil {
return ctrl.Result{}, err
}
run, err := runner.NewRunner(getter, hr.GetStorageNamespace(), logr.FromContext(ctx))
if err != nil {
return ctrl.Result{}, err
}
if err := run.Uninstall(hr); err != nil && !errors.Is(err, driver.ErrReleaseNotFound) {
return ctrl.Result{}, err
}
logr.FromContext(ctx).Info("uninstalled Helm release for deleted resource")
} else {
logr.FromContext(ctx).Info("skipping Helm uninstall for suspended resource")
}
// Remove our finalizer from the list and update it.
controllerutil.RemoveFinalizer(&hr, v2.HelmReleaseFinalizer)
if err := r.Update(ctx, &hr); err != nil {
return ctrl.Result{}, err
}
return ctrl.Result{}, nil
}
func (r *HelmReleaseReconciler) handleHelmActionResult(ctx context.Context,
hr *v2.HelmRelease, revision string, err error, action string, condition string, succeededReason string, failedReason string) error {
if err != nil {
err = fmt.Errorf("Helm %s failed: %w", action, err)
msg := err.Error()
if actionErr := (*runner.ActionError)(nil); errors.As(err, &actionErr) {
msg = msg + "\n\nLast Helm logs:\n\n" + actionErr.CapturedLogs
}
meta.SetResourceCondition(hr, condition, metav1.ConditionFalse, failedReason, msg)
r.event(ctx, *hr, revision, events.EventSeverityError, msg)
return &ConditionError{Reason: failedReason, Err: err}
} else {
msg := fmt.Sprintf("Helm %s succeeded", action)
meta.SetResourceCondition(hr, condition, metav1.ConditionTrue, succeededReason, msg)
r.event(ctx, *hr, revision, events.EventSeverityInfo, msg)
return nil
}
}
func (r *HelmReleaseReconciler) patchStatus(ctx context.Context, hr *v2.HelmRelease) error {
key := client.ObjectKeyFromObject(hr)
latest := &v2.HelmRelease{}
if err := r.Client.Get(ctx, key, latest); err != nil {
return err
}
return r.Client.Status().Patch(ctx, hr, client.MergeFrom(latest))
}
func (r *HelmReleaseReconciler) requestsForHelmChartChange(o client.Object) []reconcile.Request {
hc, ok := o.(*sourcev1.HelmChart)
if !ok {
panic(fmt.Sprintf("Expected a HelmChart, got %T", o))
}
// If we do not have an artifact, we have no requests to make
if hc.GetArtifact() == nil {
return nil
}
ctx := context.Background()
var list v2.HelmReleaseList
if err := r.List(ctx, &list, client.MatchingFields{
v2.SourceIndexKey: client.ObjectKeyFromObject(hc).String(),
}); err != nil {
return nil
}
var reqs []reconcile.Request
for _, i := range list.Items {
// If the revision of the artifact equals to the last attempted revision,
// we should not make a request for this HelmRelease
if hc.GetArtifact().Revision == i.Status.LastAttemptedRevision {
continue
}
reqs = append(reqs, reconcile.Request{NamespacedName: client.ObjectKeyFromObject(&i)})
}
return reqs
}
// event emits a Kubernetes event and forwards the event to notification controller if configured.
func (r *HelmReleaseReconciler) event(ctx context.Context, hr v2.HelmRelease, revision, severity, msg string) {
r.EventRecorder.Event(&hr, "Normal", severity, msg)
objRef, err := reference.GetReference(r.Scheme, &hr)
if err != nil {
logr.FromContext(ctx).Error(err, "unable to send event")
return
}
if r.ExternalEventRecorder != nil {
var meta map[string]string
if revision != "" {
meta = map[string]string{"revision": revision}
}
if err := r.ExternalEventRecorder.Eventf(*objRef, meta, severity, severity, msg); err != nil {
logr.FromContext(ctx).Error(err, "unable to send event")
return
}
}
}
func (r *HelmReleaseReconciler) recordSuspension(ctx context.Context, hr v2.HelmRelease) {
if r.MetricsRecorder == nil {
return
}
log := logr.FromContext(ctx)
objRef, err := reference.GetReference(r.Scheme, &hr)
if err != nil {
log.Error(err, "unable to record suspended metric")
return
}
if !hr.DeletionTimestamp.IsZero() {
r.MetricsRecorder.RecordSuspend(*objRef, false)
} else {
r.MetricsRecorder.RecordSuspend(*objRef, hr.Spec.Suspend)
}
}
func (r *HelmReleaseReconciler) recordReadiness(ctx context.Context, hr v2.HelmRelease) {
if r.MetricsRecorder == nil {
return
}
objRef, err := reference.GetReference(r.Scheme, &hr)
if err != nil {
logr.FromContext(ctx).Error(err, "unable to record readiness metric")
return
}
if rc := apimeta.FindStatusCondition(hr.Status.Conditions, meta.ReadyCondition); rc != nil {
r.MetricsRecorder.RecordCondition(*objRef, *rc, !hr.DeletionTimestamp.IsZero())
} else {
r.MetricsRecorder.RecordCondition(*objRef, metav1.Condition{
Type: meta.ReadyCondition,
Status: metav1.ConditionUnknown,
}, !hr.DeletionTimestamp.IsZero())
}
}

View File

@ -0,0 +1,212 @@
/*
Copyright 2020 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"
"io"
"io/ioutil"
"net/http"
"net/url"
"os"
"reflect"
"strings"
"github.com/go-logr/logr"
"github.com/hashicorp/go-retryablehttp"
"helm.sh/helm/v3/pkg/chart"
"helm.sh/helm/v3/pkg/chart/loader"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
v2 "github.com/fluxcd/helm-controller/api/v2beta1"
)
func (r *HelmReleaseReconciler) reconcileChart(ctx context.Context, hr *v2.HelmRelease) (*sourcev1.HelmChart, error) {
chartName := types.NamespacedName{
Namespace: hr.Spec.Chart.GetNamespace(hr.Namespace),
Name: hr.GetHelmChartName(),
}
// Garbage collect the previous HelmChart if the namespace named changed.
if hr.Status.HelmChart != "" && hr.Status.HelmChart != chartName.String() {
if err := r.deleteHelmChart(ctx, hr); err != nil {
return nil, err
}
}
// Continue with the reconciliation of the current template.
var helmChart sourcev1.HelmChart
err := r.Client.Get(ctx, chartName, &helmChart)
if err != nil && !apierrors.IsNotFound(err) {
return nil, err
}
hc := buildHelmChartFromTemplate(hr)
switch {
case apierrors.IsNotFound(err):
if err = r.Client.Create(ctx, hc); err != nil {
return nil, err
}
hr.Status.HelmChart = chartName.String()
return hc, nil
case helmChartRequiresUpdate(hr, &helmChart):
logr.FromContext(ctx).Info("chart diverged from template", strings.ToLower(sourcev1.HelmChartKind), chartName.String())
helmChart.Spec = hc.Spec
if err = r.Client.Update(ctx, &helmChart); err != nil {
return nil, err
}
hr.Status.HelmChart = chartName.String()
}
return &helmChart, nil
}
// getHelmChart retrieves the v1beta1.HelmChart for the given
// v2beta1.HelmRelease using the name that is advertised in the status
// object. It returns the v1beta1.HelmChart, or an error.
func (r *HelmReleaseReconciler) getHelmChart(ctx context.Context, hr *v2.HelmRelease) (*sourcev1.HelmChart, error) {
namespace, name := hr.Status.GetHelmChart()
hc := &sourcev1.HelmChart{}
if err := r.Client.Get(ctx, types.NamespacedName{Namespace: namespace, Name: name}, hc); err != nil {
return nil, err
}
return hc, nil
}
// loadHelmChart attempts to download the artifact from the provided source,
// loads it into a chart.Chart, and removes the downloaded artifact.
// It returns the loaded chart.Chart on success, or an error.
func (r *HelmReleaseReconciler) loadHelmChart(source *sourcev1.HelmChart) (*chart.Chart, error) {
f, err := ioutil.TempFile("", fmt.Sprintf("%s-%s-*.tgz", source.GetNamespace(), source.GetName()))
if err != nil {
return nil, err
}
defer f.Close()
defer os.Remove(f.Name())
artifactURL := source.GetArtifact().URL
if hostname := os.Getenv("SOURCE_CONTROLLER_LOCALHOST"); hostname != "" {
u, err := url.Parse(artifactURL)
if err != nil {
return nil, err
}
u.Host = hostname
artifactURL = u.String()
}
req, err := retryablehttp.NewRequest(http.MethodGet, artifactURL, nil)
if err != nil {
return nil, fmt.Errorf("failed to create a new request: %w", err)
}
resp, err := r.httpClient.Do(req)
if err != nil {
return nil, fmt.Errorf("failed to download artifact, error: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("artifact '%s' download failed (status code: %s)", source.GetArtifact().URL, resp.Status)
}
if _, err = io.Copy(f, resp.Body); err != nil {
return nil, err
}
return loader.Load(f.Name())
}
// deleteHelmChart deletes the v1beta1.HelmChart of the v2beta1.HelmRelease.
func (r *HelmReleaseReconciler) deleteHelmChart(ctx context.Context, hr *v2.HelmRelease) error {
if hr.Status.HelmChart == "" {
return nil
}
var hc sourcev1.HelmChart
chartNS, chartName := hr.Status.GetHelmChart()
err := r.Client.Get(ctx, types.NamespacedName{Namespace: chartNS, Name: chartName}, &hc)
if err != nil {
if apierrors.IsNotFound(err) {
hr.Status.HelmChart = ""
return nil
}
err = fmt.Errorf("failed to delete HelmChart '%s': %w", hr.Status.HelmChart, err)
return err
}
if err = r.Client.Delete(ctx, &hc); err != nil {
err = fmt.Errorf("failed to delete HelmChart '%s': %w", hr.Status.HelmChart, err)
return err
}
// Truncate the chart reference in the status object.
hr.Status.HelmChart = ""
return nil
}
// buildHelmChartFromTemplate builds a v1beta1.HelmChart from the
// v2beta1.HelmChartTemplate of the given v2beta1.HelmRelease.
func buildHelmChartFromTemplate(hr *v2.HelmRelease) *sourcev1.HelmChart {
template := hr.Spec.Chart
return &sourcev1.HelmChart{
ObjectMeta: metav1.ObjectMeta{
Name: hr.GetHelmChartName(),
Namespace: hr.Spec.Chart.GetNamespace(hr.Namespace),
},
Spec: sourcev1.HelmChartSpec{
Chart: template.Spec.Chart,
Version: template.Spec.Version,
SourceRef: sourcev1.LocalHelmChartSourceReference{
Name: template.Spec.SourceRef.Name,
Kind: template.Spec.SourceRef.Kind,
},
Interval: template.GetInterval(hr.Spec.Interval),
ReconcileStrategy: template.Spec.ReconcileStrategy,
ValuesFiles: template.Spec.ValuesFiles,
ValuesFile: template.Spec.ValuesFile,
},
}
}
// helmChartRequiresUpdate compares the v2beta1.HelmChartTemplate of the
// v2beta1.HelmRelease to the given v1beta1.HelmChart to determine if an
// update is required.
func helmChartRequiresUpdate(hr *v2.HelmRelease, chart *sourcev1.HelmChart) bool {
template := hr.Spec.Chart
switch {
case template.Spec.Chart != chart.Spec.Chart:
return true
// TODO(hidde): remove emptiness checks on next MINOR version
case template.Spec.Version == "" && chart.Spec.Version != "*",
template.Spec.Version != "" && template.Spec.Version != chart.Spec.Version:
return true
case template.Spec.SourceRef.Name != chart.Spec.SourceRef.Name:
return true
case template.Spec.SourceRef.Kind != chart.Spec.SourceRef.Kind:
return true
case template.GetInterval(hr.Spec.Interval) != chart.Spec.Interval:
return true
case template.Spec.ReconcileStrategy != chart.Spec.ReconcileStrategy:
return true
case !reflect.DeepEqual(template.Spec.ValuesFiles, chart.Spec.ValuesFiles):
return true
case template.Spec.ValuesFile != chart.Spec.ValuesFile:
return true
default:
return false
}
}

View File

@ -0,0 +1,457 @@
/*
Copyright 2020 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"
"testing"
"time"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
"github.com/go-logr/logr"
. "github.com/onsi/gomega"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes/scheme"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/fake"
"sigs.k8s.io/controller-runtime/pkg/log"
v2 "github.com/fluxcd/helm-controller/api/v2beta1"
)
func TestHelmReleaseReconciler_reconcileChart(t *testing.T) {
tests := []struct {
name string
hr *v2.HelmRelease
hc *sourcev1.HelmChart
expectHelmChartStatus string
expectGC bool
expectErr bool
}{
{
name: "new HelmChart",
hr: &v2.HelmRelease{
ObjectMeta: metav1.ObjectMeta{
Name: "test-release",
Namespace: "default",
},
Spec: v2.HelmReleaseSpec{
Interval: metav1.Duration{Duration: time.Minute},
Chart: v2.HelmChartTemplate{
Spec: v2.HelmChartTemplateSpec{
Chart: "chart",
SourceRef: v2.CrossNamespaceObjectReference{
Name: "test-repository",
Kind: "HelmRepository",
},
},
},
},
},
hc: nil,
expectHelmChartStatus: "default/default-test-release",
},
{
name: "existing HelmChart",
hr: &v2.HelmRelease{
ObjectMeta: metav1.ObjectMeta{
Name: "test-release",
Namespace: "default",
},
Spec: v2.HelmReleaseSpec{
Interval: metav1.Duration{Duration: time.Minute},
Chart: v2.HelmChartTemplate{
Spec: v2.HelmChartTemplateSpec{
Chart: "chart",
SourceRef: v2.CrossNamespaceObjectReference{
Name: "test-repository",
Kind: "HelmRepository",
},
},
},
},
},
hc: &sourcev1.HelmChart{
ObjectMeta: metav1.ObjectMeta{
Name: "default-test-release",
Namespace: "default",
},
Spec: sourcev1.HelmChartSpec{
Chart: "chart",
SourceRef: sourcev1.LocalHelmChartSourceReference{
Name: "test-repository",
Kind: "HelmRepository",
},
},
},
expectHelmChartStatus: "default/default-test-release",
},
{
name: "modified HelmChart",
hr: &v2.HelmRelease{
ObjectMeta: metav1.ObjectMeta{
Name: "test-release",
Namespace: "default",
},
Spec: v2.HelmReleaseSpec{
Interval: metav1.Duration{Duration: time.Minute},
Chart: v2.HelmChartTemplate{
Spec: v2.HelmChartTemplateSpec{
Chart: "chart",
SourceRef: v2.CrossNamespaceObjectReference{
Name: "test-repository",
Kind: "HelmRepository",
Namespace: "cross",
},
},
},
},
Status: v2.HelmReleaseStatus{
HelmChart: "default/default-test-release",
},
},
hc: &sourcev1.HelmChart{
ObjectMeta: metav1.ObjectMeta{
Name: "default-test-release",
Namespace: "default",
},
Spec: sourcev1.HelmChartSpec{
Chart: "chart",
SourceRef: sourcev1.LocalHelmChartSourceReference{
Name: "test-repository",
Kind: "HelmRepository",
},
},
},
expectHelmChartStatus: "cross/default-test-release",
expectGC: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
g := NewWithT(t)
g.Expect(v2.AddToScheme(scheme.Scheme)).To(Succeed())
g.Expect(sourcev1.AddToScheme(scheme.Scheme)).To(Succeed())
var c client.Client
if tt.hc != nil {
c = fake.NewFakeClientWithScheme(scheme.Scheme, tt.hc)
} else {
c = fake.NewFakeClientWithScheme(scheme.Scheme)
}
r := &HelmReleaseReconciler{
Client: c,
}
hc, err := r.reconcileChart(logr.NewContext(context.TODO(), log.NullLogger{}), tt.hr)
if tt.expectErr {
g.Expect(err).To(HaveOccurred())
g.Expect(hc).To(BeNil())
} else {
g.Expect(err).NotTo(HaveOccurred())
g.Expect(hc).NotTo(BeNil())
}
g.Expect(tt.hr.Status.HelmChart).To(Equal(tt.expectHelmChartStatus))
if tt.expectGC {
objKey := client.ObjectKeyFromObject(tt.hc)
err = c.Get(context.TODO(), objKey, tt.hc.DeepCopy())
g.Expect(apierrors.IsNotFound(err)).To(BeTrue())
}
})
}
}
func TestHelmReleaseReconciler_deleteHelmChart(t *testing.T) {
tests := []struct {
name string
hc *sourcev1.HelmChart
hr *v2.HelmRelease
expectHelmChartStatus string
expectErr bool
}{
{
name: "delete existing HelmChart",
hc: &sourcev1.HelmChart{
ObjectMeta: metav1.ObjectMeta{
Name: "test-chart",
Namespace: "default",
},
},
hr: &v2.HelmRelease{
ObjectMeta: metav1.ObjectMeta{
Name: "test-release",
},
Status: v2.HelmReleaseStatus{
HelmChart: "default/test-chart",
},
},
expectHelmChartStatus: "",
expectErr: false,
},
{
name: "delete already removed HelmChart",
hc: nil,
hr: &v2.HelmRelease{
ObjectMeta: metav1.ObjectMeta{
Name: "test-release",
},
Status: v2.HelmReleaseStatus{
HelmChart: "default/test-chart",
},
},
expectHelmChartStatus: "",
expectErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
g := NewWithT(t)
g.Expect(v2.AddToScheme(scheme.Scheme)).To(Succeed())
g.Expect(sourcev1.AddToScheme(scheme.Scheme)).To(Succeed())
var c client.Client
if tt.hc != nil {
c = fake.NewFakeClientWithScheme(scheme.Scheme, tt.hc)
} else {
c = fake.NewFakeClientWithScheme(scheme.Scheme)
}
r := &HelmReleaseReconciler{
Client: c,
}
err := r.deleteHelmChart(context.TODO(), tt.hr)
if tt.expectErr {
g.Expect(err).To(HaveOccurred())
} else {
g.Expect(err).NotTo(HaveOccurred())
}
g.Expect(tt.hr.Status.HelmChart).To(Equal(tt.expectHelmChartStatus))
})
}
}
func Test_buildHelmChartFromTemplate(t *testing.T) {
hrWithChartTemplate := v2.HelmRelease{
ObjectMeta: metav1.ObjectMeta{
Name: "test-release",
Namespace: "default",
},
Spec: v2.HelmReleaseSpec{
Interval: metav1.Duration{Duration: time.Minute},
Chart: v2.HelmChartTemplate{
Spec: v2.HelmChartTemplateSpec{
Chart: "chart",
Version: "1.0.0",
SourceRef: v2.CrossNamespaceObjectReference{
Name: "test-repository",
Kind: "HelmRepository",
},
Interval: &metav1.Duration{Duration: 2 * time.Minute},
ValuesFiles: []string{"values.yaml"},
},
},
},
}
tests := []struct {
name string
modify func(release *v2.HelmRelease)
want *sourcev1.HelmChart
}{
{
name: "builds HelmChart from HelmChartTemplate",
modify: func(*v2.HelmRelease) {},
want: &sourcev1.HelmChart{
ObjectMeta: metav1.ObjectMeta{
Name: "default-test-release",
Namespace: "default",
},
Spec: sourcev1.HelmChartSpec{
Chart: "chart",
Version: "1.0.0",
SourceRef: sourcev1.LocalHelmChartSourceReference{
Name: "test-repository",
Kind: "HelmRepository",
},
Interval: metav1.Duration{Duration: 2 * time.Minute},
ValuesFiles: []string{"values.yaml"},
},
},
},
{
name: "takes SourceRef namespace into account",
modify: func(hr *v2.HelmRelease) {
hr.Spec.Chart.Spec.SourceRef.Namespace = "cross"
},
want: &sourcev1.HelmChart{
ObjectMeta: metav1.ObjectMeta{
Name: "default-test-release",
Namespace: "cross",
},
Spec: sourcev1.HelmChartSpec{
Chart: "chart",
Version: "1.0.0",
SourceRef: sourcev1.LocalHelmChartSourceReference{
Name: "test-repository",
Kind: "HelmRepository",
},
Interval: metav1.Duration{Duration: 2 * time.Minute},
ValuesFiles: []string{"values.yaml"},
},
},
},
{
name: "falls back to HelmRelease interval",
modify: func(hr *v2.HelmRelease) {
hr.Spec.Chart.Spec.Interval = nil
},
want: &sourcev1.HelmChart{
ObjectMeta: metav1.ObjectMeta{
Name: "default-test-release",
Namespace: "default",
},
Spec: sourcev1.HelmChartSpec{
Chart: "chart",
Version: "1.0.0",
SourceRef: sourcev1.LocalHelmChartSourceReference{
Name: "test-repository",
Kind: "HelmRepository",
},
Interval: metav1.Duration{Duration: time.Minute},
ValuesFiles: []string{"values.yaml"},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
g := NewWithT(t)
hr := hrWithChartTemplate.DeepCopy()
tt.modify(hr)
g.Expect(buildHelmChartFromTemplate(hr)).To(Equal(tt.want))
})
}
}
func Test_helmChartRequiresUpdate(t *testing.T) {
hrWithChartTemplate := v2.HelmRelease{
ObjectMeta: metav1.ObjectMeta{
Name: "test-release",
},
Spec: v2.HelmReleaseSpec{
Interval: metav1.Duration{Duration: time.Minute},
Chart: v2.HelmChartTemplate{
Spec: v2.HelmChartTemplateSpec{
Chart: "chart",
Version: "1.0.0",
SourceRef: v2.CrossNamespaceObjectReference{
Name: "test-repository",
Kind: "HelmRepository",
},
Interval: &metav1.Duration{Duration: 2 * time.Minute},
},
},
},
}
tests := []struct {
name string
modify func(*v2.HelmRelease, *sourcev1.HelmChart)
want bool
}{
{
name: "detects no change",
modify: func(*v2.HelmRelease, *sourcev1.HelmChart) {},
want: false,
},
{
name: "detects chart change",
modify: func(hr *v2.HelmRelease, hc *sourcev1.HelmChart) {
hr.Spec.Chart.Spec.Chart = "new"
},
want: true,
},
{
name: "detects version change",
modify: func(hr *v2.HelmRelease, hc *sourcev1.HelmChart) {
hr.Spec.Chart.Spec.Version = "2.0.0"
},
want: true,
},
{
name: "detects chart source name change",
modify: func(hr *v2.HelmRelease, hc *sourcev1.HelmChart) {
hr.Spec.Chart.Spec.SourceRef.Name = "new"
},
want: true,
},
{
name: "detects chart source kind change",
modify: func(hr *v2.HelmRelease, hc *sourcev1.HelmChart) {
hr.Spec.Chart.Spec.SourceRef.Kind = "GitRepository"
},
want: true,
},
{
name: "detects interval change",
modify: func(hr *v2.HelmRelease, hc *sourcev1.HelmChart) {
hr.Spec.Chart.Spec.Interval = nil
},
want: true,
},
{
name: "detects reconcile strategy change",
modify: func(hr *v2.HelmRelease, hc *sourcev1.HelmChart) {
hr.Spec.Chart.Spec.ReconcileStrategy = "Revision"
},
want: true,
},
{
name: "detects values files change",
modify: func(hr *v2.HelmRelease, hc *sourcev1.HelmChart) {
hr.Spec.Chart.Spec.ValuesFiles = []string{"values-prod.yaml"}
},
want: true,
},
{
name: "detects values file change",
modify: func(hr *v2.HelmRelease, hc *sourcev1.HelmChart) {
hr.Spec.Chart.Spec.ValuesFile = "values-prod.yaml"
},
want: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
g := NewWithT(t)
hr := hrWithChartTemplate.DeepCopy()
hc := buildHelmChartFromTemplate(hr)
g.Expect(helmChartRequiresUpdate(hr, hc)).To(Equal(false))
tt.modify(hr, hc)
g.Expect(helmChartRequiresUpdate(hr, hc)).To(Equal(tt.want))
})
}
}

View File

@ -0,0 +1,294 @@
/*
Copyright 2020 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"
"reflect"
"testing"
"github.com/go-logr/logr"
"helm.sh/helm/v3/pkg/chartutil"
corev1 "k8s.io/api/core/v1"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/controller-runtime/pkg/client/fake"
"sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/yaml"
v2 "github.com/fluxcd/helm-controller/api/v2beta1"
)
func TestHelmReleaseReconciler_composeValues(t *testing.T) {
scheme := runtime.NewScheme()
_ = corev1.AddToScheme(scheme)
_ = v2.AddToScheme(scheme)
tests := []struct {
name string
resources []runtime.Object
references []v2.ValuesReference
values string
want chartutil.Values
wantErr bool
}{
{
name: "merges",
resources: []runtime.Object{
valuesConfigMap("values", map[string]string{
"values.yaml": `flat: value
nested:
configuration: value
`,
}),
valuesSecret("values", map[string][]byte{
"values.yaml": []byte(`flat:
nested: value
nested: value
`),
}),
},
references: []v2.ValuesReference{
{
Kind: "ConfigMap",
Name: "values",
},
{
Kind: "Secret",
Name: "values",
},
},
values: `
other: values
`,
want: chartutil.Values{
"flat": map[string]interface{}{
"nested": "value",
},
"nested": "value",
"other": "values",
},
},
{
name: "target path",
resources: []runtime.Object{
valuesSecret("values", map[string][]byte{"single": []byte("value")}),
},
references: []v2.ValuesReference{
{
Kind: "Secret",
Name: "values",
ValuesKey: "single",
TargetPath: "merge.at.specific.path",
},
},
want: chartutil.Values{
"merge": map[string]interface{}{
"at": map[string]interface{}{
"specific": map[string]interface{}{
"path": "value",
},
},
},
},
},
{
name: "target path with boolean value",
resources: []runtime.Object{
valuesSecret("values", map[string][]byte{"single": []byte("true")}),
},
references: []v2.ValuesReference{
{
Kind: "Secret",
Name: "values",
ValuesKey: "single",
TargetPath: "merge.at.specific.path",
},
},
want: chartutil.Values{
"merge": map[string]interface{}{
"at": map[string]interface{}{
"specific": map[string]interface{}{
"path": true,
},
},
},
},
},
{
name: "target path with set-string behavior",
resources: []runtime.Object{
valuesSecret("values", map[string][]byte{"single": []byte("\"true\"")}),
},
references: []v2.ValuesReference{
{
Kind: "Secret",
Name: "values",
ValuesKey: "single",
TargetPath: "merge.at.specific.path",
},
},
want: chartutil.Values{
"merge": map[string]interface{}{
"at": map[string]interface{}{
"specific": map[string]interface{}{
"path": "true",
},
},
},
},
},
{
name: "values reference to non existing secret",
references: []v2.ValuesReference{
{
Kind: "Secret",
Name: "missing",
},
},
wantErr: true,
},
{
name: "optional values reference to non existing secret",
references: []v2.ValuesReference{
{
Kind: "Secret",
Name: "missing",
Optional: true,
},
},
want: chartutil.Values{},
wantErr: false,
},
{
name: "values reference to non existing config map",
references: []v2.ValuesReference{
{
Kind: "ConfigMap",
Name: "missing",
},
},
wantErr: true,
},
{
name: "optional values reference to non existing config map",
references: []v2.ValuesReference{
{
Kind: "ConfigMap",
Name: "missing",
Optional: true,
},
},
want: chartutil.Values{},
wantErr: false,
},
{
name: "missing secret key",
resources: []runtime.Object{
valuesSecret("values", nil),
},
references: []v2.ValuesReference{
{
Kind: "Secret",
Name: "values",
ValuesKey: "nonexisting",
},
},
wantErr: true,
},
{
name: "missing config map key",
resources: []runtime.Object{
valuesConfigMap("values", nil),
},
references: []v2.ValuesReference{
{
Kind: "ConfigMap",
Name: "values",
ValuesKey: "nonexisting",
},
},
wantErr: true,
},
{
name: "unsupported values reference kind",
references: []v2.ValuesReference{
{
Kind: "Unsupported",
},
},
wantErr: true,
},
{
name: "invalid values",
resources: []runtime.Object{
valuesConfigMap("values", map[string]string{
"values.yaml": `
invalid`,
}),
},
references: []v2.ValuesReference{
{
Kind: "ConfigMap",
Name: "values",
},
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
c := fake.NewFakeClientWithScheme(scheme, tt.resources...)
r := &HelmReleaseReconciler{Client: c}
var values *apiextensionsv1.JSON
if tt.values != "" {
v, _ := yaml.YAMLToJSON([]byte(tt.values))
values = &apiextensionsv1.JSON{Raw: v}
}
hr := v2.HelmRelease{
Spec: v2.HelmReleaseSpec{
ValuesFrom: tt.references,
Values: values,
},
}
got, err := r.composeValues(logr.NewContext(context.TODO(), log.NullLogger{}), hr)
if (err != nil) != tt.wantErr {
t.Errorf("composeValues() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("composeValues() got = %v, want %v", got, tt.want)
}
})
}
}
func valuesSecret(name string, data map[string][]byte) *corev1.Secret {
return &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{Name: name},
Data: data,
}
}
func valuesConfigMap(name string, data map[string]string) *corev1.ConfigMap {
return &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{Name: name},
Data: data,
}
}

View File

@ -14,18 +14,15 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package predicates
package controllers
import (
"github.com/fluxcd/pkg/runtime/conditions"
"sigs.k8s.io/controller-runtime/pkg/event"
"sigs.k8s.io/controller-runtime/pkg/predicate"
sourcev1 "github.com/fluxcd/source-controller/api/v1"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
)
// SourceRevisionChangePredicate detects revision changes to the v1.Artifact of
// a v1.Source object.
type SourceRevisionChangePredicate struct {
predicate.Funcs
}
@ -50,21 +47,7 @@ func (SourceRevisionChangePredicate) Update(e event.UpdateEvent) bool {
}
if oldSource.GetArtifact() != nil && newSource.GetArtifact() != nil &&
!oldSource.GetArtifact().HasRevision(newSource.GetArtifact().Revision) {
return true
}
oldConditions, ok := e.ObjectOld.(conditions.Getter)
if !ok {
return false
}
newConditions, ok := e.ObjectNew.(conditions.Getter)
if !ok {
return false
}
if !conditions.IsReady(oldConditions) && conditions.IsReady(newConditions) {
oldSource.GetArtifact().Revision != newSource.GetArtifact().Revision {
return true
}

83
controllers/suite_test.go Normal file
View File

@ -0,0 +1,83 @@
/*
Copyright 2020 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 (
"path/filepath"
"testing"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/envtest"
"sigs.k8s.io/controller-runtime/pkg/envtest/printer"
logf "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
"github.com/fluxcd/helm-controller/api/v2beta1"
// +kubebuilder:scaffold:imports
)
// These tests use Ginkgo (BDD-style Go testing framework). Refer to
// http://onsi.github.io/ginkgo/ to learn more about Ginkgo.
var cfg *rest.Config
var k8sClient client.Client
var testEnv *envtest.Environment
func TestAPIs(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecsWithDefaultAndCustomReporters(t,
"Controller Suite",
[]Reporter{printer.NewlineReporter{}})
}
var _ = BeforeSuite(func(done Done) {
logf.SetLogger(
zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)),
)
By("bootstrapping test environment")
testEnv = &envtest.Environment{
CRDDirectoryPaths: []string{filepath.Join("..", "config", "crd", "bases")},
}
var err error
cfg, err = testEnv.Start()
Expect(err).ToNot(HaveOccurred())
Expect(cfg).ToNot(BeNil())
err = v2beta1.AddToScheme(scheme.Scheme)
Expect(err).NotTo(HaveOccurred())
// +kubebuilder:scaffold:scheme
k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme})
Expect(err).ToNot(HaveOccurred())
Expect(k8sClient).ToNot(BeNil())
close(done)
}, 60)
var _ = AfterSuite(func() {
By("tearing down the test environment")
err := testEnv.Stop()
Expect(err).ToNot(HaveOccurred())
})

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