Compare commits

..

No commits in common. "main" and "api/v0.33.0" have entirely different histories.

194 changed files with 7815 additions and 14058 deletions

View File

@ -1,34 +0,0 @@
version: 2
updates:
- package-ecosystem: "gomod"
directory: "/"
labels: ["dependencies"]
schedule:
interval: "monthly"
groups:
go-deps:
patterns:
- "*"
allow:
- dependency-type: "direct"
ignore:
# Kubernetes deps are updated by fluxcd/pkg
- dependency-name: "k8s.io/*"
- dependency-name: "sigs.k8s.io/*"
# KMS SDKs are updated by SOPS
- dependency-name: "github.com/Azure/*"
- dependency-name: "github.com/aws/*"
- dependency-name: "github.com/hashicorp/vault/*"
# Flux APIs pkg are updated at release time
- dependency-name: "github.com/fluxcd/kustomize-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"

40
.github/labels.yaml vendored
View File

@ -1,40 +0,0 @@
# Configuration file to declaratively configure labels
# Ref: https://github.com/EndBug/label-sync#Config-files
- name: area/kustomize
description: Kustomize related issues and pull requests
color: '#00e54d'
- name: area/kstatus
description: Health checking related issues and pull requests
color: '#25D5CA'
aliases: ['area/health-checks']
- name: area/sops
description: SOPS related issues and pull requests
color: '#FEE5D1'
- name: area/server-side-apply
description: SSA related issues and pull requests
color: '#2819CB'
- name: area/varsub
description: Post-build variable substitution related issues and pull requests
color: '#8D195D'
- name: backport:release/v1.0.x
description: To be backported to release/v1.0.x
color: '#ffd700'
- name: backport:release/v1.1.x
description: To be backported to release/v1.1.x
color: '#ffd700'
- name: backport:release/v1.2.x
description: To be backported to release/v1.2.x
color: '#ffd700'
- name: backport:release/v1.3.x
description: To be backported to release/v1.3.x
color: '#ffd700'
- name: backport:release/v1.4.x
description: To be backported to release/v1.4.x
color: '#ffd700'
- name: backport:release/v1.5.x
description: To be backported to release/v1.5.x
color: '#ffd700'
- name: backport:release/v1.6.x
description: To be backported to release/v1.6.x
color: '#ffd700'

View File

@ -1,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@436145e922f9561fc5ea157ff406f21af2d6b363 # v3.2.0
# xref: https://github.com/korthout/backport-action#inputs
with:
# Use token to allow workflows to be triggered for the created PR
github_token: ${{ secrets.BOT_GITHUB_TOKEN }}
# Match labels with a pattern `backport:<target-branch>`
label_pattern: '^backport:([^ ]+)$'
# A bit shorter pull-request title than the default
pull_title: '[${target_branch}] ${pull_title}'
# Simpler PR description than default
pull_description: |-
Automated backport to `${target_branch}`, triggered by a label in #${pull_number}.

View File

@ -12,13 +12,20 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@v3
- name: Setup Go
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
uses: actions/setup-go@v3
with:
go-version: 1.24.x
cache-dependency-path: |
**/go.sum
**/go.mod
go-version: 1.19.x
- id: go-env
run: |
echo "::set-output name=go-mod-cache::$(go env GOMODCACHE)"
- name: Restore Go cache
uses: actions/cache@v3
with:
path: ${{ steps.go-env.outputs.go-mod-cache }}
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go
- name: Smoke test Fuzzers
run: make fuzz-smoketest

View File

@ -4,8 +4,7 @@ on:
pull_request:
push:
branches:
- 'main'
- 'release/**'
- main
permissions:
contents: read # for actions/checkout to fetch code
@ -15,14 +14,21 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@v3
- name: Setup QEMU
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0
uses: docker/setup-qemu-action@v2
- name: Setup Docker Buildx
id: buildx
uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0
uses: docker/setup-buildx-action@v2
- name: Restore Go cache
uses: actions/cache@v3
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: Cache Docker layers
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
uses: actions/cache@v3
id: cache
with:
path: /tmp/.buildx-cache
@ -30,20 +36,16 @@ jobs:
restore-keys: |
${{ runner.os }}-buildx-ghcache-
- name: Setup Go
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
uses: actions/setup-go@v3
with:
go-version: 1.24.x
cache-dependency-path: |
**/go.sum
**/go.mod
go-version: 1.19.x
- name: Setup Kubernetes
uses: helm/kind-action@a1b0e391336a6ee6713a0583f8c6240d70863de3 # v1.12.0
uses: helm/kind-action@v1.5.0
with:
version: v0.20.0
version: v0.17.0
cluster_name: kind
node_image: kindest/node:v1.27.3@sha256:3966ac761ae0136263ffdb6cfd4db23ef8a83cba8a463690e98317add2c9ba72
- name: Setup Kustomize
uses: fluxcd/pkg/actions/kustomize@main
uses: fluxcd/pkg//actions/kustomize@main
- name: Enable integration tests
# Only run integration tests for main branch
if: github.ref == 'refs/heads/main'
@ -101,7 +103,7 @@ jobs:
- name: Run tests for removing kubectl managed fields
run: |
kubectl create ns managed-fields
kustomize build github.com/stefanprodan/podinfo//kustomize?ref=6.3.5 > /tmp/podinfo.yaml
kustomize build github.com/stefanprodan/podinfo//kustomize?ref=6.0.0 > /tmp/podinfo.yaml
kubectl -n managed-fields apply -f /tmp/podinfo.yaml
kubectl -n managed-fields apply -f ./config/testdata/managed-fields
kubectl -n managed-fields wait kustomization/podinfo --for=condition=ready --timeout=4m

View File

@ -9,22 +9,23 @@ env:
permissions:
contents: read # for actions/checkout to fetch code
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@v3
- 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@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0
uses: docker/setup-buildx-action@v2
with:
buildkitd-flags: "--debug"
- name: Build multi-arch container image
uses: docker/build-push-action@1dc73863535b631f98b2378be8619f83b136f4a0 # v6.17.0
uses: docker/build-push-action@v3
with:
push: false
builder: ${{ steps.buildx.outputs.name }}

View File

@ -11,25 +11,18 @@ on:
required: true
permissions:
contents: read
contents: write # needed to write releases
id-token: write # needed for keyless signing
packages: write # needed for ghcr access
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@v3
- name: Setup Kustomize
uses: fluxcd/pkg/actions/kustomize@main
- name: Prepare
@ -42,24 +35,24 @@ jobs:
echo "BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_OUTPUT
echo "VERSION=${VERSION}" >> $GITHUB_OUTPUT
- name: Setup QEMU
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0
uses: docker/setup-qemu-action@v2
- name: Setup Docker Buildx
id: buildx
uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0
uses: docker/setup-buildx-action@v2
- name: Login to GitHub Container Registry
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
uses: docker/login-action@v2
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@v2
with:
username: fluxcdbot
password: ${{ secrets.DOCKER_FLUXCD_PASSWORD }}
- name: Generate images meta
id: meta
uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0
uses: docker/metadata-action@v4
with:
images: |
fluxcd/${{ env.CONTROLLER }}
@ -67,8 +60,7 @@ jobs:
tags: |
type=raw,value=${{ steps.prep.outputs.VERSION }}
- name: Publish images
id: build-push
uses: docker/build-push-action@1dc73863535b631f98b2378be8619f83b136f4a0 # v6.17.0
uses: docker/build-push-action@v3
with:
sbom: true
provenance: true
@ -79,82 +71,32 @@ jobs:
platforms: linux/amd64,linux/arm/v7,linux/arm64
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
- uses: sigstore/cosign-installer@3454372f43399081ed03b604cb2d021dabca52bb # v3.8.2
- name: Check images
run: |
docker buildx imagetools inspect docker.io/fluxcd/${{ env.CONTROLLER }}:${{ steps.prep.outputs.VERSION }}
docker buildx imagetools inspect ghcr.io/fluxcd/${{ env.CONTROLLER }}:${{ steps.prep.outputs.VERSION }}
docker pull docker.io/fluxcd/${{ env.CONTROLLER }}:${{ steps.prep.outputs.VERSION }}
docker pull ghcr.io/fluxcd/${{ env.CONTROLLER }}:${{ steps.prep.outputs.VERSION }}
- uses: sigstore/cosign-installer@main
- name: Sign images
env:
COSIGN_EXPERIMENTAL: 1
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 }}
cosign sign fluxcd/${{ env.CONTROLLER }}:${{ steps.prep.outputs.VERSION }}
cosign sign ghcr.io/fluxcd/${{ env.CONTROLLER }}:${{ steps.prep.outputs.VERSION }}
- name: Generate release artifacts
if: startsWith(github.ref, 'refs/tags/v')
run: |
mkdir -p config/release
kustomize build ./config/crd > ./config/release/${{ env.CONTROLLER }}.crds.yaml
kustomize build ./config/manager > ./config/release/${{ env.CONTROLLER }}.deployment.yaml
- uses: anchore/sbom-action/download-syft@e11c554f704a0b820cbf8c51673f6945e0731532 # v0.20.0
echo '[CHANGELOG](https://github.com/fluxcd/${{ env.CONTROLLER }}/blob/main/CHANGELOG.md)' > ./config/release/notes.md
- uses: anchore/sbom-action/download-syft@v0
- name: Create release and SBOM
id: run-goreleaser
if: startsWith(github.ref, 'refs/tags/v')
uses: goreleaser/goreleaser-action@9c156ee8a17a598857849441385a2041ef570552 # v6.3.0
uses: goreleaser/goreleaser-action@v3
with:
version: latest
args: release --clean --skip=validate
args: release --release-notes=config/release/notes.md --rm-dist --skip-validate
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Generate SLSA metadata
id: slsa
env:
ARTIFACTS: "${{ steps.run-goreleaser.outputs.artifacts }}"
run: |
hashes=$(echo $ARTIFACTS | jq --raw-output '.[] | {name, "digest": (.extra.Digest // .extra.Checksum)} | select(.digest) | {digest} + {name} | join(" ") | sub("^sha256:";"")' | base64 -w0)
echo "hashes=$hashes" >> $GITHUB_OUTPUT
image_url=fluxcd/${{ env.CONTROLLER }}:${{ steps.prep.outputs.version }}
echo "image_url=$image_url" >> $GITHUB_OUTPUT
image_digest=${{ steps.build-push.outputs.digest }}
echo "image_digest=$image_digest" >> $GITHUB_OUTPUT
release-provenance:
needs: [release]
permissions:
actions: read # for detecting the Github Actions environment.
id-token: write # for creating OIDC tokens for signing.
contents: write # for uploading attestations to GitHub releases.
if: startsWith(github.ref, 'refs/tags/v')
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.1.0
with:
provenance-name: "provenance.intoto.jsonl"
base64-subjects: "${{ needs.release.outputs.hashes }}"
upload-assets: true
dockerhub-provenance:
needs: [release]
permissions:
actions: read # for detecting the Github Actions environment.
id-token: write # for creating OIDC tokens for signing.
packages: write # for uploading attestations.
if: startsWith(github.ref, 'refs/tags/v')
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v2.1.0
with:
image: ${{ needs.release.outputs.image_url }}
digest: ${{ needs.release.outputs.image_digest }}
registry-username: fluxcdbot
secrets:
registry-password: ${{ secrets.DOCKER_FLUXCD_PASSWORD }}
ghcr-provenance:
needs: [release]
permissions:
actions: read # for detecting the Github Actions environment.
id-token: write # for creating OIDC tokens for signing.
packages: write # for uploading attestations.
if: startsWith(github.ref, 'refs/tags/v')
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v2.1.0
with:
image: ghcr.io/${{ needs.release.outputs.image_url }}
digest: ${{ needs.release.outputs.image_digest }}
registry-username: fluxcdbot
secrets:
registry-password: ${{ secrets.GHCR_TOKEN }}

View File

@ -11,16 +11,15 @@ on:
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@v3
- 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
@ -30,23 +29,17 @@ jobs:
name: CodeQL
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Checkout repository
uses: actions/checkout@v3
- name: Setup Go
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
uses: actions/setup-go@v3
with:
go-version: 1.24.x
cache-dependency-path: |
**/go.sum
**/go.mod
go-version: 1.19.x
- name: Initialize CodeQL
uses: github/codeql-action/init@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18
uses: github/codeql-action/init@v2
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@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18
uses: github/codeql-action/autobuild@v2
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18
uses: github/codeql-action/analyze@v2

View File

@ -1,28 +0,0 @@
name: sync-labels
on:
workflow_dispatch:
push:
branches:
- main
paths:
- .github/labels.yaml
permissions:
contents: read
jobs:
labels:
name: Run sync
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: EndBug/label-sync@52074158190acb45f3077f9099fea818aa43f97a # v2.3.3
with:
# Configuration file
config-file: |
https://raw.githubusercontent.com/fluxcd/community/main/.github/standard-labels.yaml
.github/labels.yaml
# Strictly declarative
delete-other-labels: true

14
.gitignore vendored
View File

@ -1,26 +1,22 @@
# Binaries for programs and plugins.
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
# Test binary, built with `go test -c`.
# Test binary, built with `go test -c`
*.test
# Output of the go coverage tool.
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# Build tools downloaded at runtime.
# Dependency directories (remove the comment below to include it)
# vendor/
bin/
# Release manifests generated at runtime.
config/release/
config/crd/bases/ocirepositories.yaml
config/crd/bases/gitrepositories.yaml
config/crd/bases/buckets.yaml
build/
# CRDs for fuzzing tests.
internal/controllers/testdata/crd

View File

@ -4,26 +4,9 @@ builds:
- skip: true
release:
prerelease: "true"
extra_files:
- glob: config/release/*.yaml
prerelease: "auto"
header: |
## Changelog
[{{.Tag}} changelog](https://github.com/fluxcd/{{.ProjectName}}/blob/{{.Tag}}/CHANGELOG.md)
footer: |
## Container images
- `docker.io/fluxcd/{{.ProjectName}}:{{.Tag}}`
- `ghcr.io/fluxcd/{{.ProjectName}}:{{.Tag}}`
Supported architectures: `linux/amd64`, `linux/arm64` and `linux/arm/v7`.
The container images are built on GitHub hosted runners and are signed with cosign and GitHub OIDC.
To verify the images and their provenance (SLSA level 3), please see the [security documentation](https://fluxcd.io/flux/security/).
changelog:
disable: true
checksum:
extra_files:
@ -49,7 +32,6 @@ signs:
certificate: "${artifact}.pem"
args:
- sign-blob
- "--yes"
- "--output-certificate=${certificate}"
- "--output-signature=${signature}"
- "${artifact}"

View File

@ -2,664 +2,6 @@
All notable changes to this project are documented in this file.
## 1.6.1
**Release date:** 2025-07-08
This patch release fixes a bug introduced in v1.6.0
that causes SOPS decryption with US Government KMS
keys to fail with the error:
```
STS: AssumeRoleWithWebIdentity, https response error\n StatusCode: 0, RequestID: ,
request send failed, Post\n \"https://sts.arn.amazonaws.com/\": dial tcp:
lookupts.arn.amazonaws.com on 10.100.0.10:53: no such host
```
Fixes:
- Fix regression in STS endpoint for SOPS decryption with AWS KMS in US Gov partition
[#1478](https://github.com/fluxcd/kustomize-controller/pull/1478)
## 1.6.0
**Release date:** 2025-05-28
This minor release comes with various bug fixes and improvements.
Kustomization API now supports object-level workload identity by setting
`.spec.decryption.serviceAccountName` to the name of a service account
in the same namespace that has been configured with appropriate cloud
permissions. For this feature to work, the controller feature gate
`ObjectLevelWorkloadIdentity` must be enabled. See a complete guide
[here](https://fluxcd.io/flux/integrations/).
Kustomization API now supports the value `WaitForTermination` for the
`.spec.deletionPolicy` field. This instructs the controller to wait for the
deletion of all resources managed by the Kustomization before allowing the
Kustomization itself to be deleted. See docs
[here](https://fluxcd.io/flux/components/kustomize/kustomizations/#deletion-policy).
In addition, the Kubernetes dependencies have been updated to v1.33 and
various other controller dependencies have been updated to their latest version.
The controller is now built with Go 1.24.
Fixes:
- Fix performance regression due to using client without cache
[#1436](https://github.com/fluxcd/kustomize-controller/pull/1436)
- Fix secret value showing up in logs
[#1372](https://github.com/fluxcd/kustomize-controller/pull/1372)
Improvements:
- [RFC-0010] Introduce KMS provider decryption with service account
[#1426](https://github.com/fluxcd/kustomize-controller/pull/1426)
[#1449](https://github.com/fluxcd/kustomize-controller/pull/1449)
[#1456](https://github.com/fluxcd/kustomize-controller/pull/1456)
- Add `WaitForTermination` option to DeletionPolicy
[#1444](https://github.com/fluxcd/kustomize-controller/pull/1444)
- Skip emitting events for suspended Kustomizations
[#1396](https://github.com/fluxcd/kustomize-controller/pull/1396)
- Various dependency updates
[#1458](https://github.com/fluxcd/kustomize-controller/pull/1458)
[#1448](https://github.com/fluxcd/kustomize-controller/pull/1448)
[#1433](https://github.com/fluxcd/kustomize-controller/pull/1433)
[#1435](https://github.com/fluxcd/kustomize-controller/pull/1435)
[#1429](https://github.com/fluxcd/kustomize-controller/pull/1429)
[#1414](https://github.com/fluxcd/kustomize-controller/pull/1414)
[#1410](https://github.com/fluxcd/kustomize-controller/pull/1410)
[#1401](https://github.com/fluxcd/kustomize-controller/pull/1401)
## 1.5.1
**Release date:** 2025-02-25
This patch release fixes a bug introduced in v1.5.0
that was causing spurious logging for deprecated API versions
and sometimes failures on health checks.
In addition, all error logs resulting from SOPS decryption
failures have been sanitised.
Fixes:
- Fix secret value showing up in logs
[#1372](https://github.com/fluxcd/kustomize-controller/pull/1372)
- Use lazy restmapper vendored from controller-runtime v0.19
[#1377](https://github.com/fluxcd/kustomize-controller/pull/1377)
## 1.5.0
**Release date:** 2025-02-18
This minor release comes with various bug fixes and improvements.
The controller has been updated to Kustomize **v5.6**, please see the
`kubernetes-sigs/kustomize` [changelog](https://github.com/kubernetes-sigs/kustomize/releases)
for more details.
The Kustomization API now supports custom health checks for Custom
Resources through Common Expression Language (CEL) expressions.
See [docs](https://fluxcd.io/flux/components/kustomize/kustomizations/#health-check-expressions).
The controller now sends an origin revision from OCI artifact
annotations to notification-controller on events, which is
useful for updating commit statuses on the notification
providers that support this feature.
See [docs](https://fluxcd.io/flux/cheatsheets/oci-artifacts/#git-commit-status-updates).
It is now also possible to control whether or not kustomize-controller
will orphan resources when a Kustomization is deleted.
See [docs](https://fluxcd.io/flux/components/kustomize/kustomizations/#deletion-policy).
In addition, the Kubernetes dependencies have been updated to v1.32.1 and
various other controller dependencies have been updated to their latest
version.
Fixes:
- Clarify precedence in Kustomization substituteFrom
[#1301](https://github.com/fluxcd/kustomize-controller/pull/1301)
- Remove deprecated object metrics from controllers
[#1305](https://github.com/fluxcd/kustomize-controller/pull/1305)
Improvements:
- Enable decryption of secrets generated by Kustomize components
[#1283](https://github.com/fluxcd/kustomize-controller/pull/1283)
- Added decryption of Kustomize patches and refactor SOPS tests
[#1286](https://github.com/fluxcd/kustomize-controller/pull/1286)
- Allow control of finalization garbage collection
[#1314](https://github.com/fluxcd/kustomize-controller/pull/1314)
- Add OCI revision to events
[#1338](https://github.com/fluxcd/kustomize-controller/pull/1338)
- [RFC-0009] Add CEL custom healthchecks
[#1344](https://github.com/fluxcd/kustomize-controller/pull/1344)
- Add GroupChangeLog feature gate to fix es indexing cardinality
[#1361](https://github.com/fluxcd/kustomize-controller/pull/1361)
- Various dependency updates
[#1302](https://github.com/fluxcd/kustomize-controller/pull/1302)
[#1304](https://github.com/fluxcd/kustomize-controller/pull/1304)
[#1310](https://github.com/fluxcd/kustomize-controller/pull/1310)
[#1313](https://github.com/fluxcd/kustomize-controller/pull/1313)
[#1318](https://github.com/fluxcd/kustomize-controller/pull/1318)
[#1320](https://github.com/fluxcd/kustomize-controller/pull/1320)
[#1330](https://github.com/fluxcd/kustomize-controller/pull/1330)
[#1348](https://github.com/fluxcd/kustomize-controller/pull/1348)
[#1352](https://github.com/fluxcd/kustomize-controller/pull/1352)
[#1354](https://github.com/fluxcd/kustomize-controller/pull/1354)
[#1359](https://github.com/fluxcd/kustomize-controller/pull/1359)
[#1362](https://github.com/fluxcd/kustomize-controller/pull/1362)
[#1364](https://github.com/fluxcd/kustomize-controller/pull/1364)
[#1358](https://github.com/fluxcd/kustomize-controller/pull/1358)
## 1.4.0
**Release date:** 2024-09-27
This minor release comes with various bug fixes and improvements.
kustomize-controller in [sharded
deployment](https://fluxcd.io/flux/installation/configuration/sharding/)
configuration now supports cross-shard dependency check. This allows a
Kustomization to depend on other Kustomizations managed by different controller
shards.
In addition, the Kubernetes dependencies have been updated to v1.31.1 and
various other controller dependencies have been updated to their latest version.
The controller is now built with Go 1.23.
Fixes:
- Fix incorrect use of format strings with the conditions package.
[#1198](https://github.com/fluxcd/kustomize-controller/pull/1198)
Improvements:
- Update Bucket API to v1
[#1253](https://github.com/fluxcd/kustomize-controller/pull/1253)
- Allow cross-shard dependency check
[#1248](https://github.com/fluxcd/kustomize-controller/pull/1248)
- docs: Clarify .spec.decryption.secretRef usage
[#1242](https://github.com/fluxcd/kustomize-controller/pull/1242)
- Build with Go 1.23
[#1230](https://github.com/fluxcd/kustomize-controller/pull/1230)
- Various dependency updates
[#1165](https://github.com/fluxcd/kustomize-controller/pull/1165)
[#1181](https://github.com/fluxcd/kustomize-controller/pull/1181)
[#1212](https://github.com/fluxcd/kustomize-controller/pull/1212)
[#1228](https://github.com/fluxcd/kustomize-controller/pull/1228)
[#1229](https://github.com/fluxcd/kustomize-controller/pull/1229)
[#1233](https://github.com/fluxcd/kustomize-controller/pull/1233)
[#1239](https://github.com/fluxcd/kustomize-controller/pull/1239)
[#1240](https://github.com/fluxcd/kustomize-controller/pull/1240)
[#1243](https://github.com/fluxcd/kustomize-controller/pull/1243)
[#1249](https://github.com/fluxcd/kustomize-controller/pull/1249)
[#1250](https://github.com/fluxcd/kustomize-controller/pull/1250)
[#1251](https://github.com/fluxcd/kustomize-controller/pull/1251)
## 1.3.0
**Release date:** 2024-05-06
This minor release comes with new features, improvements and bug fixes.
The controller has been updated to Kustomize **v5.4**, please see the
`kubernetes-sigs/kustomize` [changelog](https://github.com/kubernetes-sigs/kustomize/releases)
for more details.
The Flux `Kustomization` API gains two optional fields `.spec.namePrefix` and `.spec.nameSuffix`
that can be used to specify a prefix and suffix to be added to the names
of all managed resources.
The controller now supports the `--feature-gates=StrictPostBuildSubstitutions=true`
flag, when enabled the post-build substitutions will fail if a
variable without a default value is declared in files but is
missing from the input vars.
When using variable substitution with values that are numbers or booleans,
it is now possible to covert the values to strings, for more details see the
[post-build documentation](https://github.com/fluxcd/kustomize-controller/blob/release/v1.3.x/docs/spec/v1/kustomizations.md#post-build-substitution-of-numbers-and-booleans).
In addition, the controller dependencies have been updated to Kubernetes v1.30
and controller-runtime v0.18. Various other dependencies have also been updated to
their latest version to patch upstream CVEs.
Lastly, the controller is now built with Go 1.22.
Improvements:
- Implement name prefix/suffix transformers
[#1134](https://github.com/fluxcd/kustomize-controller/pull/1134)
- Add `StrictPostBuildSubstitutions` feature flag
[#1130](https://github.com/fluxcd/kustomize-controller/pull/1130)
- Document how to use numbers and booleans in post build substitutions
[#1129](https://github.com/fluxcd/kustomize-controller/pull/1129)
- Remove deprecated aad pod identity from API docs
[#1152](https://github.com/fluxcd/kustomize-controller/pull/1152)
- api: Refer condition type constants from `fluxcd/pkg/apis`
[#1144](https://github.com/fluxcd/kustomize-controller/pull/1144)
- Update dependencies to Kustomize v5.4.0
[#1128](https://github.com/fluxcd/kustomize-controller/pull/1128)
- Various dependency updates
[#1155](https://github.com/fluxcd/kustomize-controller/pull/1155)
[#1121](https://github.com/fluxcd/kustomize-controller/pull/1121)
[#1139](https://github.com/fluxcd/kustomize-controller/pull/1139)
[#1122](https://github.com/fluxcd/kustomize-controller/pull/1122)
Fixes:
- Fix requeue warning introduced by controller-runtime
[#1090](https://github.com/fluxcd/kustomize-controller/pull/1090)
- Remove effectless statement
[#1091](https://github.com/fluxcd/kustomize-controller/pull/1091)
- Remove `genclient:Namespaced` tag
[#1092](https://github.com/fluxcd/kustomize-controller/pull/1092)
## 1.2.2
**Release date:** 2024-02-01
This patch release comes with various bug fixes and improvements.
Reconciling empty directories and directories without Kubernetes manifests no
longer results in an error. This regressing bug was introduced with the
controller upgrade to Kustomize v5.3 and has been fixed in this patch release.
The regression due to which the namespaced objects without a namespace specified
resulted in `not found` error instead of `namespace not specified` has also been
fixed. And the regression due to which Roles and ClusterRoles were reconciled
over and over due to the normalization of Roles and ClusterRoles has also been
fixed.
In addition, the Kubernetes dependencies have been updated to v1.28.6. Various
other dependencies have also been updated to their latest version to patch
upstream CVEs.
Lastly, the controller is now built with Go 1.21.
Improvements:
- Update Go to 1.21
[#1053](https://github.com/fluxcd/kustomize-controller/pull/1053)
- Various dependency updates
[#1076](https://github.com/fluxcd/kustomize-controller/pull/1076)
[#1074](https://github.com/fluxcd/kustomize-controller/pull/1074)
[#1070](https://github.com/fluxcd/kustomize-controller/pull/1070)
[#1068](https://github.com/fluxcd/kustomize-controller/pull/1068)
[#1065](https://github.com/fluxcd/kustomize-controller/pull/1065)
[#1060](https://github.com/fluxcd/kustomize-controller/pull/1060)
[#1059](https://github.com/fluxcd/kustomize-controller/pull/1059)
[#1051](https://github.com/fluxcd/kustomize-controller/pull/1051)
[#1049](https://github.com/fluxcd/kustomize-controller/pull/1049)
[#1046](https://github.com/fluxcd/kustomize-controller/pull/1046)
[#1044](https://github.com/fluxcd/kustomize-controller/pull/1044)
[#1040](https://github.com/fluxcd/kustomize-controller/pull/1040)
[#1038](https://github.com/fluxcd/kustomize-controller/pull/1038)
## 1.2.1
**Release date:** 2023-12-14
This patch release comes with improvements in logging to provide faster feedback
on any HTTP errors encountered while fetching source artifacts.
In addition, the status condition messages are now trimmed to respect the size
limit defined by the API.
Improvements:
- Update runtime to v0.43.3
[#1031](https://github.com/fluxcd/kustomize-controller/pull/1031)
- Log HTTP errors to provide faster feedback
[#1028](https://github.com/fluxcd/kustomize-controller/pull/1028)
## 1.2.0
**Release date:** 2023-12-11
This minor release comes with performance improvements, bug fixes and several new features.
The controller has been updated from Kustomize v5.0 to **v5.3**, please the see
`kubernetes-sigs/kustomize` [changelog](https://github.com/kubernetes-sigs/kustomize/releases)
for a more details.
Starting with this version, the controller will automatically perform a cleanup of
the Pods belonging to stale Kubernetes Jobs after a force apply.
A new controller flag `--override-manager` has been added to extend the Field Managers disallow list.
Using this flag, cluster administrators can configure the controller to undo changes
made with Lens and other UI tools that directly modify Kubernetes objects on clusters.
In addition, the controller dependencies have been updated, including an update to Kubernetes v1.28.
The container base image has been updated to Alpine 3.19.
Improvements:
- Update source-controller to v1.2.2
[#1024](https://github.com/fluxcd/kustomize-controller/pull/1024)
- build: update Alpine to 3.19
[#1023](https://github.com/fluxcd/kustomize-controller/pull/1023)
- Update Kustomize to v5.3.0
[#1021](https://github.com/fluxcd/kustomize-controller/pull/1021)
- Support additional Field Managers in the disallow list
[#1017](https://github.com/fluxcd/kustomize-controller/pull/1017)
- Add test for Namespace custom resource
[#1016](https://github.com/fluxcd/kustomize-controller/pull/1016)
- Update controller to Kubernetes v1.28.4
[#1014](https://github.com/fluxcd/kustomize-controller/pull/1014)
- Disable status poller cache by default
[#1012](https://github.com/fluxcd/kustomize-controller/pull/1012)
- Tweak permissions on various created files
[#1005](https://github.com/fluxcd/kustomize-controller/pull/1005)
- Cleanup pods when recreating Kubernetes Jobs
[#997](https://github.com/fluxcd/kustomize-controller/pull/997)
- Update SOPS to v3.8.1
[#995](https://github.com/fluxcd/kustomize-controller/pull/995)
## 1.1.1
**Release date:** 2023-10-11
This patch release contains an improvement to retry the reconciliation of a
`Kustomization` as soon as the source artifact is available in storage.
Which is particularly useful when the source-controller has just been upgraded.
In addition, the controller can now detect immutable field errors returned by the
Google Cloud k8s-config-connector admission controller and recreate the GCP custom
resources annotated with `kustomize.toolkit.fluxcd.io/force: Enabled`.
Improvements:
- Update `fluxcd/pkg` dependencies
[#983](https://github.com/fluxcd/kustomize-controller/pull/983)
- Bump `github.com/cyphar/filepath-securejoi`n from 0.2.3 to 0.2.4
[#962](https://github.com/fluxcd/kustomize-controller/pull/962)
Fixes:
- fix: Retry when artifacts are available in storage
[#980](https://github.com/fluxcd/kustomize-controller/pull/980)
- fix: Consistent artifact fetching retry timing
[#978](https://github.com/fluxcd/kustomize-controller/pull/978)
## 1.1.0
**Release date:** 2023-08-23
This minor release comes with performance improvements, bug fixes and several new features.
The apply behaviour has been extended with two policies `IfNotPresent` and `Ignore`.
To change the apply behaviour for specific Kubernetes resources, you can annotate them with:
| Annotation | Default | Values | Role |
|-------------------------------------|------------|----------------------------------------------------------------|-----------------|
| `kustomize.toolkit.fluxcd.io/ssa` | `Override` | - `Override`<br/>- `Merge`<br/>- `IfNotPresent`<br/>- `Ignore` | Apply policy |
| `kustomize.toolkit.fluxcd.io/force` | `Disabled` | - `Enabled`<br/>- `Disabled` | Recreate policy |
| `kustomize.toolkit.fluxcd.io/prune` | `Enabled` | - `Enabled`<br/>- `Disabled` | Delete policy |
The `IfNotPresent` policy instructs the controller to only apply the Kubernetes resources if they are not present on the cluster.
This policy can be used for Kubernetes `Secrets` and `ValidatingWebhookConfigurations` managed by cert-manager,
where Flux creates the resources with fields that are later on mutated by other controllers.
This version improves the health checking with fail-fast behaviour
by detecting stalled Kubernetes rollouts.
In addition, the controller now stops exporting an object's
metrics as soon as the object has been deleted.
Lastly, this release introduces two controller flags:
- The `--concurrent-ssa` flag sets the number of concurrent server-side apply operations
performed by the controller. Defaults to 4 concurrent operations per reconciliation.
- The `--interval-jitter-percentage` flag makes the
controller distribute the load more evenly when multiple objects are set up
with the same interval. The default of this flag is set to `5`, which means
that the interval will be jittered by a +/- 5% random value (e.g. if the
interval is 10 minutes, the actual reconciliation interval will be between 9.5
and 10.5 minutes).
Improvements:
- Add `--concurrent-ssa` flag
[#948](https://github.com/fluxcd/kustomize-controller/pull/948)
- Add `IfNotPresent` and `Ignore` SSA policies
[#943](https://github.com/fluxcd/kustomize-controller/pull/943)
- controller: jitter requeue interval
[#940](https://github.com/fluxcd/kustomize-controller/pull/940)
- Enable fail-fast behavior for health checks
[#933](https://github.com/fluxcd/kustomize-controller/pull/933)
- Bump `fluxcd/pkg/ssa` to improve immutable error detection
[#932](https://github.com/fluxcd/kustomize-controller/pull/932)
- Update dependencies
[#939](https://github.com/fluxcd/kustomize-controller/pull/939)
- Update Source API to v1.1.0
[#952](https://github.com/fluxcd/kustomize-controller/pull/952)
Fixes:
- Handle delete before adding finalizer
[#930](https://github.com/fluxcd/kustomize-controller/pull/930)
- Delete stale metrics on object delete
[#944](https://github.com/fluxcd/kustomize-controller/pull/944)
## 1.0.1
**Release date:** 2023-07-10
This is a patch release that fixes spurious events emitted for skipped resources.
Fixes:
- Exclude skipped resources from apply events
[#920](https://github.com/fluxcd/kustomize-controller/pull/920)
## 1.0.0
**Release date:** 2023-07-04
This is the first stable release of the controller. From now on, this controller
follows the [Flux 2 release cadence and support pledge](https://fluxcd.io/flux/releases/).
Starting with this version, the build, release and provenance portions of the
Flux project supply chain [provisionally meet SLSA Build Level 3](https://fluxcd.io/flux/security/slsa-assessment/).
This release includes several bug fixes. In addition, dependencies have been updated
to their latest version, including an update of Kubernetes to v1.27.3.
For a comprehensive list of changes since `v0.35.x`, please refer to the
changelog for [v1.0.0-rc.1](#100-rc1), [v1.0.0-rc.2](#100-rc2),
[v1.0.0-rc.3](#100-rc3) and [`v1.0.0-rc.4](#100-rc4).
Improvements:
- Update dependencies
[#908](https://github.com/fluxcd/kustomize-controller/pull/908)
- Align `go.mod` version with Kubernetes (Go 1.20)
[#900](https://github.com/fluxcd/kustomize-controller/pull/900)
Fixes:
- Use kustomization namespace for empty dependency source namespace
[#897](https://github.com/fluxcd/kustomize-controller/pull/897)
- docs: Clarify that targetNamespace namespace can be part of resources
[#896](https://github.com/fluxcd/kustomize-controller/pull/896)
## 1.0.0-rc.4
**Release date:** 2023-05-29
This release candidate comes with support for Kustomize v5.0.3.
⚠️ Note that Kustomize v5 contains breaking changes, please consult their
[changelog](https://github.com/kubernetes-sigs/kustomize/releases/tag/kustomize%2Fv5.0.0)
for more details.
In addition, the controller dependencies have been updated to
Kubernetes v1.27.2 and controller-runtime v0.15.0.
Improvements:
- Update Kubernetes to v1.27 and Kustomize to v5
[#850](https://github.com/fluxcd/kustomize-controller/pull/850)
- Update controller-runtime to v0.15.0
[#869](https://github.com/fluxcd/kustomize-controller/pull/869)
- Update CA certificates
[#872](https://github.com/fluxcd/kustomize-controller/pull/872)
- Update source-controller to v1.0.0-rc.4
[#873](https://github.com/fluxcd/kustomize-controller/pull/873)
## 1.0.0-rc.3
**Release date:** 2023-05-12
This release candidate comes with improved error reporting for when
the controller fails to fetch an artifact due to a checksum mismatch.
In addition, the controller dependencies have been updated to patch
CVE-2023-1732 and the base image has been updated to Alpine 3.18.
Improvements:
- Update Alpine to 3.18
[#855](https://github.com/fluxcd/kustomize-controller/pull/855)
- Update dependencies
[#862](https://github.com/fluxcd/kustomize-controller/pull/862)
- build(deps): bump github.com/cloudflare/circl from 1.1.0 to 1.3.3
[#860](https://github.com/fluxcd/kustomize-controller/pull/860)
- docs: Clarify the Kustomize components relative paths requirement
[#861](https://github.com/fluxcd/kustomize-controller/pull/861)
## 1.0.0-rc.2
**Release date:** 2023-05-09
This release candidate fixes secrets decryption when using Azure Key Vault.
In addition, the controller dependencies have been updated to their latest
versions.
Improvements:
- Fix SOPS azkv envCred
[#838](https://github.com/fluxcd/kustomize-controller/pull/838)
- Update dependencies
[#853](https://github.com/fluxcd/kustomize-controller/pull/853)
## 1.0.0-rc.1
**Release date:** 2023-04-03
This release candidate promotes the `Kustomization` API from `v1beta2` to `v1`.
The controller now supports horizontal scaling using
sharding based on a label selector.
In addition, the controller now supports Workload Identity when
decrypting secrets with SOPS and Azure Vault.
### Highlights
This release candidate requires the `GitRepository` API version `v1`,
first shipped with [source-controller](https://github.com/fluxcd/source-controller)
v1.0.0-rc.1.
#### API changes
The `Kustomization` kind was promoted from v1beta2 to v1 (GA) and deprecated fields were removed.
A new optional field called `CommonMetadata` was added to the API
for setting labels and/or annotations to all resources part of a Kustomization.
The main difference to the Kustomize
[commonLabels](https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/commonlabels/) and
[commonAnnotations](https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/commonannotations/),
is that the controller sets the labels and annotations only to the top level `metadata` field,
without patching the Kubernetes Deployment `spec.template` or the Service `spec.selector`.
The `kustomizations.kustomize.toolkit.fluxcd.io` CRD contains the following versions:
- v1 (storage version)
- v1beta2 (deprecated)
- v1beta1 (deprecated)
#### Upgrade procedure
The `Kustomization` v1 API is backwards compatible with v1beta2, except for the following:
- the deprecated field `.spec.validation` was removed
- the deprecated field `.spec.patchesStrategicMerge` was removed (replaced by `.spec.patches`)
- the deprecated field `.spec.patchesJson6902 ` was removed (replaced by `.spec.patches`)
To upgrade from v1beta2, after deploying the new CRD and controller,
set `apiVersion: kustomize.toolkit.fluxcd.io/v1` in the YAML files that contain
`Kustomization` definitions and remove the deprecated fields if any.
Bumping the API version in manifests can be done gradually.
It is advised to not delay this procedure as the beta versions will be removed after 6 months.
#### Sharding
Starting with this release, the controller can be configured with
`--watch-label-selector`, after which only objects with this label will
be reconciled by the controller.
This allows for horizontal scaling, where kustomize-controller
can be deployed multiple times with a unique label selector
which is used as the sharding key.
### Full changelog
Improvements:
- GA: Promote Kustomization API to `kustomize.toolkit.fluxcd.io/v1`
[#822](https://github.com/fluxcd/kustomize-controller/pull/822)
- Add common labels and annotations patching capabilities
[#817](https://github.com/fluxcd/kustomize-controller/pull/817)
- Add reconciler sharding capability based on label selector
[#821](https://github.com/fluxcd/kustomize-controller/pull/821)
- Support Workload Identity for Azure Vault
[#813](https://github.com/fluxcd/kustomize-controller/pull/813)
- Verify Digest of Artifact
[#818](https://github.com/fluxcd/kustomize-controller/pull/818)
- Move `controllers` to `internal/controllers`
[#820](https://github.com/fluxcd/kustomize-controller/pull/820)
- build(deps): bump github.com/opencontainers/runc from 1.1.2 to 1.1.5
[#824](https://github.com/fluxcd/kustomize-controller/pull/824)
## 0.35.1
**Release date:** 2023-03-20
This prerelease comes with a fix to error reporting.
The controller will now reveal validation errors when force applying
resources with immutable field changes.
In addition, the controller dependencies have been updated to their latest
versions.
Improvements:
- Update dependencies
[#814](https://github.com/fluxcd/kustomize-controller/pull/814)
## 0.35.0
**Release date:** 2023-03-08
This prerelease adds support for disabling the cache of the `kstatus` status
poller, which is used to determine the health of the resources applied by the
controller. To disable the cache, configure the Deployment of the controller
with `--feature-gates=DisableStatusPollerCache=true`.
This may have a positive impact on memory usage on large clusters with many
objects, at the cost of an increased number of API calls.
In addition, `klog` has been configured to log using the same logger as the
rest of the controller (providing a consistent log format).
Lastly, the controller is now built using Go `1.20`, and the dependencies have
been updated to their latest versions.
Improvements:
- api: update description LastAppliedRevision
[#798](https://github.com/fluxcd/kustomize-controller/pull/798)
- Update Go to 1.20
[#806](https://github.com/fluxcd/kustomize-controller/pull/806)
- Update dependencies
[#807](https://github.com/fluxcd/kustomize-controller/pull/807)
[#811](https://github.com/fluxcd/kustomize-controller/pull/811)
- Use `logger.SetLogger` to also configure `klog`
[#809](https://github.com/fluxcd/kustomize-controller/pull/809)
## 0.34.0
**Release date:** 2023-02-17
This prerelease adds support for parsing the
[RFC-0005](https://github.com/fluxcd/flux2/tree/main/rfcs/0005-artifact-revision-and-digest)
revision format produced by source-controller `>=v0.35.0`.
In addition, the controller dependencies have been updated to their latest
versions.
Improvements:
- Support RFC-0005 revision format
[#793](https://github.com/fluxcd/kustomize-controller/pull/793)
- Update dependencies
[#796](https://github.com/fluxcd/kustomize-controller/pull/796)
## 0.33.0
**Release date:** 2023-02-01

View File

@ -13,10 +13,19 @@ There are a number of dependencies required to be able to run the controller and
- [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)
- `sops` (v3.7.2)
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.18
You can run the test suite by simply doing

View File

@ -1,9 +1,9 @@
ARG GO_VERSION=1.24
ARG XX_VERSION=1.6.1
ARG GO_VERSION=1.19
ARG XX_VERSION=1.1.0
FROM --platform=$BUILDPLATFORM tonistiigi/xx:${XX_VERSION} AS xx
FROM --platform=$BUILDPLATFORM golang:${GO_VERSION}-alpine AS builder
FROM --platform=$BUILDPLATFORM golang:${GO_VERSION}-alpine as builder
# Copy the build utilities.
COPY --from=xx / /
@ -24,18 +24,18 @@ RUN go mod download
# copy source code
COPY main.go main.go
COPY controllers/ controllers/
COPY internal/ internal/
# build
ENV CGO_ENABLED=0
RUN xx-go build -trimpath -a -o kustomize-controller main.go
FROM alpine:3.21
FROM alpine:3.17
ARG TARGETPLATFORM
RUN apk --no-cache add ca-certificates tini git openssh-client gnupg \
&& update-ca-certificates
# Uses GnuPG from edge to patch CVE-2022-3515.
RUN apk add --no-cache ca-certificates tini git openssh-client && \
apk add --no-cache gnupg --repository=https://dl-cdn.alpinelinux.org/alpine/edge/main
COPY --from=builder /workspace/kustomize-controller /usr/local/bin/

View File

@ -5,7 +5,7 @@ CRD_OPTIONS ?= crd:crdVersions=v1
SOURCE_VER ?= $(shell go list -m all | grep github.com/fluxcd/source-controller/api | awk '{print $$2}')
# Use the same version of SOPS already referenced on go.mod
SOPS_VER := $(shell go list -m all | grep github.com/getsops/sops | awk '{print $$2}')
SOPS_VER := $(shell go list -m all | grep go.mozilla.org/sops | awk '{print $$2}')
# Repository root based on Git metadata
REPOSITORY_ROOT := $(shell git rev-parse --show-toplevel)
@ -43,10 +43,6 @@ OCIREPO_CRD ?= config/crd/bases/ocirepositories.yaml
# detect and download new CRDs when the SOURCE_VER changes.
SOURCE_CRD_VER=$(BUILD_DIR)/.src-crd-$(SOURCE_VER)
# API (doc) generation utilities
CONTROLLER_GEN_VERSION ?= v0.16.1
GEN_API_REF_DOCS_VERSION ?= e327d0730470cbd61b06300f81c5fcf91c23c113
all: manager
# Download the envtest binaries to testbin
@ -58,7 +54,7 @@ install-envtest: setup-envtest
SOPS = $(GOBIN)/sops
$(SOPS): ## Download latest sops binary if none is found.
$(call go-install-tool,$(SOPS),github.com/getsops/sops/v3/cmd/sops@$(SOPS_VER))
$(call go-install-tool,$(SOPS),go.mozilla.org/sops/v3/cmd/sops@$(SOPS_VER))
# Run controller tests
KUBEBUILDER_ASSETS?="$(shell $(ENVTEST) --arch=$(ENVTEST_ARCH) use -i $(ENVTEST_KUBERNETES_VERSION) --bin-dir=$(ENVTEST_ASSETS_DIR) -p path)"
@ -78,7 +74,6 @@ run: generate fmt vet manifests
$(SOURCE_CRD_VER):
rm -f $(BUILD_DIR)/.src-crd*
$(MAKE) cleanup-crd-deps
if ! test -d "$(BUILD_DIR)"; then mkdir -p $(BUILD_DIR); fi
touch $(SOURCE_CRD_VER)
$(GITREPO_CRD):
@ -131,12 +126,12 @@ manifests: controller-gen
# Generate API reference documentation
api-docs: gen-crd-api-reference-docs
$(GEN_CRD_API_REFERENCE_DOCS) -api-dir=./api/v1 -config=./hack/api-docs/config.json -template-dir=./hack/api-docs/template -out-file=./docs/api/v1/kustomize.md
$(GEN_CRD_API_REFERENCE_DOCS) -api-dir=./api/v1beta2 -config=./hack/api-docs/config.json -template-dir=./hack/api-docs/template -out-file=./docs/api/kustomize.md
# Run go mod tidy
tidy:
cd api; rm -f go.sum; go mod tidy -compat=1.24
rm -f go.sum; go mod tidy -compat=1.24
cd api; rm -f go.sum; go mod tidy -compat=1.19
rm -f go.sum; go mod tidy -compat=1.19
# Run go fmt against code
fmt:
@ -171,13 +166,13 @@ docker-deploy:
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))
$(call go-install-tool,$(CONTROLLER_GEN),sigs.k8s.io/controller-tools/cmd/controller-gen@v0.8.0)
# 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))
gen-crd-api-reference-docs:
$(call go-install-tool,$(GEN_CRD_API_REFERENCE_DOCS),github.com/ahmetb/gen-crd-api-reference-docs@v0.3.0)
ENVTEST = $(GOBIN)/setup-envtest
.PHONY: envtest

View File

@ -1,9 +1,6 @@
domain: toolkit.fluxcd.io
repo: github.com/fluxcd/kustomize-controller
resources:
- group: kustomize
kind: Kustomization
version: v1
- group: kustomize
kind: Kustomization
version: v1beta2

View File

@ -34,14 +34,14 @@ the controller performs actions to reconcile the cluster current state with the
## Specifications
* [API](docs/spec/v1/README.md)
* [API](docs/spec/v1beta2/README.md)
* [Controller](docs/spec/README.md)
## Guides
* [Get started with Flux](https://fluxcd.io/flux/get-started/)
* [Setup Notifications](https://fluxcd.io/flux/guides/notifications/)
* [Manage Kubernetes secrets with Flux and SOPS](https://fluxcd.io/flux/guides/mozilla-sops/)
* [Manage Kubernetes secrets with Flux and Mozilla SOPS](https://fluxcd.io/flux/guides/mozilla-sops/)
* [How to build, publish and consume OCI Artifacts with Flux](https://fluxcd.io/flux/cheatsheets/oci-artifacts/)
* [Flux and Kustomize FAQ](https://fluxcd.io/flux/faq/#kustomize-questions)

View File

@ -1,36 +1,36 @@
module github.com/fluxcd/kustomize-controller/api
go 1.24.0
go 1.18
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
github.com/fluxcd/pkg/apis/kustomize v0.8.0
github.com/fluxcd/pkg/apis/meta v0.19.0
k8s.io/apiextensions-apiserver v0.26.1
k8s.io/apimachinery v0.26.1
sigs.k8s.io/controller-runtime v0.14.2
)
// Fix CVE-2022-32149
replace golang.org/x/text => golang.org/x/text v0.4.0
// Fix CVE-2022-28948
replace gopkg.in/yaml.v3 => gopkg.in/yaml.v3 v3.0.1
require (
github.com/fxamacker/cbor/v2 v2.8.0 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/logr v1.2.3 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
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
golang.org/x/net v0.3.1-0.20221206200815-1e63c2f08a10 // indirect
golang.org/x/text v0.5.0 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // 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
sigs.k8s.io/yaml v1.5.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
k8s.io/klog/v2 v2.80.1 // indirect
k8s.io/utils v0.0.0-20221128185143-99ec85e7a448 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
sigs.k8s.io/yaml v1.3.0 // indirect
)

View File

@ -1,91 +1,79 @@
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fluxcd/pkg/apis/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/fluxcd/pkg/apis/kustomize v0.8.0 h1:A6aLolxPV2Sll44SOHiX96lbXXmRZmS5BoEerkRHrfM=
github.com/fluxcd/pkg/apis/kustomize v0.8.0/go.mod h1:9DPEVSfVIkiC2H3Dk6Ght4YJkswhYIaufXla4tB5Y84=
github.com/fluxcd/pkg/apis/meta v0.19.0 h1:CX75e/eaRWZDTzNdMSWomY1InlssLKcS8GQDSg/aopI=
github.com/fluxcd/pkg/apis/meta v0.19.0/go.mod h1:7b6prDPsViyAzoY7eRfSPS0/MbXpGGsOMvRq2QrTKa4=
github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/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/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
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/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/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/onsi/ginkgo/v2 v2.6.0 h1:9t9b9vRUbFq3C4qKFCGkVuq/fIHji802N1nrtkh1mNc=
github.com/onsi/gomega v1.24.1 h1:KORJXNNTzJXzu4ScJWssJfJMnJ+2QJqhoQSRwNlze9E=
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/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.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.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
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.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
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.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.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-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.3.1-0.20221206200815-1e63c2f08a10 h1:Frnccbp+ok2GkUS2tC84yAq/U9Vg+0sIO7aRL3T4Xnc=
golang.org/x/net v0.3.1-0.20221206200815-1e63c2f08a10/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
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-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo=
golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
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=
@ -95,27 +83,24 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
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=
k8s.io/api v0.26.1 h1:f+SWYiPd/GsiWwVRz+NbFyCgvv75Pk9NK6dlkZgpCRQ=
k8s.io/apiextensions-apiserver v0.26.1 h1:cB8h1SRk6e/+i3NOrQgSFij1B2S0Y0wDoNl66bn8RMI=
k8s.io/apiextensions-apiserver v0.26.1/go.mod h1:AptjOSXDGuE0JICx/Em15PaoO7buLwTs0dGleIHixSM=
k8s.io/apimachinery v0.26.1 h1:8EZ/eGJL+hY/MYCNwhmDzVqq2lPl3N3Bo8rvweJwXUQ=
k8s.io/apimachinery v0.26.1/go.mod h1:tnPmbONNJ7ByJNz9+n9kMjNP8ON+1qoAIIC70lztu74=
k8s.io/klog/v2 v2.80.1 h1:atnLQ121W371wYYFawwYx1aEY2eUfs4l3J72wtgAwV4=
k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
k8s.io/utils v0.0.0-20221128185143-99ec85e7a448 h1:KTgPnR10d5zhztWptI952TNtt/4u5h3IzDXkdIMuo2Y=
k8s.io/utils v0.0.0-20221128185143-99ec85e7a448/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
sigs.k8s.io/controller-runtime v0.14.2 h1:P6IwDhbsRWsBClt/8/h8Zy36bCuGuW5Op7MHpFrN/60=
sigs.k8s.io/controller-runtime v0.14.2/go.mod h1:WqIdsAY6JBsjfc/CqO0CORmNtoCtE4S6qbPc9s68h+0=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE=
sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E=
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=

View File

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

View File

@ -1,33 +0,0 @@
/*
Copyright 2023 The Flux authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1
import (
"k8s.io/apimachinery/pkg/runtime/schema"
"sigs.k8s.io/controller-runtime/pkg/scheme"
)
var (
// GroupVersion is group version used to register these objects.
GroupVersion = schema.GroupVersion{Group: "kustomize.toolkit.fluxcd.io", Version: "v1"}
// SchemeBuilder is used to add go types to the GroupVersionKind scheme.
SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
// AddToScheme adds the types in this group-version to the given scheme.
AddToScheme = SchemeBuilder.AddToScheme
)

View File

@ -1,34 +0,0 @@
/*
Copyright 2023 The Flux authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1
// ResourceInventory contains a list of Kubernetes resource object references
// that have been applied by a Kustomization.
type ResourceInventory struct {
// Entries of Kubernetes resource object references.
Entries []ResourceRef `json:"entries"`
}
// ResourceRef contains the information necessary to locate a resource within a cluster.
type ResourceRef struct {
// ID is the string representation of the Kubernetes resource object's metadata,
// in the format '<namespace>_<name>_<group>_<kind>'.
ID string `json:"id"`
// Version is the API version of the Kubernetes resource object's kind.
Version string `json:"v"`
}

View File

@ -1,391 +0,0 @@
/*
Copyright 2023 The Flux authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1
import (
"time"
"github.com/fluxcd/pkg/apis/kustomize"
"github.com/fluxcd/pkg/apis/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
const (
KustomizationKind = "Kustomization"
KustomizationFinalizer = "finalizers.fluxcd.io"
MaxConditionMessageLength = 20000
EnabledValue = "enabled"
DisabledValue = "disabled"
MergeValue = "Merge"
IfNotPresentValue = "IfNotPresent"
IgnoreValue = "Ignore"
DeletionPolicyMirrorPrune = "MirrorPrune"
DeletionPolicyDelete = "Delete"
DeletionPolicyWaitForTermination = "WaitForTermination"
DeletionPolicyOrphan = "Orphan"
)
// KustomizationSpec defines the configuration to calculate the desired state
// from a Source using Kustomize.
type KustomizationSpec struct {
// CommonMetadata specifies the common labels and annotations that are
// applied to all resources. Any existing label or annotation will be
// overridden if its key matches a common one.
// +optional
CommonMetadata *CommonMetadata `json:"commonMetadata,omitempty"`
// DependsOn may contain a DependencyReference slice
// with references to Kustomization resources that must be ready before this
// Kustomization can be reconciled.
// +optional
DependsOn []DependencyReference `json:"dependsOn,omitempty"`
// Decrypt Kubernetes secrets before applying them on the cluster.
// +optional
Decryption *Decryption `json:"decryption,omitempty"`
// The interval at which to reconcile the Kustomization.
// 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"`
// The interval at which to retry a previously failed reconciliation.
// When not specified, the controller uses the KustomizationSpec.Interval
// value to retry failures.
// +kubebuilder:validation:Type=string
// +kubebuilder:validation:Pattern="^([0-9]+(\\.[0-9]+)?(ms|s|m|h))+$"
// +optional
RetryInterval *metav1.Duration `json:"retryInterval,omitempty"`
// The KubeConfig for reconciling the Kustomization on a remote cluster.
// When used in combination with KustomizationSpec.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 KustomizationSpec.ServiceAccountName
// is empty.
// +optional
KubeConfig *meta.KubeConfigReference `json:"kubeConfig,omitempty"`
// Path to the directory containing the kustomization.yaml file, or the
// set of plain YAMLs a kustomization.yaml should be generated for.
// Defaults to 'None', which translates to the root path of the SourceRef.
// +optional
Path string `json:"path,omitempty"`
// PostBuild describes which actions to perform on the YAML manifest
// generated by building the kustomize overlay.
// +optional
PostBuild *PostBuild `json:"postBuild,omitempty"`
// Prune enables garbage collection.
// +required
Prune bool `json:"prune"`
// DeletionPolicy can be used to control garbage collection when this
// Kustomization is deleted. Valid values are ('MirrorPrune', 'Delete',
// 'WaitForTermination', 'Orphan'). 'MirrorPrune' mirrors the Prune field
// (orphan if false, delete if true). Defaults to 'MirrorPrune'.
// +kubebuilder:validation:Enum=MirrorPrune;Delete;WaitForTermination;Orphan
// +optional
DeletionPolicy string `json:"deletionPolicy,omitempty"`
// A list of resources to be included in the health assessment.
// +optional
HealthChecks []meta.NamespacedObjectKindReference `json:"healthChecks,omitempty"`
// NamePrefix will prefix the names of all managed resources.
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=200
// +kubebuilder:validation:Optional
// +optional
NamePrefix string `json:"namePrefix,omitempty" yaml:"namePrefix,omitempty"`
// NameSuffix will suffix the names of all managed resources.
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=200
// +kubebuilder:validation:Optional
// +optional
NameSuffix string `json:"nameSuffix,omitempty" yaml:"nameSuffix,omitempty"`
// 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"`
// Images is a list of (image name, new name, new tag or digest)
// for changing image names, tags or digests. This can also be achieved with a
// patch, but this operator is simpler to specify.
// +optional
Images []kustomize.Image `json:"images,omitempty"`
// The name of the Kubernetes service account to impersonate
// when reconciling this Kustomization.
// +optional
ServiceAccountName string `json:"serviceAccountName,omitempty"`
// Reference of the source where the kustomization file is.
// +required
SourceRef CrossNamespaceSourceReference `json:"sourceRef"`
// This flag tells the controller to suspend subsequent kustomize executions,
// it does not apply to already started executions. Defaults to false.
// +optional
Suspend bool `json:"suspend,omitempty"`
// TargetNamespace sets or overrides the namespace in the
// kustomization.yaml file.
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=63
// +kubebuilder:validation:Optional
// +optional
TargetNamespace string `json:"targetNamespace,omitempty"`
// Timeout for validation, apply and health checking operations.
// Defaults to 'Interval' duration.
// +kubebuilder:validation:Type=string
// +kubebuilder:validation:Pattern="^([0-9]+(\\.[0-9]+)?(ms|s|m|h))+$"
// +optional
Timeout *metav1.Duration `json:"timeout,omitempty"`
// Force instructs the controller to recreate resources
// when patching fails due to an immutable field change.
// +kubebuilder:default:=false
// +optional
Force bool `json:"force,omitempty"`
// Wait instructs the controller to check the health of all the reconciled
// resources. When enabled, the HealthChecks are ignored. Defaults to false.
// +optional
Wait bool `json:"wait,omitempty"`
// Components specifies relative paths to specifications of other Components.
// +optional
Components []string `json:"components,omitempty"`
// HealthCheckExprs is a list of healthcheck expressions for evaluating the
// health of custom resources using Common Expression Language (CEL).
// The expressions are evaluated only when Wait or HealthChecks are specified.
// +optional
HealthCheckExprs []kustomize.CustomHealthCheck `json:"healthCheckExprs,omitempty"`
}
// CommonMetadata defines the common labels and annotations.
type CommonMetadata struct {
// Annotations to be added to the object's metadata.
// +optional
Annotations map[string]string `json:"annotations,omitempty"`
// Labels to be added to the object's metadata.
// +optional
Labels map[string]string `json:"labels,omitempty"`
}
// Decryption defines how decryption is handled for Kubernetes manifests.
type Decryption struct {
// Provider is the name of the decryption engine.
// +kubebuilder:validation:Enum=sops
// +required
Provider string `json:"provider"`
// ServiceAccountName is the name of the service account used to
// authenticate with KMS services from cloud providers. If a
// static credential for a given cloud provider is defined
// inside the Secret referenced by SecretRef, that static
// credential takes priority.
// +optional
ServiceAccountName string `json:"serviceAccountName,omitempty"`
// The secret name containing the private OpenPGP keys used for decryption.
// A static credential for a cloud provider defined inside the Secret
// takes priority to secret-less authentication with the ServiceAccountName
// field.
// +optional
SecretRef *meta.LocalObjectReference `json:"secretRef,omitempty"`
}
// PostBuild describes which actions to perform on the YAML manifest
// generated by building the kustomize overlay.
type PostBuild struct {
// Substitute holds a map of key/value pairs.
// The variables defined in your YAML manifests that match any of the keys
// defined in the map will be substituted with the set value.
// Includes support for bash string replacement functions
// e.g. ${var:=default}, ${var:position} and ${var/substring/replacement}.
// +optional
Substitute map[string]string `json:"substitute,omitempty"`
// SubstituteFrom holds references to ConfigMaps and Secrets containing
// the variables and their values to be substituted in the YAML manifests.
// The ConfigMap and the Secret data keys represent the var names, and they
// must match the vars declared in the manifests for the substitution to
// happen.
// +optional
SubstituteFrom []SubstituteReference `json:"substituteFrom,omitempty"`
}
// SubstituteReference contains a reference to a resource containing
// the variables name and value.
type SubstituteReference 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"`
// Optional indicates whether the referenced resource must exist, or whether to
// tolerate its absence. If true and the referenced resource is absent, proceed
// as if the resource was present but empty, without any variables defined.
// +kubebuilder:default:=false
// +optional
Optional bool `json:"optional,omitempty"`
}
// KustomizationStatus defines the observed state of a kustomization.
type KustomizationStatus struct {
meta.ReconcileRequestStatus `json:",inline"`
// ObservedGeneration is the last reconciled generation.
// +optional
ObservedGeneration int64 `json:"observedGeneration,omitempty"`
// +optional
Conditions []metav1.Condition `json:"conditions,omitempty"`
// The last successfully applied revision.
// Equals the Revision of the applied Artifact from the referenced Source.
// +optional
LastAppliedRevision string `json:"lastAppliedRevision,omitempty"`
// The last successfully applied origin revision.
// Equals the origin revision of the applied Artifact from the referenced Source.
// Usually present on the Metadata of the applied Artifact and depends on the
// Source type, e.g. for OCI it's the value associated with the key
// "org.opencontainers.image.revision".
// +optional
LastAppliedOriginRevision string `json:"lastAppliedOriginRevision,omitempty"`
// LastAttemptedRevision is the revision of the last reconciliation attempt.
// +optional
LastAttemptedRevision string `json:"lastAttemptedRevision,omitempty"`
// Inventory contains the list of Kubernetes resource object references that
// have been successfully applied.
// +optional
Inventory *ResourceInventory `json:"inventory,omitempty"`
}
// GetTimeout returns the timeout with default.
func (in Kustomization) GetTimeout() time.Duration {
duration := in.Spec.Interval.Duration - 30*time.Second
if in.Spec.Timeout != nil {
duration = in.Spec.Timeout.Duration
}
if duration < 30*time.Second {
return 30 * time.Second
}
return duration
}
// GetRetryInterval returns the retry interval
func (in Kustomization) GetRetryInterval() time.Duration {
if in.Spec.RetryInterval != nil {
return in.Spec.RetryInterval.Duration
}
return in.GetRequeueAfter()
}
// GetRequeueAfter returns the duration after which the Kustomization must be
// reconciled again.
func (in Kustomization) GetRequeueAfter() time.Duration {
return in.Spec.Interval.Duration
}
// GetDeletionPolicy returns the deletion policy and default value if not specified.
func (in Kustomization) GetDeletionPolicy() string {
if in.Spec.DeletionPolicy == "" {
return DeletionPolicyMirrorPrune
}
return in.Spec.DeletionPolicy
}
// GetDependsOn returns the dependencies as a list of meta.NamespacedObjectReference.
//
// This function makes the Kustomization type conformant with the meta.ObjectWithDependencies interface
// and allows the controller-runtime to index Kustomizations by their dependencies.
func (in Kustomization) GetDependsOn() []meta.NamespacedObjectReference {
deps := make([]meta.NamespacedObjectReference, len(in.Spec.DependsOn))
for i := range in.Spec.DependsOn {
deps[i] = meta.NamespacedObjectReference{
Name: in.Spec.DependsOn[i].Name,
Namespace: in.Spec.DependsOn[i].Namespace,
}
}
return deps
}
// GetConditions returns the status conditions of the object.
func (in Kustomization) GetConditions() []metav1.Condition {
return in.Status.Conditions
}
// SetConditions sets the status conditions on the object.
func (in *Kustomization) SetConditions(conditions []metav1.Condition) {
in.Status.Conditions = conditions
}
// +genclient
// +kubebuilder:storageversion
// +kubebuilder:object:root=true
// +kubebuilder:resource:shortName=ks
// +kubebuilder:subresource:status
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description=""
// +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].status",description=""
// +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].message",description=""
// Kustomization is the Schema for the kustomizations API.
type Kustomization struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec KustomizationSpec `json:"spec,omitempty"`
// +kubebuilder:default:={"observedGeneration":-1}
Status KustomizationStatus `json:"status,omitempty"`
}
// +kubebuilder:object:root=true
// KustomizationList contains a list of kustomizations.
type KustomizationList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []Kustomization `json:"items"`
}
func init() {
SchemeBuilder.Register(&Kustomization{}, &KustomizationList{})
}

View File

@ -1,72 +0,0 @@
/*
Copyright 2023 The Flux authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1
import (
"fmt"
)
// CrossNamespaceSourceReference contains enough information to let you locate the
// typed Kubernetes resource object at cluster level.
type CrossNamespaceSourceReference struct {
// API version of the referent.
// +optional
APIVersion string `json:"apiVersion,omitempty"`
// Kind of the referent.
// +kubebuilder:validation:Enum=OCIRepository;GitRepository;Bucket
// +required
Kind string `json:"kind"`
// Name of the referent.
// +required
Name string `json:"name"`
// Namespace of the referent, defaults to the namespace of the Kubernetes
// resource object that contains the reference.
// +optional
Namespace string `json:"namespace,omitempty"`
}
// String returns a string representation of the CrossNamespaceSourceReference
// in the format "Kind/Name" or "Kind/Namespace/Name" if Namespace is set.
func (s *CrossNamespaceSourceReference) String() string {
if s.Namespace != "" {
return fmt.Sprintf("%s/%s/%s", s.Kind, s.Namespace, s.Name)
}
return fmt.Sprintf("%s/%s", s.Kind, s.Name)
}
// DependencyReference defines a Kustomization dependency on another Kustomization resource.
type DependencyReference struct {
// Name of the referent.
// +required
Name string `json:"name"`
// Namespace of the referent, defaults to the namespace of the Kustomization
// 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,350 +0,0 @@
//go:build !ignore_autogenerated
/*
Copyright 2023 The Flux authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by controller-gen. DO NOT EDIT.
package v1
import (
"github.com/fluxcd/pkg/apis/kustomize"
"github.com/fluxcd/pkg/apis/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *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 *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 *Decryption) DeepCopyInto(out *Decryption) {
*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 Decryption.
func (in *Decryption) DeepCopy() *Decryption {
if in == nil {
return nil
}
out := new(Decryption)
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 *Kustomization) DeepCopyInto(out *Kustomization) {
*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 Kustomization.
func (in *Kustomization) DeepCopy() *Kustomization {
if in == nil {
return nil
}
out := new(Kustomization)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *Kustomization) 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 *KustomizationList) DeepCopyInto(out *KustomizationList) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]Kustomization, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KustomizationList.
func (in *KustomizationList) DeepCopy() *KustomizationList {
if in == nil {
return nil
}
out := new(KustomizationList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *KustomizationList) 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 *KustomizationSpec) DeepCopyInto(out *KustomizationSpec) {
*out = *in
if in.CommonMetadata != nil {
in, out := &in.CommonMetadata, &out.CommonMetadata
*out = new(CommonMetadata)
(*in).DeepCopyInto(*out)
}
if in.DependsOn != nil {
in, out := &in.DependsOn, &out.DependsOn
*out = make([]DependencyReference, len(*in))
copy(*out, *in)
}
if in.Decryption != nil {
in, out := &in.Decryption, &out.Decryption
*out = new(Decryption)
(*in).DeepCopyInto(*out)
}
out.Interval = in.Interval
if in.RetryInterval != nil {
in, out := &in.RetryInterval, &out.RetryInterval
*out = new(metav1.Duration)
**out = **in
}
if in.KubeConfig != nil {
in, out := &in.KubeConfig, &out.KubeConfig
*out = new(meta.KubeConfigReference)
(*in).DeepCopyInto(*out)
}
if in.PostBuild != nil {
in, out := &in.PostBuild, &out.PostBuild
*out = new(PostBuild)
(*in).DeepCopyInto(*out)
}
if in.HealthChecks != nil {
in, out := &in.HealthChecks, &out.HealthChecks
*out = make([]meta.NamespacedObjectKindReference, len(*in))
copy(*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)
}
out.SourceRef = in.SourceRef
if in.Timeout != nil {
in, out := &in.Timeout, &out.Timeout
*out = new(metav1.Duration)
**out = **in
}
if in.Components != nil {
in, out := &in.Components, &out.Components
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.HealthCheckExprs != nil {
in, out := &in.HealthCheckExprs, &out.HealthCheckExprs
*out = make([]kustomize.CustomHealthCheck, len(*in))
copy(*out, *in)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KustomizationSpec.
func (in *KustomizationSpec) DeepCopy() *KustomizationSpec {
if in == nil {
return nil
}
out := new(KustomizationSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *KustomizationStatus) DeepCopyInto(out *KustomizationStatus) {
*out = *in
out.ReconcileRequestStatus = in.ReconcileRequestStatus
if in.Conditions != nil {
in, out := &in.Conditions, &out.Conditions
*out = make([]metav1.Condition, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.Inventory != nil {
in, out := &in.Inventory, &out.Inventory
*out = new(ResourceInventory)
(*in).DeepCopyInto(*out)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KustomizationStatus.
func (in *KustomizationStatus) DeepCopy() *KustomizationStatus {
if in == nil {
return nil
}
out := new(KustomizationStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *PostBuild) DeepCopyInto(out *PostBuild) {
*out = *in
if in.Substitute != nil {
in, out := &in.Substitute, &out.Substitute
*out = make(map[string]string, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
if in.SubstituteFrom != nil {
in, out := &in.SubstituteFrom, &out.SubstituteFrom
*out = make([]SubstituteReference, len(*in))
copy(*out, *in)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PostBuild.
func (in *PostBuild) DeepCopy() *PostBuild {
if in == nil {
return nil
}
out := new(PostBuild)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ResourceInventory) DeepCopyInto(out *ResourceInventory) {
*out = *in
if in.Entries != nil {
in, out := &in.Entries, &out.Entries
*out = make([]ResourceRef, len(*in))
copy(*out, *in)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceInventory.
func (in *ResourceInventory) DeepCopy() *ResourceInventory {
if in == nil {
return nil
}
out := new(ResourceInventory)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ResourceRef) DeepCopyInto(out *ResourceRef) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceRef.
func (in *ResourceRef) DeepCopy() *ResourceRef {
if in == nil {
return nil
}
out := new(ResourceRef)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *SubstituteReference) DeepCopyInto(out *SubstituteReference) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubstituteReference.
func (in *SubstituteReference) DeepCopy() *SubstituteReference {
if in == nil {
return nil
}
out := new(SubstituteReference)
in.DeepCopyInto(out)
return out
}

View File

@ -271,13 +271,13 @@ const (
)
// +genclient
// +genclient:Namespaced
// +kubebuilder:object:root=true
// +kubebuilder:resource:shortName=ks
// +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=""
// +kubebuilder:deprecatedversion:warning="v1beta1 Kustomization is deprecated, upgrade to v1"
// Kustomization is the Schema for the kustomizations API.
type Kustomization struct {

View File

@ -1,7 +1,8 @@
//go:build !ignore_autogenerated
// +build !ignore_autogenerated
/*
Copyright 2023 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.
@ -175,9 +176,7 @@ func (in *KustomizationSpec) DeepCopyInto(out *KustomizationSpec) {
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])
}
copy(*out, *in)
}
if in.PatchesStrategicMerge != nil {
in, out := &in.PatchesStrategicMerge, &out.PatchesStrategicMerge

View File

@ -36,11 +36,6 @@ const (
// KustomizationSpec defines the configuration to calculate the desired state from a Source using Kustomize.
type KustomizationSpec struct {
// CommonMetadata specifies the common labels and annotations that are applied to all resources.
// Any existing label or annotation will be overridden if its key matches a common one.
// +optional
CommonMetadata *CommonMetadata `json:"commonMetadata,omitempty"`
// DependsOn may contain a meta.NamespacedObjectReference slice
// with references to Kustomization resources that must be ready before this
// Kustomization can be reconciled.
@ -155,25 +150,14 @@ type KustomizationSpec struct {
// +optional
Wait bool `json:"wait,omitempty"`
// Components specifies relative paths to specifications of other Components.
// +optional
Components []string `json:"components,omitempty"`
// Deprecated: Not used in v1beta2.
// +kubebuilder:validation:Enum=none;client;server
// +optional
Validation string `json:"validation,omitempty"`
}
// CommonMetadata defines the common labels and annotations.
type CommonMetadata struct {
// Annotations to be added to the object's metadata.
// Components specifies relative paths to specifications of other Components
// +optional
Annotations map[string]string `json:"annotations,omitempty"`
// Labels to be added to the object's metadata.
// +optional
Labels map[string]string `json:"labels,omitempty"`
Components []string `json:"components,omitempty"`
}
// Decryption defines how decryption is handled for Kubernetes manifests.
@ -243,7 +227,7 @@ type KustomizationStatus struct {
Conditions []metav1.Condition `json:"conditions,omitempty"`
// The last successfully applied revision.
// Equals the Revision of the applied Artifact from the referenced Source.
// The revision format for Git sources is <branch|tag>/<commit-sha>.
// +optional
LastAppliedRevision string `json:"lastAppliedRevision,omitempty"`
@ -304,13 +288,14 @@ func (in *Kustomization) GetStatusConditions() *[]metav1.Condition {
}
// +genclient
// +genclient:Namespaced
// +kubebuilder:storageversion
// +kubebuilder:object:root=true
// +kubebuilder:resource:shortName=ks
// +kubebuilder:subresource:status
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description=""
// +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].status",description=""
// +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].message",description=""
// +kubebuilder:deprecatedversion:warning="v1beta2 Kustomization is deprecated, upgrade to v1"
// Kustomization is the Schema for the kustomizations API.
type Kustomization struct {
@ -334,3 +319,11 @@ type KustomizationList struct {
func init() {
SchemeBuilder.Register(&Kustomization{}, &KustomizationList{})
}
func trimString(str string, limit int) string {
if len(str) <= limit {
return str
}
return str[0:limit] + "..."
}

View File

@ -1,7 +1,8 @@
//go:build !ignore_autogenerated
// +build !ignore_autogenerated
/*
Copyright 2023 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.
@ -28,35 +29,6 @@ import (
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 *CrossNamespaceSourceReference) DeepCopyInto(out *CrossNamespaceSourceReference) {
*out = *in
@ -154,11 +126,6 @@ func (in *KustomizationList) DeepCopyObject() runtime.Object {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *KustomizationSpec) DeepCopyInto(out *KustomizationSpec) {
*out = *in
if in.CommonMetadata != nil {
in, out := &in.CommonMetadata, &out.CommonMetadata
*out = new(CommonMetadata)
(*in).DeepCopyInto(*out)
}
if in.DependsOn != nil {
in, out := &in.DependsOn, &out.DependsOn
*out = make([]meta.NamespacedObjectReference, len(*in))
@ -178,7 +145,7 @@ func (in *KustomizationSpec) DeepCopyInto(out *KustomizationSpec) {
if in.KubeConfig != nil {
in, out := &in.KubeConfig, &out.KubeConfig
*out = new(meta.KubeConfigReference)
(*in).DeepCopyInto(*out)
**out = **in
}
if in.PostBuild != nil {
in, out := &in.PostBuild, &out.PostBuild
@ -193,9 +160,7 @@ func (in *KustomizationSpec) DeepCopyInto(out *KustomizationSpec) {
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])
}
copy(*out, *in)
}
if in.PatchesStrategicMerge != nil {
in, out := &in.PatchesStrategicMerge, &out.PatchesStrategicMerge

View File

@ -2,8 +2,8 @@ apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: kustomize-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.34.0/source-controller.crds.yaml
- https://github.com/fluxcd/source-controller/releases/download/v0.34.0/source-controller.deployment.yaml
- ../crd
- ../rbac
- ../manager

View File

@ -5,4 +5,4 @@ resources:
images:
- name: fluxcd/kustomize-controller
newName: fluxcd/kustomize-controller
newTag: v1.6.0
newTag: v0.33.0

View File

@ -2,6 +2,7 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
creationTimestamp: null
name: manager-role
rules:
- apiGroups:
@ -21,12 +22,6 @@ rules:
verbs:
- create
- patch
- apiGroups:
- ""
resources:
- serviceaccounts/token
verbs:
- create
- apiGroups:
- kustomize.toolkit.fluxcd.io
resources:

View File

@ -1,4 +1,4 @@
apiVersion: kustomize.toolkit.fluxcd.io/v1
apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
kind: Kustomization
metadata:
name: webapp-dev
@ -12,7 +12,7 @@ spec:
wait: true
timeout: 2m
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
kind: Kustomization
metadata:
name: webapp-production

View File

@ -1,4 +1,4 @@
apiVersion: source.toolkit.fluxcd.io/v1
apiVersion: source.toolkit.fluxcd.io/v1beta1
kind: GitRepository
metadata:
name: webapp-latest
@ -8,7 +8,7 @@ spec:
ref:
branch: master
---
apiVersion: source.toolkit.fluxcd.io/v1
apiVersion: source.toolkit.fluxcd.io/v1beta1
kind: GitRepository
metadata:
name: webapp-releases

View File

@ -1,4 +1,4 @@
apiVersion: source.toolkit.fluxcd.io/v1
apiVersion: source.toolkit.fluxcd.io/v1beta1
kind: GitRepository
metadata:
name: certs
@ -8,7 +8,7 @@ spec:
ref:
tag: "v1.1.0"
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
kind: Kustomization
metadata:
name: certs

View File

@ -1,4 +1,4 @@
apiVersion: kustomize.toolkit.fluxcd.io/v1
apiVersion: kustomize.toolkit.fluxcd.io/v1beta1
kind: Kustomization
metadata:
name: backend
@ -11,8 +11,9 @@ spec:
sourceRef:
kind: GitRepository
name: webapp
validation: server
healthChecks:
- kind: Deployment
name: backend
namespace: webapp
timeout: 2m
timeout: 2m

View File

@ -1,4 +1,4 @@
apiVersion: kustomize.toolkit.fluxcd.io/v1
apiVersion: kustomize.toolkit.fluxcd.io/v1beta1
kind: Kustomization
metadata:
name: common
@ -9,3 +9,4 @@ spec:
sourceRef:
kind: GitRepository
name: webapp
validation: client

View File

@ -1,4 +1,4 @@
apiVersion: kustomize.toolkit.fluxcd.io/v1
apiVersion: kustomize.toolkit.fluxcd.io/v1beta1
kind: Kustomization
metadata:
name: frontend
@ -12,8 +12,9 @@ spec:
sourceRef:
kind: GitRepository
name: webapp
validation: server
healthChecks:
- kind: Deployment
name: frontend
namespace: webapp
timeout: 2m
timeout: 2m

View File

@ -1,4 +1,4 @@
apiVersion: source.toolkit.fluxcd.io/v1
apiVersion: source.toolkit.fluxcd.io/v1beta1
kind: GitRepository
metadata:
name: webapp
@ -6,4 +6,4 @@ spec:
interval: 10m
url: https://github.com/stefanprodan/podinfo
ref:
semver: ">=6.3.5"
semver: ">=3.2.3"

View File

@ -33,7 +33,7 @@ subjects:
name: gotk-reconciler
namespace: impersonation
---
apiVersion: source.toolkit.fluxcd.io/v1
apiVersion: source.toolkit.fluxcd.io/v1beta1
kind: GitRepository
metadata:
name: podinfo
@ -42,9 +42,9 @@ spec:
interval: 5m
url: https://github.com/stefanprodan/podinfo
ref:
tag: "6.3.5"
tag: "6.3.0"
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
kind: Kustomization
metadata:
name: podinfo

View File

@ -1,4 +1,4 @@
apiVersion: kustomize.toolkit.fluxcd.io/v1
apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
kind: Kustomization
metadata:
name: podinfo
@ -12,7 +12,7 @@ spec:
timeout: 1m
targetNamespace: managed-fields
---
apiVersion: source.toolkit.fluxcd.io/v1
apiVersion: source.toolkit.fluxcd.io/v1beta1
kind: GitRepository
metadata:
name: podinfo
@ -20,4 +20,4 @@ spec:
interval: 5m
url: https://github.com/stefanprodan/podinfo
ref:
semver: "6.3.5"
semver: "6.0.0"

View File

@ -1,4 +1,4 @@
apiVersion: source.toolkit.fluxcd.io/v1
apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: OCIRepository
metadata:
name: oci
@ -7,9 +7,9 @@ spec:
interval: 10m
url: oci://ghcr.io/stefanprodan/manifests/podinfo
ref:
tag: "6.3.5"
tag: "6.3.0"
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
kind: Kustomization
metadata:
name: oci
@ -17,7 +17,7 @@ metadata:
spec:
targetNamespace: oci
interval: 10m
path: "./"
path: "./kustomize"
prune: true
sourceRef:
kind: OCIRepository

View File

@ -1,4 +1,4 @@
apiVersion: kustomize.toolkit.fluxcd.io/v1
apiVersion: kustomize.toolkit.fluxcd.io/v1beta1
kind: Kustomization
metadata:
name: webapp-production
@ -9,6 +9,7 @@ spec:
sourceRef:
kind: GitRepository
name: webapp-releases
validation: client
healthChecks:
- kind: Deployment
name: backend
@ -18,7 +19,7 @@ spec:
namespace: production
timeout: 2m
---
apiVersion: source.toolkit.fluxcd.io/v1
apiVersion: source.toolkit.fluxcd.io/v1beta1
kind: GitRepository
metadata:
name: webapp-releases
@ -26,4 +27,4 @@ spec:
interval: 5m
url: https://github.com/stefanprodan/podinfo
ref:
semver: ">=6.3.5"
semver: ">=3.2.3"

View File

@ -1,4 +1,4 @@
apiVersion: kustomize.toolkit.fluxcd.io/v1
apiVersion: kustomize.toolkit.fluxcd.io/v1beta1
kind: Kustomization
metadata:
name: webapp-staging
@ -9,6 +9,7 @@ spec:
sourceRef:
kind: GitRepository
name: webapp-releases
validation: client
healthChecks:
- kind: Deployment
name: backend
@ -18,7 +19,7 @@ spec:
namespace: staging
timeout: 2m
---
apiVersion: source.toolkit.fluxcd.io/v1
apiVersion: source.toolkit.fluxcd.io/v1beta1
kind: GitRepository
metadata:
name: webapp-latest

View File

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

View File

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package controller
package controllers
import (
"context"
@ -22,17 +22,16 @@ import (
"testing"
"time"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2"
apiacl "github.com/fluxcd/pkg/apis/acl"
"github.com/fluxcd/pkg/apis/meta"
"github.com/fluxcd/pkg/testserver"
sourcev1 "github.com/fluxcd/source-controller/api/v1"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
. "github.com/onsi/gomega"
apimeta "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
)
func TestKustomizationReconciler_NoCrossNamespaceRefs(t *testing.T) {
@ -90,7 +89,7 @@ stringData:
Interval: metav1.Duration{Duration: reconciliationInterval},
Path: "./",
KubeConfig: &meta.KubeConfigReference{
SecretRef: &meta.SecretKeyReference{
SecretRef: meta.SecretKeyReference{
Name: "kubeconfig",
},
},
@ -115,7 +114,7 @@ stringData:
return resultK.Status.LastAppliedRevision == revision
}, timeout, time.Second).Should(BeTrue())
g.Expect(readyCondition.Reason).To(Equal(meta.ReconciliationSucceededReason))
g.Expect(readyCondition.Reason).To(Equal(kustomizev1.ReconciliationSucceededReason))
})
t.Run("fails to reconcile from cross-namespace source", func(t *testing.T) {

View File

@ -0,0 +1,229 @@
/*
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.
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"
"os"
"os/exec"
"testing"
"time"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2"
"github.com/fluxcd/pkg/apis/meta"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
"github.com/hashicorp/vault/api"
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
)
func TestKustomizationReconciler_Decryptor(t *testing.T) {
g := NewWithT(t)
cli, err := api.NewClient(api.DefaultConfig())
g.Expect(err).NotTo(HaveOccurred(), "failed to create vault client")
// create a master key on the vault transit engine
path, data := "sops/keys/firstkey", map[string]interface{}{"type": "rsa-4096"}
_, err = cli.Logical().Write(path, data)
g.Expect(err).NotTo(HaveOccurred(), "failed to write key")
// encrypt the testdata vault secret
cmd := exec.Command("sops", "--hc-vault-transit", cli.Address()+"/v1/sops/keys/firstkey", "--encrypt", "--encrypted-regex", "^(data|stringData)$", "--in-place", "./testdata/sops/secret.vault.yaml")
err = cmd.Run()
g.Expect(err).NotTo(HaveOccurred(), "failed to encrypt file")
// defer the testdata vault secret decryption, to leave a clean testdata vault secret
defer func() {
cmd := exec.Command("sops", "--hc-vault-transit", cli.Address()+"/v1/sops/keys/firstkey", "--decrypt", "--encrypted-regex", "^(data|stringData)$", "--in-place", "./testdata/sops/secret.vault.yaml")
err = cmd.Run()
}()
id := "sops-" + randStringRunes(5)
err = createNamespace(id)
g.Expect(err).NotTo(HaveOccurred(), "failed to create test namespace")
err = createKubeConfigSecret(id)
g.Expect(err).NotTo(HaveOccurred(), "failed to create kubeconfig secret")
artifactName := "sops-" + randStringRunes(5)
artifactChecksum, err := testServer.ArtifactFromDir("testdata/sops", artifactName)
g.Expect(err).ToNot(HaveOccurred())
overlayArtifactName := "sops-" + randStringRunes(5)
overlayChecksum, err := testServer.ArtifactFromDir("testdata/test-dotenv", overlayArtifactName)
g.Expect(err).ToNot(HaveOccurred())
repositoryName := types.NamespacedName{
Name: fmt.Sprintf("sops-%s", randStringRunes(5)),
Namespace: id,
}
overlayRepositoryName := types.NamespacedName{
Name: fmt.Sprintf("sops-%s", randStringRunes(5)),
Namespace: id,
}
err = applyGitRepository(repositoryName, artifactName, "main/"+artifactChecksum)
g.Expect(err).NotTo(HaveOccurred())
err = applyGitRepository(overlayRepositoryName, overlayArtifactName, "main/"+overlayChecksum)
g.Expect(err).NotTo(HaveOccurred())
pgpKey, err := os.ReadFile("testdata/sops/pgp.asc")
g.Expect(err).ToNot(HaveOccurred())
ageKey, err := os.ReadFile("testdata/sops/age.txt")
g.Expect(err).ToNot(HaveOccurred())
sopsSecretKey := types.NamespacedName{
Name: "sops-" + randStringRunes(5),
Namespace: id,
}
sopsSecret := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: sopsSecretKey.Name,
Namespace: sopsSecretKey.Namespace,
},
StringData: map[string]string{
"pgp.asc": string(pgpKey),
"age.agekey": string(ageKey),
"sops.vault-token": "secret",
},
}
g.Expect(k8sClient.Create(context.Background(), sopsSecret)).To(Succeed())
kustomizationKey := types.NamespacedName{
Name: fmt.Sprintf("sops-%s", randStringRunes(5)),
Namespace: id,
}
kustomization := &kustomizev1.Kustomization{
ObjectMeta: metav1.ObjectMeta{
Name: kustomizationKey.Name,
Namespace: kustomizationKey.Namespace,
},
Spec: kustomizev1.KustomizationSpec{
Interval: metav1.Duration{Duration: 2 * time.Minute},
Path: "./",
KubeConfig: &meta.KubeConfigReference{
SecretRef: meta.SecretKeyReference{
Name: "kubeconfig",
},
},
SourceRef: kustomizev1.CrossNamespaceSourceReference{
Name: repositoryName.Name,
Namespace: repositoryName.Namespace,
Kind: sourcev1.GitRepositoryKind,
},
Decryption: &kustomizev1.Decryption{
Provider: "sops",
SecretRef: &meta.LocalObjectReference{
Name: sopsSecretKey.Name,
},
},
TargetNamespace: id,
},
}
g.Expect(k8sClient.Create(context.TODO(), kustomization)).To(Succeed())
g.Eventually(func() bool {
var obj kustomizev1.Kustomization
_ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(kustomization), &obj)
return obj.Status.LastAppliedRevision == "main/"+artifactChecksum
}, timeout, time.Second).Should(BeTrue())
overlayKustomizationName := fmt.Sprintf("sops-%s", randStringRunes(5))
overlayKs := kustomization.DeepCopy()
overlayKs.ResourceVersion = ""
overlayKs.Name = overlayKustomizationName
overlayKs.Spec.SourceRef.Name = overlayRepositoryName.Name
overlayKs.Spec.SourceRef.Namespace = overlayRepositoryName.Namespace
overlayKs.Spec.Path = "./testdata/test-dotenv/overlays"
g.Expect(k8sClient.Create(context.TODO(), overlayKs)).To(Succeed())
g.Eventually(func() bool {
var obj kustomizev1.Kustomization
_ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(overlayKs), &obj)
return obj.Status.LastAppliedRevision == "main/"+overlayChecksum
}, timeout, time.Second).Should(BeTrue())
t.Run("decrypts SOPS secrets", func(t *testing.T) {
g := NewWithT(t)
var pgpSecret corev1.Secret
g.Expect(k8sClient.Get(context.TODO(), types.NamespacedName{Name: "sops-pgp", Namespace: id}, &pgpSecret)).To(Succeed())
g.Expect(pgpSecret.Data["secret"]).To(Equal([]byte(`my-sops-pgp-secret`)))
var ageSecret corev1.Secret
g.Expect(k8sClient.Get(context.TODO(), types.NamespacedName{Name: "sops-age", Namespace: id}, &ageSecret)).To(Succeed())
g.Expect(ageSecret.Data["secret"]).To(Equal([]byte(`my-sops-age-secret`)))
var daySecret corev1.Secret
g.Expect(k8sClient.Get(context.TODO(), types.NamespacedName{Name: "sops-day", Namespace: id}, &daySecret)).To(Succeed())
g.Expect(string(daySecret.Data["secret"])).To(Equal("day=Tuesday\n"))
var yearSecret corev1.Secret
g.Expect(k8sClient.Get(context.TODO(), types.NamespacedName{Name: "sops-year", Namespace: id}, &yearSecret)).To(Succeed())
g.Expect(string(yearSecret.Data["year"])).To(Equal("2017"))
var unencryptedSecret corev1.Secret
g.Expect(k8sClient.Get(context.TODO(), types.NamespacedName{Name: "unencrypted-sops-year", Namespace: id}, &unencryptedSecret)).To(Succeed())
g.Expect(string(unencryptedSecret.Data["year"])).To(Equal("2021"))
var year1Secret corev1.Secret
g.Expect(k8sClient.Get(context.TODO(), types.NamespacedName{Name: "sops-year1", Namespace: id}, &year1Secret)).To(Succeed())
g.Expect(string(year1Secret.Data["year"])).To(Equal("year1"))
var year2Secret corev1.Secret
g.Expect(k8sClient.Get(context.TODO(), types.NamespacedName{Name: "sops-year2", Namespace: id}, &year2Secret)).To(Succeed())
g.Expect(string(year2Secret.Data["year"])).To(Equal("year2"))
var encodedSecret corev1.Secret
g.Expect(k8sClient.Get(context.TODO(), types.NamespacedName{Name: "sops-month", Namespace: id}, &encodedSecret)).To(Succeed())
g.Expect(string(encodedSecret.Data["month.yaml"])).To(Equal("month: May\n"))
var hcvaultSecret corev1.Secret
g.Expect(k8sClient.Get(context.TODO(), types.NamespacedName{Name: "sops-hcvault", Namespace: id}, &hcvaultSecret)).To(Succeed())
g.Expect(string(hcvaultSecret.Data["secret"])).To(Equal("my-sops-vault-secret\n"))
})
t.Run("does not emit change events for identical secrets", func(t *testing.T) {
g := NewWithT(t)
resultK := &kustomizev1.Kustomization{}
revision := "v2.0.0"
err = applyGitRepository(repositoryName, artifactName, revision)
g.Expect(err).NotTo(HaveOccurred())
g.Eventually(func() bool {
_ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(kustomization), resultK)
return resultK.Status.LastAppliedRevision == revision
}, timeout, time.Second).Should(BeTrue())
events := getEvents(resultK.GetName(), map[string]string{"kustomize.toolkit.fluxcd.io/revision": revision})
g.Expect(len(events)).To(BeIdenticalTo(1))
g.Expect(events[0].Message).Should(ContainSubstring("Reconciliation finished"))
g.Expect(events[0].Message).ShouldNot(ContainSubstring("configured"))
})
}

View File

@ -0,0 +1,186 @@
/*
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.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package controllers
import (
"context"
"fmt"
"testing"
"time"
"github.com/fluxcd/pkg/apis/meta"
"github.com/fluxcd/pkg/testserver"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
. "github.com/onsi/gomega"
apimeta "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2"
)
func TestKustomizationReconciler_DependsOn(t *testing.T) {
g := NewWithT(t)
id := "dep-" + randStringRunes(5)
revision := "v1.0.0"
err := createNamespace(id)
g.Expect(err).NotTo(HaveOccurred(), "failed to create test namespace")
err = createKubeConfigSecret(id)
g.Expect(err).NotTo(HaveOccurred(), "failed to create kubeconfig secret")
manifests := func(name string, data string) []testserver.File {
return []testserver.File{
{
Name: "config.yaml",
Body: fmt.Sprintf(`---
apiVersion: v1
kind: ConfigMap
metadata:
name: %[1]s
data:
key: "%[2]s"
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: "v2-%[1]s"
namespace: "%[2]s"
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: test
minReplicas: 1
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
- type: Pods
pods:
metric:
name: packets-per-second
target:
type: AverageValue
averageValue: 1k
- type: Object
object:
metric:
name: requests-per-second
describedObject:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
name: main-route
target:
type: Value
value: 10k
`, name, data),
},
}
}
artifact, err := testServer.ArtifactFromFiles(manifests(id, id))
g.Expect(err).NotTo(HaveOccurred())
repositoryName := types.NamespacedName{
Name: fmt.Sprintf("dep-%s", randStringRunes(5)),
Namespace: id,
}
kustomizationKey := types.NamespacedName{
Name: fmt.Sprintf("dep-%s", randStringRunes(5)),
Namespace: id,
}
kustomization := &kustomizev1.Kustomization{
ObjectMeta: metav1.ObjectMeta{
Name: kustomizationKey.Name,
Namespace: kustomizationKey.Namespace,
},
Spec: kustomizev1.KustomizationSpec{
Interval: metav1.Duration{Duration: reconciliationInterval},
Path: "./",
KubeConfig: &meta.KubeConfigReference{
SecretRef: meta.SecretKeyReference{
Name: "kubeconfig",
},
},
SourceRef: kustomizev1.CrossNamespaceSourceReference{
Name: repositoryName.Name,
Namespace: repositoryName.Namespace,
Kind: sourcev1.GitRepositoryKind,
},
TargetNamespace: id,
Prune: true,
},
}
g.Expect(k8sClient.Create(context.Background(), kustomization)).To(Succeed())
resultK := &kustomizev1.Kustomization{}
g.Eventually(func() bool {
_ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(kustomization), resultK)
return apimeta.FindStatusCondition(resultK.Status.Conditions, meta.ReadyCondition) != nil
}, timeout, time.Second).Should(BeTrue())
t.Run("fails due to source not found", func(t *testing.T) {
g := NewWithT(t)
g.Eventually(func() bool {
_ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(kustomization), resultK)
ready := apimeta.FindStatusCondition(resultK.Status.Conditions, meta.ReadyCondition)
return ready.Reason == kustomizev1.ArtifactFailedReason
}, timeout, time.Second).Should(BeTrue())
})
t.Run("reconciles when source is found", func(t *testing.T) {
g := NewWithT(t)
err = applyGitRepository(repositoryName, artifact, revision)
g.Expect(err).NotTo(HaveOccurred())
g.Eventually(func() bool {
_ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(kustomization), resultK)
ready := apimeta.FindStatusCondition(resultK.Status.Conditions, meta.ReadyCondition)
return ready.Reason == kustomizev1.ReconciliationSucceededReason
}, timeout, time.Second).Should(BeTrue())
})
t.Run("fails due to dependency not found", func(t *testing.T) {
g := NewWithT(t)
g.Eventually(func() error {
_ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(kustomization), resultK)
resultK.Spec.DependsOn = []meta.NamespacedObjectReference{
{
Namespace: id,
Name: "root",
},
}
return k8sClient.Update(context.Background(), resultK)
}, timeout, time.Second).Should(BeNil())
g.Eventually(func() bool {
_ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(kustomization), resultK)
ready := apimeta.FindStatusCondition(resultK.Status.Conditions, meta.ReadyCondition)
return ready.Reason == kustomizev1.DependencyNotReadyReason
}, timeout, time.Second).Should(BeTrue())
})
}

View File

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package controller
package controllers
import (
"context"
@ -25,14 +25,14 @@ import (
"github.com/fluxcd/pkg/apis/meta"
"github.com/fluxcd/pkg/testserver"
sourcev1 "github.com/fluxcd/source-controller/api/v1"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
. "github.com/onsi/gomega"
apimeta "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2"
)
func TestKustomizationReconciler_ArtifactDownload(t *testing.T) {
@ -86,7 +86,7 @@ stringData:
Interval: metav1.Duration{Duration: reconciliationInterval},
Path: "./",
KubeConfig: &meta.KubeConfigReference{
SecretRef: &meta.SecretKeyReference{
SecretRef: meta.SecretKeyReference{
Name: "kubeconfig",
},
},

View File

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package controller
package controllers
import (
"context"
@ -22,17 +22,16 @@ import (
"testing"
"time"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2"
"github.com/fluxcd/pkg/apis/meta"
"github.com/fluxcd/pkg/testserver"
sourcev1 "github.com/fluxcd/source-controller/api/v1"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
apimeta "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
)
func TestKustomizationReconciler_Force(t *testing.T) {
@ -87,7 +86,7 @@ stringData:
Interval: metav1.Duration{Duration: reconciliationInterval},
Path: "./",
KubeConfig: &meta.KubeConfigReference{
SecretRef: &meta.SecretKeyReference{
SecretRef: meta.SecretKeyReference{
Name: "kubeconfig",
},
},
@ -144,7 +143,7 @@ stringData:
events := getEvents(resultK.GetName(), map[string]string{"kustomize.toolkit.fluxcd.io/revision": revision})
g.Expect(len(events) > 0).To(BeTrue())
g.Expect(events[0].Type).To(BeIdenticalTo("Warning"))
g.Expect(events[0].Message).To(ContainSubstring("field is immutable"))
g.Expect(events[0].Message).To(ContainSubstring("invalid, error: secret is immutable"))
})
})
@ -169,6 +168,6 @@ stringData:
kstatusCheck.CheckErr(ctx, resultK)
g.Expect(apimeta.IsStatusConditionTrue(resultK.Status.Conditions, meta.HealthyCondition)).To(BeTrue())
g.Expect(apimeta.IsStatusConditionTrue(resultK.Status.Conditions, kustomizev1.HealthyCondition)).To(BeTrue())
})
}

View File

@ -17,13 +17,14 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package controller
package controllers
import (
"archive/tar"
"compress/gzip"
"context"
"crypto/sha1"
"crypto/sha256"
"embed"
"errors"
"fmt"
@ -40,7 +41,6 @@ import (
securejoin "github.com/cyphar/filepath-securejoin"
"github.com/hashicorp/vault/api"
"github.com/opencontainers/go-digest"
"github.com/ory/dockertest/v3"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -57,11 +57,10 @@ import (
"github.com/fluxcd/pkg/runtime/controller"
"github.com/fluxcd/pkg/runtime/testenv"
"github.com/fluxcd/pkg/testserver"
sourcev1 "github.com/fluxcd/source-controller/api/v1"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
fuzz "github.com/AdaLogics/go-fuzz-headers"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2"
)
var (
@ -76,12 +75,12 @@ var (
debugMode = os.Getenv("DEBUG_TEST") != ""
)
const vaultVersion = "1.13.2"
const vaultVersion = "1.2.2"
const defaultBinVersion = "1.24"
//go:embed testdata/crd/*.yaml
//go:embed testdata/sops/keys/pgp.asc
//go:embed testdata/sops/keys/age.txt
//go:embed testdata/sops/pgp.asc
//go:embed testdata/sops/age.txt
var testFiles embed.FS
// FuzzControllers implements a fuzzer that targets the Kustomize controller.
@ -125,9 +124,8 @@ func Fuzz_Controllers(f *testing.F) {
reconciler := &KustomizationReconciler{
ControllerName: controllerName,
Client: testEnv,
Mapper: testEnv.GetRESTMapper(),
}
if err := (reconciler).SetupWithManager(ctx, testEnv, KustomizationReconcilerOptions{}); err != nil {
if err := (reconciler).SetupWithManager(testEnv, KustomizationReconcilerOptions{MaxConcurrentReconciles: 1}); err != nil {
panic(fmt.Sprintf("Failed to start GitRepositoryReconciler: %v", err))
}
}, func() error {
@ -183,11 +181,11 @@ func Fuzz_Controllers(f *testing.F) {
if err != nil {
return err
}
pgpKey, err := testFiles.ReadFile("testdata/sops/keys/pgp.asc")
pgpKey, err := testFiles.ReadFile("testdata/sops/pgp.asc")
if err != nil {
return err
}
ageKey, err := testFiles.ReadFile("testdata/sops/keys/age.txt")
ageKey, err := testFiles.ReadFile("testdata/sops/age.txt")
if err != nil {
return err
}
@ -232,7 +230,7 @@ func Fuzz_Controllers(f *testing.F) {
Spec: kustomizev1.KustomizationSpec{
Path: "./",
KubeConfig: &meta.KubeConfigReference{
SecretRef: &meta.SecretKeyReference{
SecretRef: meta.SecretKeyReference{
Name: "kubeconfig",
},
},
@ -365,7 +363,7 @@ func createFiles(f *fuzz.ConsumeFuzzer, rootDir string) error {
continue // some errors here are not permanent, so we can try again with different values
}
err = os.MkdirAll(dirPath, 0o750)
err = os.MkdirAll(dirPath, 0o755)
if err != nil {
if noOfCreatedFiles > 0 {
return nil
@ -434,7 +432,7 @@ func ensureDependencies() error {
// as it is being consumed directly from the embed.FS.
embedDirs := []string{"testdata/crd"}
for _, dir := range embedDirs {
err := os.MkdirAll(dir, 0o750)
err := os.MkdirAll(dir, 0o755)
if err != nil {
return fmt.Errorf("mkdir %s: %v", dir, err)
}
@ -453,7 +451,7 @@ func ensureDependencies() error {
return fmt.Errorf("reading embedded file %s: %v", fileName, err)
}
os.WriteFile(fileName, data, 0o600)
os.WriteFile(fileName, data, 0o644)
if err != nil {
return fmt.Errorf("writing %s: %v", fileName, err)
}
@ -600,7 +598,7 @@ func applyGitRepository(objKey client.ObjectKey, artifactName string, revision s
}
b, _ := os.ReadFile(filepath.Join(testServer.Root(), artifactName))
dig := digest.SHA256.FromBytes(b)
checksum := fmt.Sprintf("%x", sha256.Sum256(b))
url := fmt.Sprintf("%s/%s", testServer.URL(), artifactName)
@ -617,7 +615,7 @@ func applyGitRepository(objKey client.ObjectKey, artifactName string, revision s
Path: url,
URL: url,
Revision: revision,
Digest: dig.String(),
Checksum: checksum,
LastUpdateTime: metav1.Now(),
},
}
@ -728,7 +726,7 @@ func createArtifact(artifactServer *testserver.ArtifactServer, fixture, path str
return "", err
}
if err := os.Chmod(f.Name(), 0o600); err != nil {
if err := os.Chmod(f.Name(), 0644); err != nil {
return "", err
}

View File

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package controller
package controllers
import (
"context"
@ -22,9 +22,10 @@ import (
"testing"
"time"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2"
"github.com/fluxcd/pkg/apis/meta"
"github.com/fluxcd/pkg/testserver"
sourcev1 "github.com/fluxcd/source-controller/api/v1"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
rbacv1 "k8s.io/api/rbac/v1"
@ -33,8 +34,6 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
)
func TestKustomizationReconciler_Impersonation(t *testing.T) {
@ -93,7 +92,7 @@ data:
Interval: metav1.Duration{Duration: time.Minute},
Path: "./",
KubeConfig: &meta.KubeConfigReference{
SecretRef: &meta.SecretKeyReference{
SecretRef: meta.SecretKeyReference{
Name: "kubeconfig",
},
},
@ -119,7 +118,7 @@ data:
return resultK.Status.LastAppliedRevision == revision
}, timeout, time.Second).Should(BeTrue())
g.Expect(readyCondition.Reason).To(Equal(meta.ReconciliationSucceededReason))
g.Expect(readyCondition.Reason).To(Equal(kustomizev1.ReconciliationSucceededReason))
})
t.Run("fails to reconcile impersonating the default service account", func(t *testing.T) {
@ -131,7 +130,7 @@ data:
g.Eventually(func() bool {
_ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(kustomization), resultK)
readyCondition = apimeta.FindStatusCondition(resultK.Status.Conditions, meta.ReadyCondition)
return readyCondition.Reason == meta.ReconciliationFailedReason
return readyCondition.Reason == kustomizev1.ReconciliationFailedReason
}, timeout, time.Second).Should(BeTrue())
g.Expect(readyCondition.Message).To(ContainSubstring("system:serviceaccount:%s:default", id))
@ -187,7 +186,7 @@ data:
return resultK.Status.LastAppliedRevision == revision
}, timeout, time.Second).Should(BeTrue())
g.Expect(readyCondition.Reason).To(Equal(meta.ReconciliationSucceededReason))
g.Expect(readyCondition.Reason).To(Equal(kustomizev1.ReconciliationSucceededReason))
})
t.Run("can finalize impersonating service account", func(t *testing.T) {
@ -261,7 +260,7 @@ data:
Interval: metav1.Duration{Duration: time.Minute},
Path: "./",
KubeConfig: &meta.KubeConfigReference{
SecretRef: &meta.SecretKeyReference{
SecretRef: meta.SecretKeyReference{
Name: secretName,
Key: secretKey,
},
@ -288,7 +287,7 @@ data:
return apimeta.IsStatusConditionFalse(resultK.Status.Conditions, meta.ReadyCondition)
}, timeout, time.Second).Should(BeTrue())
g.Expect(readyCondition.Reason).To(Equal(meta.ReconciliationFailedReason))
g.Expect(readyCondition.Reason).To(Equal(kustomizev1.ReconciliationFailedReason))
g.Expect(readyCondition.Message).To(ContainSubstring(`Secret "%s" not found`, secretName))
})
@ -314,7 +313,7 @@ data:
return resultK.Status.LastAppliedRevision == revision
}, timeout, time.Second).Should(BeTrue())
g.Expect(readyCondition.Reason).To(Equal(meta.ReconciliationSucceededReason))
g.Expect(readyCondition.Reason).To(Equal(kustomizev1.ReconciliationSucceededReason))
})
}

View File

@ -0,0 +1,90 @@
/*
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"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2"
"github.com/fluxcd/pkg/runtime/dependency"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
)
func (r *KustomizationReconciler) requestsForRevisionChangeOf(indexKey string) func(obj client.Object) []reconcile.Request {
return func(obj client.Object) []reconcile.Request {
repo, ok := obj.(interface {
GetArtifact() *sourcev1.Artifact
})
if !ok {
panic(fmt.Sprintf("Expected an object conformed with GetArtifact() method, but got a %T", obj))
}
// If we do not have an artifact, we have no requests to make
if repo.GetArtifact() == nil {
return nil
}
ctx := context.Background()
var list kustomizev1.KustomizationList
if err := r.List(ctx, &list, client.MatchingFields{
indexKey: client.ObjectKeyFromObject(obj).String(),
}); err != nil {
return nil
}
var dd []dependency.Dependent
for _, d := range list.Items {
// If the revision of the artifact equals to the last attempted revision,
// we should not make a request for this Kustomization
if repo.GetArtifact().Revision == d.Status.LastAttemptedRevision {
continue
}
dd = append(dd, d.DeepCopy())
}
sorted, err := dependency.Sort(dd)
if err != nil {
return nil
}
reqs := make([]reconcile.Request, len(sorted))
for i := range sorted {
reqs[i].NamespacedName.Name = sorted[i].Name
reqs[i].NamespacedName.Namespace = sorted[i].Namespace
}
return reqs
}
}
func (r *KustomizationReconciler) indexBy(kind string) func(o client.Object) []string {
return func(o client.Object) []string {
k, ok := o.(*kustomizev1.Kustomization)
if !ok {
panic(fmt.Sprintf("Expected a Kustomization, got %T", o))
}
if k.Spec.SourceRef.Kind == kind {
namespace := k.GetNamespace()
if k.Spec.SourceRef.Namespace != "" {
namespace = k.Spec.SourceRef.Namespace
}
return []string{fmt.Sprintf("%s/%s", namespace, k.Spec.SourceRef.Name)}
}
return nil
}
}

View File

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package controller
package controllers
import (
"context"
@ -25,18 +25,18 @@ import (
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime/schema"
"sigs.k8s.io/cli-utils/pkg/object"
"github.com/fluxcd/cli-utils/pkg/object"
"github.com/fluxcd/pkg/apis/meta"
"github.com/fluxcd/pkg/testserver"
sourcev1 "github.com/fluxcd/source-controller/api/v1"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
. "github.com/onsi/gomega"
apimeta "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2"
)
func TestKustomizationReconciler_Inventory(t *testing.T) {
@ -97,7 +97,7 @@ stringData:
Interval: metav1.Duration{Duration: 2 * time.Minute},
Path: "./",
KubeConfig: &meta.KubeConfigReference{
SecretRef: &meta.SecretKeyReference{
SecretRef: meta.SecretKeyReference{
Name: "kubeconfig",
},
},

View File

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package controller
package controllers
import (
"context"
@ -22,17 +22,16 @@ import (
"testing"
"time"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2"
"github.com/fluxcd/pkg/apis/meta"
"github.com/fluxcd/pkg/testserver"
sourcev1 "github.com/fluxcd/source-controller/api/v1"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
)
func TestKustomizationReconciler_Prune(t *testing.T) {
@ -99,7 +98,7 @@ data:
Interval: metav1.Duration{Duration: reconciliationInterval},
Path: "./",
KubeConfig: &meta.KubeConfigReference{
SecretRef: &meta.SecretKeyReference{
SecretRef: meta.SecretKeyReference{
Name: "kubeconfig",
},
},
@ -227,7 +226,7 @@ data:
Interval: metav1.Duration{Duration: reconciliationInterval},
Path: "./",
KubeConfig: &meta.KubeConfigReference{
SecretRef: &meta.SecretKeyReference{
SecretRef: meta.SecretKeyReference{
Name: "kubeconfig",
},
},
@ -385,7 +384,7 @@ data:
Interval: metav1.Duration{Duration: reconciliationInterval},
Path: "./",
KubeConfig: &meta.KubeConfigReference{
SecretRef: &meta.SecretKeyReference{
SecretRef: meta.SecretKeyReference{
Name: "kubeconfig",
},
},

View File

@ -14,223 +14,27 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package controller
package controllers
import (
"context"
"fmt"
"strings"
"testing"
"time"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2"
"github.com/fluxcd/pkg/apis/kustomize"
"github.com/fluxcd/pkg/apis/meta"
"github.com/fluxcd/pkg/testserver"
sourcev1 "github.com/fluxcd/source-controller/api/v1"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
. "github.com/onsi/gomega"
appsv1 "k8s.io/api/apps/v1"
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/types"
"sigs.k8s.io/controller-runtime/pkg/client"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
)
func TestKustomizationReconciler_CommonMetadata(t *testing.T) {
g := NewWithT(t)
id := "cm-" + randStringRunes(5)
revision := "v1.0.0"
resultK := &kustomizev1.Kustomization{}
err := createNamespace(id)
g.Expect(err).NotTo(HaveOccurred(), "failed to create test namespace")
err = createKubeConfigSecret(id)
g.Expect(err).NotTo(HaveOccurred(), "failed to create kubeconfig secret")
manifests := func(name string) []testserver.File {
return []testserver.File{
{
Name: "config.yaml",
Body: fmt.Sprintf(`---
apiVersion: v1
kind: ConfigMap
metadata:
name: %[1]s
annotations:
tenant: test
data:
key: val
`, name),
},
}
}
artifact, err := testServer.ArtifactFromFiles(manifests(id))
g.Expect(err).NotTo(HaveOccurred())
repositoryName := types.NamespacedName{
Name: fmt.Sprintf("cm-%s", randStringRunes(5)),
Namespace: id,
}
err = applyGitRepository(repositoryName, artifact, revision)
g.Expect(err).NotTo(HaveOccurred())
kustomizationKey := types.NamespacedName{
Name: fmt.Sprintf("cm-%s", randStringRunes(5)),
Namespace: id,
}
kustomization := &kustomizev1.Kustomization{
ObjectMeta: metav1.ObjectMeta{
Name: kustomizationKey.Name,
Namespace: kustomizationKey.Namespace,
},
Spec: kustomizev1.KustomizationSpec{
Interval: metav1.Duration{Duration: 2 * time.Minute},
Path: "./",
KubeConfig: &meta.KubeConfigReference{
SecretRef: &meta.SecretKeyReference{
Name: "kubeconfig",
},
},
SourceRef: kustomizev1.CrossNamespaceSourceReference{
Name: repositoryName.Name,
Namespace: repositoryName.Namespace,
Kind: sourcev1.GitRepositoryKind,
},
CommonMetadata: &kustomizev1.CommonMetadata{
Annotations: map[string]string{
"tenant": id,
},
Labels: map[string]string{
"tenant": id,
},
},
TargetNamespace: id,
},
}
g.Expect(k8sClient.Create(context.Background(), kustomization)).To(Succeed())
t.Run("sets labels and annotations", func(t *testing.T) {
g := NewWithT(t)
g.Eventually(func() bool {
_ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(kustomization), resultK)
return isReconcileSuccess(resultK)
}, timeout, time.Second).Should(BeTrue())
kstatusCheck.CheckErr(ctx, resultK)
var cm corev1.ConfigMap
g.Expect(k8sClient.Get(context.Background(), client.ObjectKey{Name: id, Namespace: id}, &cm)).To(Succeed())
g.Expect(cm.GetLabels()).To(HaveKeyWithValue("tenant", id))
g.Expect(cm.GetAnnotations()).To(HaveKeyWithValue("tenant", id))
})
t.Run("removes labels and annotations", func(t *testing.T) {
g := NewWithT(t)
resultK.Spec.CommonMetadata = nil
g.Expect(k8sClient.Update(context.Background(), resultK)).To(Succeed())
g.Eventually(func() bool {
_ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(kustomization), resultK)
return isReconcileSuccess(resultK)
}, timeout, time.Second).Should(BeTrue())
kstatusCheck.CheckErr(ctx, resultK)
var cm corev1.ConfigMap
g.Expect(k8sClient.Get(context.Background(), client.ObjectKey{Name: id, Namespace: id}, &cm)).To(Succeed())
g.Expect(cm.GetLabels()).ToNot(HaveKeyWithValue("tenant", id))
g.Expect(cm.GetAnnotations()).ToNot(HaveKeyWithValue("tenant", id))
})
}
func TestKustomizationReconciler_NamePrefixSuffix(t *testing.T) {
g := NewWithT(t)
id := "np-" + randStringRunes(5)
revision := "v1.0.0"
resultK := &kustomizev1.Kustomization{}
err := createNamespace(id)
g.Expect(err).NotTo(HaveOccurred(), "failed to create test namespace")
err = createKubeConfigSecret(id)
g.Expect(err).NotTo(HaveOccurred(), "failed to create kubeconfig secret")
manifests := func(name string) []testserver.File {
return []testserver.File{
{
Name: "config.yaml",
Body: fmt.Sprintf(`---
apiVersion: v1
kind: ConfigMap
metadata:
name: %[1]s
annotations:
tenant: test
data:
key: val
`, name),
},
}
}
artifact, err := testServer.ArtifactFromFiles(manifests(id))
g.Expect(err).NotTo(HaveOccurred())
repositoryName := types.NamespacedName{
Name: fmt.Sprintf("cm-%s", randStringRunes(5)),
Namespace: id,
}
err = applyGitRepository(repositoryName, artifact, revision)
g.Expect(err).NotTo(HaveOccurred())
kustomizationKey := types.NamespacedName{
Name: fmt.Sprintf("cm-%s", randStringRunes(5)),
Namespace: id,
}
kustomization := &kustomizev1.Kustomization{
ObjectMeta: metav1.ObjectMeta{
Name: kustomizationKey.Name,
Namespace: kustomizationKey.Namespace,
},
Spec: kustomizev1.KustomizationSpec{
Interval: metav1.Duration{Duration: 2 * time.Minute},
Path: "./",
KubeConfig: &meta.KubeConfigReference{
SecretRef: &meta.SecretKeyReference{
Name: "kubeconfig",
},
},
SourceRef: kustomizev1.CrossNamespaceSourceReference{
Name: repositoryName.Name,
Namespace: repositoryName.Namespace,
Kind: sourcev1.GitRepositoryKind,
},
NamePrefix: "prefix-",
NameSuffix: "-suffix",
TargetNamespace: id,
},
}
g.Expect(k8sClient.Create(context.Background(), kustomization)).To(Succeed())
t.Run("sets name prefix and suffix", func(t *testing.T) {
g := NewWithT(t)
g.Eventually(func() bool {
_ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(kustomization), resultK)
return isReconcileSuccess(resultK)
}, timeout, time.Second).Should(BeTrue())
kstatusCheck.CheckErr(ctx, resultK)
name := fmt.Sprintf("prefix-%s-suffix", id)
var cm corev1.ConfigMap
g.Expect(k8sClient.Get(context.Background(), client.ObjectKey{Name: name, Namespace: id}, &cm)).To(Succeed())
})
}
func TestKustomizationReconciler_KustomizeTransformer(t *testing.T) {
g := NewWithT(t)
id := "transformers-" + randStringRunes(5)
@ -270,7 +74,7 @@ func TestKustomizationReconciler_KustomizeTransformer(t *testing.T) {
Interval: metav1.Duration{Duration: reconciliationInterval},
Path: "./",
KubeConfig: &meta.KubeConfigReference{
SecretRef: &meta.SecretKeyReference{
SecretRef: meta.SecretKeyReference{
Name: "kubeconfig",
},
},
@ -393,7 +197,7 @@ func TestKustomizationReconciler_KustomizeTransformerFiles(t *testing.T) {
Interval: metav1.Duration{Duration: reconciliationInterval},
Path: "./",
KubeConfig: &meta.KubeConfigReference{
SecretRef: &meta.SecretKeyReference{
SecretRef: meta.SecretKeyReference{
Name: "kubeconfig",
},
},
@ -512,7 +316,7 @@ func TestKustomizationReconciler_FluxTransformers(t *testing.T) {
Interval: metav1.Duration{Duration: reconciliationInterval},
Path: "./",
KubeConfig: &meta.KubeConfigReference{
SecretRef: &meta.SecretKeyReference{
SecretRef: meta.SecretKeyReference{
Name: "kubeconfig",
},
},
@ -540,14 +344,14 @@ func TestKustomizationReconciler_FluxTransformers(t *testing.T) {
path: /metadata/labels/patch1
value: inline-json
`,
Target: &kustomize.Selector{
Target: kustomize.Selector{
LabelSelector: "app=podinfo",
},
},
{
Patch: `
apiVersion: apps/v1
kind: Deployment
apiVersion: v1
kind: Pod
metadata:
name: podinfo
labels:
@ -555,6 +359,25 @@ metadata:
`,
},
},
PatchesJSON6902: []kustomize.JSON6902Patch{
{
Patch: []kustomize.JSON6902{
{Op: "add", Path: "/metadata/labels/patch3", Value: &apiextensionsv1.JSON{Raw: []byte(`"json6902"`)}},
{Op: "replace", Path: "/spec/replicas", Value: &apiextensionsv1.JSON{Raw: []byte("2")}},
},
Target: kustomize.Selector{
Group: "apps",
Version: "v1",
Kind: "Deployment",
Name: "podinfo",
},
},
},
PatchesStrategicMerge: []apiextensionsv1.JSON{
{
Raw: []byte(`{"kind":"Deployment","apiVersion":"apps/v1","metadata":{"name":"podinfo","labels":{"patch4":"strategic-merge"}}}`),
},
},
},
}
@ -572,6 +395,9 @@ metadata:
t.Run("applies patches", func(t *testing.T) {
g.Expect(deployment.ObjectMeta.Labels["patch1"]).To(Equal("inline-json"))
g.Expect(deployment.ObjectMeta.Labels["patch2"]).To(Equal("inline-yaml"))
g.Expect(deployment.ObjectMeta.Labels["patch3"]).To(Equal("json6902"))
g.Expect(deployment.ObjectMeta.Labels["patch4"]).To(Equal("strategic-merge"))
g.Expect(*deployment.Spec.Replicas).To(Equal(int32(2)))
g.Expect(deployment.Spec.Template.Spec.Containers[0].Image).To(ContainSubstring("5.2.0"))
g.Expect(deployment.Spec.Template.Spec.Containers[1].Image).To(ContainSubstring("sha256:2832f53c577d44753e97b0ed5f00e7e3a06979c9fab77d0e78bdac4b612b14fb"))
})

View File

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package controller
package controllers
import (
"context"
@ -22,14 +22,13 @@ import (
"testing"
"time"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2"
"github.com/fluxcd/pkg/apis/meta"
sourcev1 "github.com/fluxcd/source-controller/api/v1"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
. "github.com/onsi/gomega"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
)
func TestKustomizationReconciler_Validation(t *testing.T) {
@ -80,7 +79,7 @@ func TestKustomizationReconciler_Validation(t *testing.T) {
Interval: metav1.Duration{Duration: 2 * time.Minute},
Path: "./",
KubeConfig: &meta.KubeConfigReference{
SecretRef: &meta.SecretKeyReference{
SecretRef: meta.SecretKeyReference{
Name: "kubeconfig",
},
},
@ -120,7 +119,7 @@ func TestKustomizationReconciler_Validation(t *testing.T) {
g.Eventually(func() bool {
_ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(kustomization), &resultK)
for _, c := range resultK.Status.Conditions {
if c.Reason == meta.BuildFailedReason {
if c.Reason == kustomizev1.BuildFailedReason {
return true
}
}
@ -133,7 +132,7 @@ func TestKustomizationReconciler_Validation(t *testing.T) {
g.Eventually(func() bool {
_ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(overlayKs), &resultK)
for _, c := range resultK.Status.Conditions {
if c.Reason == meta.BuildFailedReason {
if c.Reason == kustomizev1.BuildFailedReason {
return true
}
}

View File

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package controller
package controllers
import (
"context"
@ -23,7 +23,7 @@ import (
"github.com/fluxcd/pkg/apis/meta"
"github.com/fluxcd/pkg/testserver"
sourcev1 "github.com/fluxcd/source-controller/api/v1"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
apimeta "k8s.io/apimachinery/pkg/api/meta"
@ -31,7 +31,7 @@ import (
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2"
)
func TestKustomizationReconciler_Varsub(t *testing.T) {
@ -120,7 +120,7 @@ stringData:
},
Spec: kustomizev1.KustomizationSpec{
KubeConfig: &meta.KubeConfigReference{
SecretRef: &meta.SecretKeyReference{
SecretRef: meta.SecretKeyReference{
Name: "kubeconfig",
},
},
@ -164,7 +164,7 @@ stringData:
g.Eventually(func() bool {
_ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(inputK), resultK)
for _, c := range resultK.Status.Conditions {
if c.Reason == meta.ReconciliationSucceededReason {
if c.Reason == kustomizev1.ReconciliationSucceededReason {
return true
}
}
@ -178,7 +178,7 @@ stringData:
t.Run("sets status", func(t *testing.T) {
g.Expect(resultK.Status.LastAppliedRevision).To(Equal(revision))
g.Expect(apimeta.IsStatusConditionTrue(resultK.Status.Conditions, meta.ReadyCondition)).To(BeTrue())
g.Expect(apimeta.IsStatusConditionTrue(resultK.Status.Conditions, meta.HealthyCondition)).To(BeTrue())
g.Expect(apimeta.IsStatusConditionTrue(resultK.Status.Conditions, kustomizev1.HealthyCondition)).To(BeTrue())
})
t.Run("replaces vars", func(t *testing.T) {
@ -269,7 +269,7 @@ metadata:
},
Spec: kustomizev1.KustomizationSpec{
KubeConfig: &meta.KubeConfigReference{
SecretRef: &meta.SecretKeyReference{
SecretRef: meta.SecretKeyReference{
Name: "kubeconfig",
},
},
@ -315,7 +315,7 @@ metadata:
resultK := &kustomizev1.Kustomization{}
_ = k8sClient.Get(ctx, client.ObjectKeyFromObject(inputK), resultK)
for _, c := range resultK.Status.Conditions {
if c.Reason == meta.ReconciliationSucceededReason {
if c.Reason == kustomizev1.ReconciliationSucceededReason {
return true
}
}
@ -349,224 +349,3 @@ metadata:
g.Expect(resultSA.Labels["shape"]).To(Equal("square"))
})
}
func TestKustomizationReconciler_VarsubNumberBool(t *testing.T) {
ctx := context.Background()
g := NewWithT(t)
id := "vars-" + randStringRunes(5)
revision := "v1.0.0/" + randStringRunes(7)
err := createNamespace(id)
g.Expect(err).NotTo(HaveOccurred(), "failed to create test namespace")
err = createKubeConfigSecret(id)
g.Expect(err).NotTo(HaveOccurred(), "failed to create kubeconfig secret")
manifests := func(name string) []testserver.File {
return []testserver.File{
{
Name: "templates.yaml",
Body: fmt.Sprintf(`
---
apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
name: %[1]s
namespace: %[1]s
labels:
id: ${numberStr}
enabled: ${booleanStr}
annotations:
id: ${q}${number}${q}
enabled: ${q}${boolean}${q}
spec:
interval: ${number}m
url: https://host/repo
---
apiVersion: v1
kind: ConfigMap
metadata:
name: %[1]s
namespace: %[1]s
data:
id: ${q}${number}${q}
text: |
This variable is escaped $${var}
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus at
nisl sem. Nullam nec dui ipsum. Nam vehicula volutpat ipsum, ac fringilla
nisl convallis sed. Aliquam porttitor turpis finibus, finibus velit ut,
imperdiet mauris. Cras nec neque nulla. Maecenas semper nulla et elit
dictum sagittis. Quisque tincidunt non diam non ullamcorper. Curabitur
pretium urna odio, vitae ullamcorper purus mollis sit amet. Nam ac lectus
ac arcu varius feugiat id fringilla massa.
\?
`, name),
},
}
}
artifact, err := testServer.ArtifactFromFiles(manifests(id))
g.Expect(err).NotTo(HaveOccurred())
repositoryName := types.NamespacedName{
Name: randStringRunes(5),
Namespace: id,
}
err = applyGitRepository(repositoryName, artifact, revision)
g.Expect(err).NotTo(HaveOccurred())
inputK := &kustomizev1.Kustomization{
ObjectMeta: metav1.ObjectMeta{
Name: id,
Namespace: id,
},
Spec: kustomizev1.KustomizationSpec{
KubeConfig: &meta.KubeConfigReference{
SecretRef: &meta.SecretKeyReference{
Name: "kubeconfig",
},
},
Interval: metav1.Duration{Duration: reconciliationInterval},
Path: "./",
Prune: true,
SourceRef: kustomizev1.CrossNamespaceSourceReference{
Kind: sourcev1.GitRepositoryKind,
Name: repositoryName.Name,
},
PostBuild: &kustomizev1.PostBuild{
Substitute: map[string]string{
"q": `"`,
"numberStr": "!!str 123",
"number": "123",
"booleanStr": "!!str true",
"boolean": "true",
},
},
Wait: false,
},
}
g.Expect(k8sClient.Create(ctx, inputK)).Should(Succeed())
g.Eventually(func() bool {
resultK := &kustomizev1.Kustomization{}
_ = k8sClient.Get(ctx, client.ObjectKeyFromObject(inputK), resultK)
for _, c := range resultK.Status.Conditions {
if c.Reason == meta.ReconciliationSucceededReason {
return true
}
}
return false
}, timeout, interval).Should(BeTrue())
resultRepo := &sourcev1.GitRepository{}
g.Expect(k8sClient.Get(ctx, types.NamespacedName{Name: id, Namespace: id}, resultRepo)).Should(Succeed())
g.Expect(resultRepo.Labels["id"]).To(Equal("123"))
g.Expect(resultRepo.Annotations["id"]).To(Equal("123"))
g.Expect(resultRepo.Labels["enabled"]).To(Equal("true"))
g.Expect(resultRepo.Annotations["enabled"]).To(Equal("true"))
resultCM := &corev1.ConfigMap{}
g.Expect(k8sClient.Get(ctx, types.NamespacedName{Name: id, Namespace: id}, resultCM)).Should(Succeed())
g.Expect(resultCM.Data["id"]).To(Equal("123"))
g.Expect(resultCM.Data["text"]).To(ContainSubstring(`${var}`))
g.Expect(resultCM.Data["text"]).ToNot(ContainSubstring(`$${var}`))
g.Expect(resultCM.Data["text"]).To(ContainSubstring(`\?`))
}
func TestKustomizationReconciler_VarsubStrict(t *testing.T) {
reconciler.StrictSubstitutions = true
defer func() {
reconciler.StrictSubstitutions = false
}()
ctx := context.Background()
g := NewWithT(t)
id := "vars-" + randStringRunes(5)
revision := "v1.0.0/" + randStringRunes(7)
err := createNamespace(id)
g.Expect(err).NotTo(HaveOccurred(), "failed to create test namespace")
err = createKubeConfigSecret(id)
g.Expect(err).NotTo(HaveOccurred(), "failed to create kubeconfig secret")
manifests := func(name string) []testserver.File {
return []testserver.File{
{
Name: "service-account.yaml",
Body: fmt.Sprintf(`
apiVersion: v1
kind: ServiceAccount
metadata:
name: %[1]s
namespace: %[1]s
labels:
default: ${default:=test}
missing: ${missing}
`, name),
},
}
}
artifact, err := testServer.ArtifactFromFiles(manifests(id))
g.Expect(err).NotTo(HaveOccurred())
repositoryName := types.NamespacedName{
Name: randStringRunes(5),
Namespace: id,
}
err = applyGitRepository(repositoryName, artifact, revision)
g.Expect(err).NotTo(HaveOccurred())
inputK := &kustomizev1.Kustomization{
ObjectMeta: metav1.ObjectMeta{
Name: id,
Namespace: id,
},
Spec: kustomizev1.KustomizationSpec{
KubeConfig: &meta.KubeConfigReference{
SecretRef: &meta.SecretKeyReference{
Name: "kubeconfig",
},
},
Interval: metav1.Duration{Duration: reconciliationInterval},
Path: "./",
Prune: true,
SourceRef: kustomizev1.CrossNamespaceSourceReference{
Kind: sourcev1.GitRepositoryKind,
Name: repositoryName.Name,
},
PostBuild: &kustomizev1.PostBuild{
Substitute: map[string]string{
"test": "test",
},
},
Wait: true,
},
}
g.Expect(k8sClient.Create(ctx, inputK)).Should(Succeed())
var resultK kustomizev1.Kustomization
t.Run("fails to reconcile", func(t *testing.T) {
g.Eventually(func() bool {
_ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(inputK), &resultK)
for _, c := range resultK.Status.Conditions {
if c.Reason == meta.BuildFailedReason {
return true
}
}
return false
}, timeout, interval).Should(BeTrue())
})
ready := apimeta.FindStatusCondition(resultK.Status.Conditions, meta.ReadyCondition)
g.Expect(ready.Message).To(ContainSubstring("variable not set"))
g.Expect(k8sClient.Delete(context.Background(), &resultK)).To(Succeed())
}

View File

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package controller
package controllers
import (
"context"
@ -22,22 +22,19 @@ import (
"testing"
"time"
runtimeClient "github.com/fluxcd/pkg/runtime/client"
. "github.com/onsi/gomega"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
"github.com/fluxcd/pkg/apis/kustomize"
"github.com/fluxcd/pkg/apis/meta"
"github.com/fluxcd/pkg/runtime/conditions"
"github.com/fluxcd/pkg/testserver"
sourcev1 "github.com/fluxcd/source-controller/api/v1"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2"
)
func TestKustomizationReconciler_WaitConditions(t *testing.T) {
@ -46,7 +43,6 @@ func TestKustomizationReconciler_WaitConditions(t *testing.T) {
revision := "v1.0.0"
resultK := &kustomizev1.Kustomization{}
reconcileRequestAt := metav1.Now().String()
timeout := 60 * time.Second
err := createNamespace(id)
g.Expect(err).NotTo(HaveOccurred(), "failed to create test namespace")
@ -105,7 +101,7 @@ parameters:
Interval: metav1.Duration{Duration: 2 * time.Minute},
Path: "./",
KubeConfig: &meta.KubeConfigReference{
SecretRef: &meta.SecretKeyReference{
SecretRef: meta.SecretKeyReference{
Name: "kubeconfig",
},
},
@ -130,8 +126,8 @@ parameters:
}, timeout, time.Second).Should(BeTrue())
logStatus(t, resultK)
g.Expect(conditions.IsTrue(resultK, meta.HealthyCondition)).To(BeTrue())
g.Expect(conditions.GetReason(resultK, meta.HealthyCondition)).To(BeIdenticalTo(meta.SucceededReason))
g.Expect(conditions.IsTrue(resultK, kustomizev1.HealthyCondition)).To(BeTrue())
g.Expect(conditions.GetReason(resultK, kustomizev1.HealthyCondition)).To(BeIdenticalTo(meta.SucceededReason))
g.Expect(resultK.Status.ObservedGeneration).To(BeIdenticalTo(resultK.Generation))
@ -158,12 +154,12 @@ parameters:
g.Eventually(func() bool {
_ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(kustomization), resultK)
return isReconcileRunning(resultK) && conditions.IsUnknown(resultK, meta.HealthyCondition)
return isReconcileRunning(resultK) && conditions.IsUnknown(resultK, kustomizev1.HealthyCondition)
}, timeout, time.Second).Should(BeTrue())
logStatus(t, resultK)
expectedMessage := "Running health checks"
for _, c := range []string{meta.ReconcilingCondition, meta.HealthyCondition} {
for _, c := range []string{meta.ReconcilingCondition, kustomizev1.HealthyCondition} {
g.Expect(conditions.GetReason(resultK, c)).To(BeIdenticalTo(meta.ProgressingReason))
g.Expect(conditions.GetMessage(resultK, c)).To(ContainSubstring(expectedMessage))
g.Expect(conditions.GetObservedGeneration(resultK, c)).To(BeIdenticalTo(resultK.Generation))
@ -178,14 +174,14 @@ parameters:
}, timeout, time.Second).Should(BeTrue())
logStatus(t, resultK)
for _, c := range []string{meta.HealthyCondition, meta.ReadyCondition} {
for _, c := range []string{kustomizev1.HealthyCondition, meta.ReadyCondition} {
g.Expect(conditions.IsFalse(resultK, c)).To(BeTrue())
g.Expect(conditions.GetReason(resultK, c)).To(BeIdenticalTo(meta.HealthCheckFailedReason))
g.Expect(conditions.GetReason(resultK, c)).To(BeIdenticalTo(kustomizev1.HealthCheckFailedReason))
g.Expect(conditions.GetObservedGeneration(resultK, c)).To(BeIdenticalTo(resultK.Generation))
}
expectedMessage := "Running health checks"
g.Expect(conditions.GetReason(resultK, meta.ReconcilingCondition)).To(BeIdenticalTo(meta.ProgressingWithRetryReason))
g.Expect(conditions.GetReason(resultK, meta.ReconcilingCondition)).To(BeIdenticalTo(kustomizev1.ProgressingWithRetryReason))
g.Expect(conditions.GetMessage(resultK, meta.ReconcilingCondition)).To(ContainSubstring(expectedMessage))
g.Expect(resultK.Status.LastHandledReconcileAt).To(BeIdenticalTo(reconcileRequestAt))
@ -215,13 +211,13 @@ parameters:
logStatus(t, resultK)
expectedMessage := "Health check passed"
g.Expect(conditions.IsTrue(resultK, meta.HealthyCondition)).To(BeTrue())
g.Expect(conditions.GetReason(resultK, meta.HealthyCondition)).To(BeIdenticalTo(meta.SucceededReason))
g.Expect(conditions.GetObservedGeneration(resultK, meta.HealthyCondition)).To(BeIdenticalTo(resultK.Generation))
g.Expect(conditions.GetMessage(resultK, meta.HealthyCondition)).To(ContainSubstring(expectedMessage))
g.Expect(conditions.IsTrue(resultK, kustomizev1.HealthyCondition)).To(BeTrue())
g.Expect(conditions.GetReason(resultK, kustomizev1.HealthyCondition)).To(BeIdenticalTo(meta.SucceededReason))
g.Expect(conditions.GetObservedGeneration(resultK, kustomizev1.HealthyCondition)).To(BeIdenticalTo(resultK.Generation))
g.Expect(conditions.GetMessage(resultK, kustomizev1.HealthyCondition)).To(ContainSubstring(expectedMessage))
g.Expect(conditions.IsTrue(resultK, meta.ReadyCondition)).To(BeTrue())
g.Expect(conditions.GetReason(resultK, meta.ReadyCondition)).To(BeIdenticalTo(meta.ReconciliationSucceededReason))
g.Expect(conditions.GetReason(resultK, meta.ReadyCondition)).To(BeIdenticalTo(kustomizev1.ReconciliationSucceededReason))
g.Expect(conditions.GetObservedGeneration(resultK, meta.ReadyCondition)).To(BeIdenticalTo(resultK.Generation))
g.Expect(conditions.GetMessage(resultK, meta.ReadyCondition)).To(BeIdenticalTo(fmt.Sprintf("Applied revision: %s", revision)))
@ -252,7 +248,7 @@ parameters:
logStatus(t, resultK)
g.Expect(isReconcileSuccess(resultK)).To(BeTrue())
g.Expect(conditions.IsTrue(resultK, meta.HealthyCondition)).To(BeTrue())
g.Expect(conditions.IsTrue(resultK, kustomizev1.HealthyCondition)).To(BeTrue())
g.Expect(conditions.GetMessage(resultK, meta.ReadyCondition)).To(BeIdenticalTo(fmt.Sprintf("Applied revision: %s", revision)))
g.Expect(resultK.Status.LastAttemptedRevision).To(BeIdenticalTo(resultK.Status.LastAppliedRevision))
@ -278,171 +274,3 @@ parameters:
}, timeout, time.Second).Should(BeTrue())
})
}
func TestKustomizationReconciler_WaitsForCustomHealthChecks(t *testing.T) {
g := NewWithT(t)
id := "cel-" + randStringRunes(5)
revision := "v1.0.0"
resultK := &kustomizev1.Kustomization{}
timeout := 60 * time.Second
err := createNamespace(id)
g.Expect(err).NotTo(HaveOccurred(), "failed to create test namespace")
err = createKubeConfigSecret(id)
g.Expect(err).NotTo(HaveOccurred(), "failed to create kubeconfig secret")
manifests := func(name string) []testserver.File {
return []testserver.File{
{
Name: "config.yaml",
Body: fmt.Sprintf(`---
apiVersion: v1
kind: ConfigMap
metadata:
name: %[1]s
data: {}
`, name),
},
}
}
artifact, err := testServer.ArtifactFromFiles(manifests(id))
g.Expect(err).NotTo(HaveOccurred())
repositoryName := types.NamespacedName{
Name: fmt.Sprintf("wait-%s", randStringRunes(5)),
Namespace: id,
}
err = applyGitRepository(repositoryName, artifact, revision)
g.Expect(err).NotTo(HaveOccurred())
kustomizationKey := types.NamespacedName{
Name: fmt.Sprintf("wait-%s", randStringRunes(5)),
Namespace: id,
}
kustomization := &kustomizev1.Kustomization{
ObjectMeta: metav1.ObjectMeta{
Name: kustomizationKey.Name,
Namespace: kustomizationKey.Namespace,
},
Spec: kustomizev1.KustomizationSpec{
Interval: metav1.Duration{Duration: 2 * time.Minute},
Path: "./",
KubeConfig: &meta.KubeConfigReference{
SecretRef: &meta.SecretKeyReference{
Name: "kubeconfig",
},
},
SourceRef: kustomizev1.CrossNamespaceSourceReference{
Name: repositoryName.Name,
Namespace: repositoryName.Namespace,
Kind: sourcev1.GitRepositoryKind,
},
TargetNamespace: id,
Prune: true,
Timeout: &metav1.Duration{Duration: time.Second},
Wait: true,
HealthCheckExprs: []kustomize.CustomHealthCheck{{
APIVersion: "v1",
Kind: "ConfigMap",
HealthCheckExpressions: kustomize.HealthCheckExpressions{
InProgress: "has(data.foo.bar)",
Current: "true",
},
}},
},
}
err = k8sClient.Create(context.Background(), kustomization)
g.Expect(err).NotTo(HaveOccurred())
g.Eventually(func() bool {
_ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(kustomization), resultK)
return conditions.IsFalse(resultK, meta.ReadyCondition)
}, timeout, time.Second).Should(BeTrue())
logStatus(t, resultK)
msg := conditions.GetMessage(resultK, meta.ReadyCondition)
g.Expect(msg).
To(ContainSubstring("timeout waiting for: [ConfigMap"))
g.Expect(msg).
To(ContainSubstring("failed to evaluate the CEL expression 'has(data.foo.bar)': no such attribute(s): data.foo.bar"))
}
func TestKustomizationReconciler_RESTMapper(t *testing.T) {
g := NewWithT(t)
id := "rm-" + randStringRunes(5)
resultK := &kustomizev1.Kustomization{}
restMapper, err := runtimeClient.NewDynamicRESTMapper(testEnv.Config)
g.Expect(err).NotTo(HaveOccurred())
err = createNamespace(id)
g.Expect(err).NotTo(HaveOccurred(), "failed to create test namespace")
err = createKubeConfigSecret(id)
g.Expect(err).NotTo(HaveOccurred(), "failed to create kubeconfig secret")
artifactName := "val-" + randStringRunes(5)
artifactChecksum, err := testServer.ArtifactFromDir("testdata/restmapper", artifactName)
g.Expect(err).ToNot(HaveOccurred())
repositoryName := types.NamespacedName{
Name: fmt.Sprintf("val-%s", randStringRunes(5)),
Namespace: id,
}
err = applyGitRepository(repositoryName, artifactName, "main/"+artifactChecksum)
g.Expect(err).NotTo(HaveOccurred())
kustomization := &kustomizev1.Kustomization{}
kustomization.Name = id
kustomization.Namespace = id
kustomization.Spec = kustomizev1.KustomizationSpec{
Interval: metav1.Duration{Duration: 10 * time.Minute},
Prune: true,
Path: "./",
Wait: true,
SourceRef: kustomizev1.CrossNamespaceSourceReference{
Name: repositoryName.Name,
Namespace: repositoryName.Namespace,
Kind: sourcev1.GitRepositoryKind,
},
KubeConfig: &meta.KubeConfigReference{
SecretRef: &meta.SecretKeyReference{
Name: "kubeconfig",
},
},
}
g.Expect(k8sClient.Create(context.Background(), kustomization)).To(Succeed())
g.Eventually(func() bool {
_ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(kustomization), resultK)
return isReconcileSuccess(resultK) && resultK.Status.LastAttemptedRevision == "main/"+artifactChecksum
}, timeout, time.Second).Should(BeTrue())
t.Run("discovers newly registered CRD and preferred version", func(t *testing.T) {
mapping, err := restMapper.RESTMapping(schema.GroupKind{Kind: "ClusterCleanupPolicy", Group: "kyverno.io"})
g.Expect(err).NotTo(HaveOccurred())
g.Expect(mapping.Resource.Version).To(Equal("v2"))
})
t.Run("finalizes object", func(t *testing.T) {
g.Expect(k8sClient.Delete(context.Background(), resultK)).To(Succeed())
g.Eventually(func() bool {
err = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(kustomization), resultK)
return apierrors.IsNotFound(err)
}, timeout, time.Second).Should(BeTrue())
})
t.Run("discovery fails for deleted CRD", func(t *testing.T) {
newMapper, err := runtimeClient.NewDynamicRESTMapper(testEnv.Config)
g.Expect(err).NotTo(HaveOccurred())
_, err = newMapper.RESTMapping(schema.GroupKind{Kind: "ClusterCleanupPolicy", Group: "kyverno.io"})
g.Expect(err).To(HaveOccurred())
})
}

View File

@ -14,13 +14,13 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package controller
package controllers
import (
"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/v1beta2"
)
type SourceRevisionChangePredicate struct {
@ -47,7 +47,7 @@ func (SourceRevisionChangePredicate) Update(e event.UpdateEvent) bool {
}
if oldSource.GetArtifact() != nil && newSource.GetArtifact() != nil &&
!oldSource.GetArtifact().HasRevision(newSource.GetArtifact().Revision) {
oldSource.GetArtifact().Revision != newSource.GetArtifact().Revision {
return true
}

View File

@ -14,10 +14,11 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package controller
package controllers
import (
"context"
"crypto/sha256"
"fmt"
"math/rand"
"os"
@ -26,7 +27,6 @@ import (
"time"
"github.com/hashicorp/vault/api"
"github.com/opencontainers/go-digest"
"github.com/ory/dockertest/v3"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -37,30 +37,31 @@ import (
"sigs.k8s.io/controller-runtime/pkg/envtest"
controllerLog "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
"sigs.k8s.io/controller-runtime/pkg/predicate"
"sigs.k8s.io/yaml"
"github.com/fluxcd/pkg/apis/meta"
"github.com/fluxcd/pkg/runtime/conditions"
kcheck "github.com/fluxcd/pkg/runtime/conditions/check"
"github.com/fluxcd/pkg/runtime/controller"
"github.com/fluxcd/pkg/runtime/metrics"
"github.com/fluxcd/pkg/runtime/testenv"
"github.com/fluxcd/pkg/testserver"
sourcev1 "github.com/fluxcd/source-controller/api/v1"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2"
)
func init() {
rand.Seed(time.Now().UnixNano())
}
const (
timeout = time.Second * 30
interval = time.Second * 1
reconciliationInterval = time.Second * 5
vaultVersion = "1.13.2"
overrideManagerName = "node-fetch"
sopsAgeSecret = "sops-age-secret"
)
const vaultVersion = "1.2.2"
var (
reconciler *KustomizationReconciler
k8sClient client.Client
@ -74,19 +75,16 @@ var (
debugMode = os.Getenv("DEBUG_TEST") != ""
)
func runInContext(registerControllers func(*testenv.Environment), run func() int) (code int) {
func runInContext(registerControllers func(*testenv.Environment), run func() error, crdPath string) error {
var err error
utilruntime.Must(kustomizev1.AddToScheme(scheme.Scheme))
utilruntime.Must(sourcev1.AddToScheme(scheme.Scheme))
utilruntime.Must(kustomizev1.AddToScheme(scheme.Scheme))
if debugMode {
controllerLog.SetLogger(zap.New(zap.WriteTo(os.Stderr), zap.UseDevMode(false)))
}
testEnv = testenv.New(
testenv.WithCRDPath(filepath.Join("..", "..", "config", "crd", "bases")),
testenv.WithMaxConcurrentReconciles(4),
)
testEnv = testenv.New(testenv.WithCRDPath(crdPath))
testServer, err = testserver.NewTempArtifactServer()
if err != nil {
@ -133,7 +131,7 @@ func runInContext(registerControllers func(*testenv.Environment), run func() int
pool.Purge(resource)
}()
code = run()
runErr := run()
if debugMode {
events := &corev1.EventList{}
@ -156,13 +154,15 @@ func runInContext(registerControllers func(*testenv.Environment), run func() int
panic(fmt.Sprintf("Failed to remove storage server dir: %v", err))
}
return code
return runErr
}
func TestMain(m *testing.M) {
code := runInContext(func(testEnv *testenv.Environment) {
code := 0
runInContext(func(testEnv *testenv.Environment) {
controllerName := "kustomize-controller"
testMetricsH = controller.NewMetrics(testEnv, metrics.MustMakeRecorder(), kustomizev1.KustomizationFinalizer)
testMetricsH = controller.MustMakeMetrics(testEnv)
kstatusCheck = kcheck.NewChecker(testEnv.Client,
&kcheck.Conditions{
NegativePolarity: []string{meta.StalledCondition, meta.ReconcilingCondition},
@ -174,23 +174,21 @@ func TestMain(m *testing.M) {
kstatusInProgressCheck = kcheck.NewInProgressChecker(testEnv.Client)
kstatusInProgressCheck.DisableFetch = true
reconciler = &KustomizationReconciler{
ControllerName: controllerName,
Client: testEnv,
Mapper: testEnv.GetRESTMapper(),
APIReader: testEnv,
EventRecorder: testEnv.GetEventRecorderFor(controllerName),
Metrics: testMetricsH,
ConcurrentSSA: 4,
DisallowedFieldManagers: []string{overrideManagerName},
SOPSAgeSecret: sopsAgeSecret,
ControllerName: controllerName,
Client: testEnv,
EventRecorder: testEnv.GetEventRecorderFor(controllerName),
Metrics: testMetricsH,
}
if err := (reconciler).SetupWithManager(ctx, testEnv, KustomizationReconcilerOptions{
if err := (reconciler).SetupWithManager(testEnv, KustomizationReconcilerOptions{
MaxConcurrentReconciles: 4,
DependencyRequeueInterval: 2 * time.Second,
WatchConfigsPredicate: predicate.Not(predicate.Funcs{}),
}); err != nil {
panic(fmt.Sprintf("Failed to start KustomizationReconciler: %v", err))
}
}, m.Run)
}, func() error {
code = m.Run()
return nil
}, filepath.Join("..", "config", "crd", "bases"))
os.Exit(code)
}
@ -207,7 +205,7 @@ func randStringRunes(n int) string {
func isReconcileRunning(k *kustomizev1.Kustomization) bool {
return conditions.IsReconciling(k) &&
conditions.GetReason(k, meta.ReconcilingCondition) != meta.ProgressingWithRetryReason
conditions.GetReason(k, meta.ReconcilingCondition) != kustomizev1.ProgressingWithRetryReason
}
func isReconcileSuccess(k *kustomizev1.Kustomization) bool {
@ -230,7 +228,7 @@ func isReconcileFailure(k *kustomizev1.Kustomization) bool {
return isHandled && conditions.IsReconciling(k) &&
conditions.IsFalse(k, meta.ReadyCondition) &&
conditions.GetObservedGeneration(k, meta.ReadyCondition) == k.Generation &&
conditions.GetReason(k, meta.ReconcilingCondition) == meta.ProgressingWithRetryReason
conditions.GetReason(k, meta.ReconcilingCondition) == kustomizev1.ProgressingWithRetryReason
}
func logStatus(t *testing.T, k *kustomizev1.Kustomization) {
@ -279,29 +277,7 @@ func createKubeConfigSecret(namespace string) error {
return k8sClient.Create(context.Background(), secret)
}
type gitRepoOption func(*gitRepoOptions)
type gitRepoOptions struct {
artifactMetadata map[string]string
}
func withGitRepoArtifactMetadata(k, v string) gitRepoOption {
return func(o *gitRepoOptions) {
if o.artifactMetadata == nil {
o.artifactMetadata = make(map[string]string)
}
o.artifactMetadata[k] = v
}
}
func applyGitRepository(objKey client.ObjectKey, artifactName string,
revision string, opts ...gitRepoOption) error {
var opt gitRepoOptions
for _, o := range opts {
o(&opt)
}
func applyGitRepository(objKey client.ObjectKey, artifactName string, revision string) error {
repo := &sourcev1.GitRepository{
TypeMeta: metav1.TypeMeta{
Kind: sourcev1.GitRepositoryKind,
@ -318,7 +294,7 @@ func applyGitRepository(objKey client.ObjectKey, artifactName string,
}
b, _ := os.ReadFile(filepath.Join(testServer.Root(), artifactName))
dig := digest.SHA256.FromBytes(b)
checksum := fmt.Sprintf("%x", sha256.Sum256(b))
url := fmt.Sprintf("%s/%s", testServer.URL(), artifactName)
@ -335,18 +311,17 @@ func applyGitRepository(objKey client.ObjectKey, artifactName string,
Path: url,
URL: url,
Revision: revision,
Digest: dig.String(),
Checksum: checksum,
LastUpdateTime: metav1.Now(),
Metadata: opt.artifactMetadata,
},
}
patchOpts := []client.PatchOption{
opt := []client.PatchOption{
client.ForceOwnership,
client.FieldOwner("kustomize-controller"),
}
if err := k8sClient.Patch(context.Background(), repo, client.Apply, patchOpts...); err != nil {
if err := k8sClient.Patch(context.Background(), repo, client.Apply, opt...); err != nil {
return err
}
@ -369,13 +344,13 @@ func createVaultTestInstance() (*dockertest.Pool, *dockertest.Resource, error) {
// uses a sensible default on windows (tcp/http) and linux/osx (socket)
pool, err := dockertest.NewPool("")
if err != nil {
return nil, nil, fmt.Errorf("could not connect to docker: %s", err)
return nil, nil, fmt.Errorf("Could not connect to docker: %s", err)
}
// pulls an image, creates a container based on it and runs it
resource, err := pool.Run("vault", vaultVersion, []string{"VAULT_DEV_ROOT_TOKEN_ID=secret"})
if err != nil {
return nil, nil, fmt.Errorf("could not start resource: %s", err)
return nil, nil, fmt.Errorf("Could not start resource: %s", err)
}
os.Setenv("VAULT_ADDR", fmt.Sprintf("http://127.0.0.1:%v", resource.GetPort("8200/tcp")))
@ -384,24 +359,24 @@ func createVaultTestInstance() (*dockertest.Pool, *dockertest.Resource, error) {
if err := pool.Retry(func() error {
cli, err := api.NewClient(api.DefaultConfig())
if err != nil {
return fmt.Errorf("cannot create Vault Client: %w", err)
return fmt.Errorf("Cannot create Vault Client: %w", err)
}
status, err := cli.Sys().InitStatus()
if err != nil {
return err
}
if status != true {
return fmt.Errorf("vault not ready yet")
return fmt.Errorf("Vault not ready yet")
}
if err := cli.Sys().Mount("sops", &api.MountInput{
Type: "transit",
}); err != nil {
return fmt.Errorf("cannot create Vault Transit Engine: %w", err)
return fmt.Errorf("Cannot create Vault Transit Engine: %w", err)
}
return nil
}); err != nil {
return nil, nil, fmt.Errorf("could not connect to docker: %w", err)
return nil, nil, fmt.Errorf("Could not connect to docker: %w", err)
}
return pool, resource, nil

11
controllers/testdata/sops/.sops.yaml vendored Normal file
View File

@ -0,0 +1,11 @@
# creation rules are evaluated sequentially, the first match wins
creation_rules:
# files using age
- path_regex: \.age.yaml$
encrypted_regex: ^(data|stringData)$
age: age1l44xcng8dqj32nlv6d930qvvrny05hglzcv9qpc7kxjc6902ma4qufys29
- path_regex: month.yaml$
pgp: 35C1A64CD7FC0AB6EB66756B2445463C3234ECE1
# fallback to PGP
- encrypted_regex: ^(data|stringData)$
pgp: 35C1A64CD7FC0AB6EB66756B2445463C3234ECE1

1
controllers/testdata/sops/day.txt vendored Normal file
View File

@ -0,0 +1 @@
day=Tuesday

View File

@ -0,0 +1,20 @@
{
"data": "ENC[AES256_GCM,data:YWPHPTVOCWivqZu0,iv:tLqbJD/KN2BchlAz1mnf4FtMY+SP5hiBYJP6dHy8gtc=,tag:Aj9T0Q7y9baA84EfEt8MfQ==,type:str]",
"sops": {
"kms": null,
"gcp_kms": null,
"azure_kv": null,
"hc_vault": null,
"lastmodified": "2021-04-27T20:27:20Z",
"mac": "ENC[AES256_GCM,data:1OqDvIaUpOKFa1vsa6nc+GHIvsxwQ3JhJsDTp+Yl2r8y0+n0VUbCm9FyqVvq8ur3Y3NyZfX+7FL6HxgTN0RnSMdwK1X16ioGWBk4CM3K7W8tyY7gmhddsuJqSDZdV7Hr2s7FB6LZJAHWO9vTn9zXM75Ef0B5yuOgzp29LmIhCK4=,iv:8ozNZ7IgDub2vICSzHWcAdx7/sVEoe8YayXYrAkN0BM=,tag:UwE0b6eTpA9uir+4Mwed7g==,type:str]",
"pgp": [
{
"created_at": "2021-04-27T20:27:20Z",
"enc": "-----BEGIN PGP MESSAGE-----\n\nhQIMA90SOJihaAjLAQ//cd4d6zghXW7uJ8rk0PoWiCVy5BeYwnInJT4uqJ5uUY62\nFLlsM4ZJB2SSBHGcXdwkWqTXeLLmD8aEuAe0lfutcOYyMZVWeYY+wybyJ5TgBMAo\nvEJoY67felWRb4h0BzkHIG/ZLiuDTV020GJNH2tGgE/mXVPhYosQ+EmA5EF45vfj\nqx2LjZjsCg28FK2qkXnHHjOV/12OnGpR0y6t9GijBUtttyjYaXUpNUSUiHHMjXyL\nQnKlRPt9N2QF6oUQVEwr9plNYKTfmeqUwWh6wFAaWF/104oSOwXFA8ID5wF6de1j\ntnzVf+1Ld5WNmXGmrz/6ugWfcU/3147EuPodjTyQIFMTxA6V7Z7BORjhuxFpR/jS\noZJF/SS70fg9J7sdizWKFNkqS9pPasdNHcGuXU+KGkD2ya54WyUDE86gMq0xtEf3\nMmQJRnjHuriD5EvnKmDJ+QE9nU0ld0kyfVUueHQHCtuuw7yZGi8vlyyjOq4nqCGV\nZ4TJcmpt7pKoxEAnp2tImnos7DbEoQMl7RIYgrhxS7Nej9naYeadFz/G84uwjfm0\nBr5J3A+xtG37HXQWqtd7EXmy/I94okNVXeAZuuQFt/So78jJ4H9uQK1snukPNBhr\nG8aM8SfdrTbp4KZQpm2RJwNdhbHzHoz2M2Dc6Eo14FceW0R0jYDaKTwKeNIgH6jS\nXgGdX+eJRyC1yhp6HAXOaaR9MvXJ8xCi6clWRpI9h3wxnrZtg+pERFeHhp2Ldlww\nRTjw4g3Cp9GQJB/0aTkVVOPmZ4/jpCyUS6hiV3cEE4veuDYZ20evpgO4sld6Ve8=\n=1o9a\n-----END PGP MESSAGE-----\n",
"fp": "35C1A64CD7FC0AB6EB66756B2445463C3234ECE1"
}
],
"encrypted_regex": "^(data|stringData)$",
"version": "3.6.0"
}
}

View File

@ -1,13 +1,14 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namePrefix: files-
secretGenerator:
- name: sops-month
files:
- month.yaml
- name: sops-year
envs:
- year.env
- name: unencrypted-sops-year
envs:
- unencrypted-year.env
generatorOptions:
disableNameSuffixHash: true
secretGenerator:
- name: secret
files:
- key=file.txt
configMapGenerator:
- name: configmap
files:
- key=file.txt

View File

@ -0,0 +1,32 @@
month: ENC[AES256_GCM,data:9e+R,iv:EzJxah6sCY2D9L76l/CuVq6qVq2ncJDYphm9gXE/ZgM=,tag:r82agynzHp/aOTVo6Iu9wg==,type:str]
sops:
kms: []
gcp_kms: []
azure_kv: []
hc_vault: []
age: []
lastmodified: "2021-05-31T11:27:34Z"
mac: ENC[AES256_GCM,data:BV/jKqSzKr2sq/yA4HToFseOWOB04cYo+54Dby/Jp4ZuVwxNt1i02zncsvWyQZK5WFcvK47brvzN6fWJyyf5WnX+XISbuUDGMWjqNG/te3YKEY4ZqJUopDF/AxDZDkUC5KdnIln6RZqtHuJH18J35kakWFrg1YOJtI28ZVK5yBM=,iv:T6JJkYbfqpUz2AClToZtSsuVbUXcPD5nqaUhJJdH6Uc=,tag:jvmH8iyfivoGIt1k+Uodrg==,type:str]
pgp:
- created_at: "2021-05-31T11:27:34Z"
enc: |
-----BEGIN PGP MESSAGE-----
hQIMA90SOJihaAjLAQ/9HYs2HyaYL9dOj8zIAr3JzqEFHlMX59Vw8kj9KxBQJXYQ
N3mE/HHQVBWk/36Pq/14n0Eals8GwivDDiJmovfeRASmb0/LnGQDzMkDGEJvyu7N
Q69rBjzVWbmMPgI0vQb0zTBRcUW+LnSijkv+H5mxuFnnZd8N3UeFLHX2oKNeA7O3
pYjjK8vr6KaXJqYfH+bFs29cnk0+xZiThr21cz40yFZD7ynns4xjdVtqI5bvGk/F
bDW7oGgJe+q/9OHKJaVESLrcZMe2lLxA7x821ssq6BlNzv9DHTc7PloVNepsze6d
MBTgzAZoH04ENQSiL9qo24AVGaFhUXak7MslxE8nhjFJD6sfb0Q/LtlhOSpDw7NR
gugPzQuQLGN9U54id0bql8CBi58g0wdxjo6kDlMYTEd9CZbugfM1pR1imknlgPLi
7ODDrWTTxnZm4+hZRj7EjMGlRshavPgZ/rgT1tTnjNw9c+llgCWW8Ei8JOEvA86M
DwsPzodesMO56yf3MJPAgakCapTH9VMad+E63yUMsNAX6+otrjgssvxg3j8KnjPp
Z7593P7RGYrRR+YwEi5nTHmDL1H80vP6pNnBGd7wLa3TLzypkDiZSKY6vq6vSIwd
QOpLX3VC2X53mtWmNm7oWxKLX3hKPrjTqBYE0EDK7Yc0q8rj++ygntOekI+WSm/S
XAG4Ufue6i2MTvnZmK/Byt+E/zT4jRmjRQImGekHB+rLYfM3Z85i6ExH4OCCWNqC
rg4DqrWTS8Nvt2PE5UC3Phqe51D4/ZrQPVPkFQftgQl44xECv4X8rI7RTux6
=HE0m
-----END PGP MESSAGE-----
fp: 35C1A64CD7FC0AB6EB66756B2445463C3234ECE1
unencrypted_suffix: _unencrypted
version: 3.7.1

View File

@ -0,0 +1 @@
year=2021

View File

@ -0,0 +1,7 @@
year=ENC[AES256_GCM,data:EfNnlA==,iv:pBaHDmjQ1d6JrA0Rk19giCQon7CP37hZ0dEQTkJEw1U=,tag:J29CEN9S6pSie8tsAD2REA==,type:str]
sops_age__list_0__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB3NHYyMHdNcXhMS2x6aXJq\nTHVhbUYrcW8waFduN1NoWUIyTWFuMmNEVGpzCjUxb05zUndSdnpiQng2VnZ2SkNF\nbnlzY0VmaVd1Z0xZR2FKdDRPQlhKSE0KLS0tIDlEaGgwT3VHcUg5QzFpenZNOTBk\nbUZ5QkRnY0kwMFpYanFLYTlvc0FXdXMKb32CnEO8yg91kkUMFXhBL5Sfz32dNOJT\ntNGdKcOGVBzOJVgU1RquB+5OcJdbuwdV7GCq8KvXqh5fypTI00hZeg==\n-----END AGE ENCRYPTED FILE-----\n
sops_age__list_0__map_recipient=age1l44xcng8dqj32nlv6d930qvvrny05hglzcv9qpc7kxjc6902ma4qufys29
sops_lastmodified=2021-10-14T15:35:45Z
sops_mac=ENC[AES256_GCM,data:brSfy5j0wETn6YT7p8qoCSuI6bevGwrxBbtcqBSYRJ+GgLAr9a7rtwHK8/BnKCi1C1H/zGa1gEERqz2j6Zw0uS4V5lejvtDtfRn9DwYWQ2Aqo2zi4crfNhljerwQVa/Hy9pq2falIZyyhoDX30WOoLe+2eZWQXLtFlVkx4x7U1s=,iv:wr4szytKCN9j6dqccZZl0bkDUHsOtFSvDXjdpuZwTbA=,tag:N1uQ25uLS+E6yQPzXJRiNw==,type:str]
sops_version=3.7.1
sops_unencrypted_suffix=_unencrypted

View File

@ -0,0 +1,26 @@
apiVersion: v1
kind: Secret
metadata:
name: sops-age
stringData:
secret: ENC[AES256_GCM,data:RwzrBF8wy16SpfbQoeADeKyz,iv:DuJce2Ebx1Y49DaLCOJ74OOkgiv21roxhz/sZqKCSSs=,tag:Gg9XHapZI5q+rvtgeY6nrg==,type:str]
sops:
kms: []
gcp_kms: []
azure_kv: []
hc_vault: []
age:
- recipient: age1l44xcng8dqj32nlv6d930qvvrny05hglzcv9qpc7kxjc6902ma4qufys29
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBNeGduOFZjRWw2WTFQdWdu
OS83OEZaN1E1aU1zSThhMlNEZzd0aEYvdURFCnE3bmJ5c3J2cDNEbXhselFPVC9v
NFhMRjZjOHZOdEpoYjdiS0ZPd2pvN1kKLS0tIDZUVEFoblpDNWhnaWxYRTBjaktk
bHRXV0o1K2ZDNm5Mem5SdzNBMTNuNFUKylE2cRLqydjj6e4+4Giwn4y8mIPej+CM
Bab3UWiK1da2rFNTOEnoHl6QDAVxNrWdrrIa5k22SzApT88VtJ4xuQ==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2021-04-06T09:07:05Z"
mac: ENC[AES256_GCM,data:oaM8qFtEP8dOCd/Tr5yb08uetsnDtZO8o1rCayN53ncQ1HUAdhRBrFdmbYx1YTh1mwQVVN6sGYqFZU1LBMVv5pTqvpwd41biJZEg8NznXQWx0GA2Z6HOrblGhFZKrqky3P5xN+6j63zkJizXWgBMKzRvBnsVKxjZGr/lk1vVVv4=,iv:p4y9Fo3SArkEMuoK2d9sQYgNdc0iw/StFhg/5LnhcXM=,tag:61JGbnEw35tv6WnGj46JOw==,type:str]
pgp: []
encrypted_regex: ^(data|stringData)$
version: 3.7.0

View File

@ -0,0 +1,7 @@
apiVersion: v1
data:
secret: ewoJImRhdGEiOiAiRU5DW0FFUzI1Nl9HQ00sZGF0YTpCZDJuL1VCc21KN2NYYXVvLGl2OmR4c25ncWVDVitzVVVIM24rVTZ1N1F3WjEvRFptM3RhVlVOSjJRTFNlWGM9LHRhZzp3enhxUjA2MWRmbmVhQmlMNHRxaTN3PT0sdHlwZTpzdHJdIiwKCSJzb3BzIjogewoJCSJrbXMiOiBudWxsLAoJCSJnY3Bfa21zIjogbnVsbCwKCQkiYXp1cmVfa3YiOiBudWxsLAoJCSJoY192YXVsdCI6IG51bGwsCgkJImxhc3Rtb2RpZmllZCI6ICIyMDIxLTA0LTI3VDE5OjQ4OjIwWiIsCgkJIm1hYyI6ICJFTkNbQUVTMjU2X0dDTSxkYXRhOkUwQmFsdjRGcWRiQVNRSGNpa2oyaURTeTdCTjBVSUY3cHhlSFNwUUZ2dXF6akVtRWlDV2xJRFl0dmgxY2t4ZnZxNHpYS2xITkp6QitkM1RSaHNuaGtIZ2tSWFA1MldwUkNHZ1pwY3h5Q3FCTmhhL00wRGNGY1ZZZG14T2NVNEU4eFdsdFRuektzZll0bVkvTVludmVJT1htNkpmMUhPS2FVM1EwdzBGbG8wQT0saXY6QWgza0puZEI3UnE5RVV3ZUc0TUMzUmh5bXRYRXY0ellIc2M3M3NxQzlGdz0sdGFnOnpOS3ZHcW5WNG8yWTdhNUJTV28yZEE9PSx0eXBlOnN0cl0iLAoJCSJwZ3AiOiBbCgkJCXsKCQkJCSJjcmVhdGVkX2F0IjogIjIwMjEtMDQtMjdUMTk6NDg6MjBaIiwKCQkJCSJlbmMiOiAiLS0tLS1CRUdJTiBQR1AgTUVTU0FHRS0tLS0tXG5cbmhRSU1BOTBTT0ppaGFBakxBUS8vZGo2NzlnSXpKdU1vc05wdkRZQVNUOVF4MjBGdmJOREsvTDhmY2xlTFd0NHpcbktWaHdlTnRRdXhZbXA1a2Z6VUpBWXh2Mk01a2NSWFo1QzVDWDJLSER2N1lxVWRRdVdMam9wTFRmR1RPcE56RlBcbjNyZE5sRXZKMC8zSXdteEhtYXVPbUpPazByRUQrOXZtTXNCL3pnaXIxWkd2d0tTNVM5dW9XSDN6bUlVdmJBR29cbmpCKzAxRkdqaXlYRUhSanFzbFlMZ0tXczhZaVR4anNPOVd3QlU0ZmRySzRCKytEaWFweVdFcDJYVWhFZWt6MjFcbjR3dXU5dEp5TmtOWXpmMXNXUWxMc1lPblMzRkkrNSsrMFg1SmREYWtFVmkzSnF1TmtLeDRuWms3ZHJqcktnM1hcbnJPWTc1YnIxdGkwTkxrQWFsaUwvbEJSR3JCTW5BeTViV0l4dkpoSmtqRGMyZTNBWmJNbXdJQ0FJZ05kMEcrNFBcbkJqWkhNWnZUQk1RN0VvWFhGeVg5K3JKKzFnUzF5UEJuaFNma3lrSmJSR1ljdnB1RVRFL1NyK0FSa0s0cHV5bFVcbk5sdU8xZmdOMEF1STVqVll2NzJ1MzJWZEw2N2ZYbjlPdjhFYmlkdVVKcWoxZXB3Mk53dDNZK2xrNERLbVBybVRcbjFRTzF3OC96UHo1SlR0U1R4ZXFJak4weXBTazFocE9XekNwOTE0QmgxckFscXFxakorc0Q4dkVseEk2N2JSWG5cblY1alBkZkQwQktLU0tqS0ZLeVhnUHdPdCtvd2xTTDROR0V6bmdTcmsyeDlTcHVDdWQweXpoeVpta2tHRm5JKzdcbmhpT2kzeGxmZnkvRWY4TDkvaWhDbmJQc1pTck50L0RPQlVGK0ZGQUlmZitpUElPRTBieGZCaHpMNWZOTS9ZdlNcblhBRS9pYk42NktLT2ZwYWlqWnRXSkdTY1RHVVlYMkt2WTAwN2h6Y1ErR3BaZUZOd3oyUlpEd3BkTzZ4N3JHelFcbkFHQUtjd2pTYXcramluVzQwWmZnOWQ5YmFMdWRYTDRXVU9FSUdTN2FpWjNFNjJTSFJGU2U0dmNpSVh6blxuPThRcmZcbi0tLS0tRU5EIFBHUCBNRVNTQUdFLS0tLS1cbiIsCgkJCQkiZnAiOiAiMzVDMUE2NENEN0ZDMEFCNkVCNjY3NTZCMjQ0NTQ2M0MzMjM0RUNFMSIKCQkJfQoJCV0sCgkJImVuY3J5cHRlZF9yZWdleCI6ICJeKGRhdGF8c3RyaW5nRGF0YSkkIiwKCQkidmVyc2lvbiI6ICIzLjYuMCIKCX0KfQ==
kind: Secret
metadata:
creationTimestamp: null
name: sops-day

View File

@ -0,0 +1,8 @@
apiVersion: v1
data:
secret: bXktc29wcy12YXVsdC1zZWNyZXQK
kind: Secret
metadata:
name: sops-hcvault
namespace: default
type: Opaque

37
controllers/testdata/sops/secret.yaml vendored Normal file
View File

@ -0,0 +1,37 @@
apiVersion: v1
kind: Secret
metadata:
name: sops-pgp
stringData:
secret: ENC[AES256_GCM,data:rZEmadbj49GoQLlK85hKKAsc,iv:FX4Dfbd173bZQdUgEVRo4q29m/Gz9ob07QHFuiCAufA=,tag:VM6tzAVdGjsythy2Mr5tvw==,type:str]
sops:
kms: []
gcp_kms: []
azure_kv: []
hc_vault: []
age: []
lastmodified: "2021-04-06T09:07:19Z"
mac: ENC[AES256_GCM,data:iBg8FY39VSykcWZ/asv86P3VNZkscQdINNOy3UtI5m4OWDpUkyDuq66w7ELiiEXJ3D+b7JKJrsSrYtT7Tn7t+NZGxJcLQFEczozvWgKd2hCikxnMEepCJ3tRcoz7JaItommi1HvA08syGfLA5f6eOxsHQWzmjVdYaVpQ4VGRibk=,iv:VI+Fb7dXV4442IMKZSHOb0GJ/2nNgK9AUTblOZ49Oco=,tag:gJjFguJeE7irKZW7yZi0jw==,type:str]
pgp:
- created_at: "2021-04-06T09:07:19Z"
enc: |
-----BEGIN PGP MESSAGE-----
hQIMA90SOJihaAjLAQ/+LnZo9UHmJ2Llcpq6m5gjo5hbCx6aYTbrvJOFCWeu2oyC
71XsuTUzBp7TK8SkGrxlJmUodezACQ3rCsKY/r2GI4t9HkVRSuhnc/YQMunm3iG1
bsgfdV/KBm0Go7dFXy2R1Pt3PuVnuM9MZ59U4SdqYGZDI7vzy2gfH127qa3oIOoF
2OFfwhUy8nZIVCJ47ExIdrc7Qdk94tbLfwmBAKHFN4Ab0YXasKCpH9O+9/vQ+JJU
7xy61Nv4dqtEDYU9QTh2ZuT6ZaWikTqCcIv/W7lW1RsT8n7YiRZv9POobKDh5KbP
PyfqvJsLcJB8LHN2kZfwr6Iemuce19kRi+7JL9zMGRJSsq0thJ0ly3JBi48pU27w
jbFnmxlIwfb0EsLBp9lsxw7GoUbooSC/rfI5NVeQ+4lFA4gQn2oz7i4zTYesnwil
lrgMxz49SSluAYsGjrJHc+ABmlDz83K42KtWlNjwaIbDgHMl4EbYUe4pxcynEZ6D
0csDIsIA15MP0THfTL1F1vkhvdPHNuUlVjFqgWaJAP2CC5KH8IeTCUN72FySEYAB
BJH+VQoRnS942M8VQAfUQyBsfZKtQhyCkU7KEimUjQzy75JWgy8YMX1mviXk52qB
kVHQIjNEuBta58pmNyhxc+6+bz+ABGp+mR9QemUQjmXghH3VjOwnZVj6KMMX4J3S
XgEubPmw6u4nYqb9bLDVyE2uXXA4TVgFDuZxJrbZOn9zF2aQOOGfZX2Gx5xgK+pV
srM1wyJqdP+QL/fWO9ZI38+tyr1T5zOBPpJ/JTrkSJoVeRWpwuI6BUCZhH66nfU=
=+1cf
-----END PGP MESSAGE-----
fp: 35C1A64CD7FC0AB6EB66756B2445463C3234ECE1
encrypted_regex: ^(data|stringData)$
version: 3.7.0

View File

@ -1,13 +1,8 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namePrefix: envs-
secretGenerator:
- name: sops-year2
envs:
- ./secrets/year2.txt
generatorOptions:
disableNameSuffixHash: true
secretGenerator:
- name: secret
envs:
- env.env
configMapGenerator:
- name: configmap
envs:
- env.env

View File

@ -0,0 +1,7 @@
year=ENC[AES256_GCM,data:HoFRvaM=,iv:XNDFLkONNvKSKkbqErVx1/tnEtDuZIG3SficCd7NIaM=,tag:aC7SCerL01kYyXyXkWR2ag==,type:str]
sops_unencrypted_suffix=_unencrypted
sops_mac=ENC[AES256_GCM,data:s75x7NzSjmkovCOopnT1eIfXMAdwwsN8KoVdVbAYDTAsB856w/i/W/JshXAUdr5SnXHNbtwzEha/HSppnWEQw1nds18yZCeIW54QE7yxvBKw9Mhd3wxHWiZWziTY0awbYinbyQ45zpq1Iz97BueNjhwtZWMQzRKLQvwyqEljTHs=,iv:AuKqCzIgTYcogtyLrtM6VdgwKTlDE3uMxvVaWbpKBOA=,tag:Ija+U/97TxxWoXYDpG6+jg==,type:str]
sops_age__list_0__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBYV1FYTkdzV210SkswWmty\nZzZSVzlCUlRQcVNEOVpYSWNSSWtPd00rcDJrCjZKVVp6aFY2cHJQbm9oY2Q1Z2N3\nLzBWalF4ZHZYTU5kMlcwaGRvYkVKcFEKLS0tIG1QTjNuY0pRbFBqT3dFNFROQWU3\nTWQxNVlUNG8rblQyYmJoaCtKSGcrdE0KjUJ+hGiyCkzUG41mwT3rAb0BdwBF8303\nhBDRmW+DjP1ETrGTXviTS1Cq29IX1K2KdBRxixjtwewkXV/i87wHRA==\n-----END AGE ENCRYPTED FILE-----\n
sops_age__list_0__map_recipient=age1l44xcng8dqj32nlv6d930qvvrny05hglzcv9qpc7kxjc6902ma4qufys29
sops_lastmodified=2021-10-15T11:09:14Z
sops_version=3.7.1

View File

@ -1,12 +1,10 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namePrefix: patches-
patches:
- path: merge1.yaml
- path: merge2.yaml
resources:
- ../bases
secretGenerator:
- name: sops-year1
envs:
- year1.env
generatorOptions:
disableNameSuffixHash: true
secretGenerator:
- name: secret
literals:
- key=value

View File

@ -0,0 +1,7 @@
year=ENC[AES256_GCM,data:tV/GLTE=,iv:AtEKKSUa4BiTnDzGMtpGrO78NuR0wMXzjKrQScbtX24=,tag:zAzcBzQ6ORO+NhcY3idHcA==,type:str]
sops_lastmodified=2021-10-15T11:08:51Z
sops_unencrypted_suffix=_unencrypted
sops_age__list_0__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBFU29oWEh2ckRjaCs3d1FJ\nYTkxN0dqY1lsc1dEUmZ4OGN0N1BHK0xxQld3CmpTL2Z2VDloQStCYnRmYnJ0SDFj\nVU9USmszbU44YUxzRi95Q0sxY2t0bkUKLS0tIC80Ulh1RWJPeUFqbUFNSjFOeGIy\nY001MzMwbnRsQXlsN1VVY2xLY20yazQKYhZQGZpay9J1cnGiHCKBY6DtYMCSIBo7\nAP41GiVukT6M4LT83TpWzWgbR/xNgreKdNpweYcw+Fp+wJHVeR3+fg==\n-----END AGE ENCRYPTED FILE-----\n
sops_mac=ENC[AES256_GCM,data:rw8vAq+8nqa5/V8p/ICuVKXNQCeTIFExF33qy1YEbc8f4kePDhTlGqxluEytbWOhk+hzCd4POk+zY8bWBY2QSiq0lle2rCtE2WT3I04/+bHzX74yMBuadYLqiUFEhkra/58FXD404PPJBUrOy8mAPgWVczcqMexYhzz//tPdGMY=,iv:yk3CsyGigCSHonvMBTQvjg+kgNssf87KqlKeR6FE8sk=,tag:dCaOhh97ebJWNT5v35n6Iw==,type:str]
sops_version=3.7.1
sops_age__list_0__map_recipient=age1l44xcng8dqj32nlv6d930qvvrny05hglzcv9qpc7kxjc6902ma4qufys29

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