Compare commits
No commits in common. "main" and "v0.0.1-alpha.4" have entirely different histories.
main
...
v0.0.1-alp
|
@ -0,0 +1,6 @@
|
|||
FROM giantswarm/tiny-tools
|
||||
|
||||
COPY entrypoint.sh /entrypoint.sh
|
||||
RUN chmod +x /entrypoint.sh
|
||||
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
|
@ -0,0 +1,9 @@
|
|||
name: 'kubebuilder'
|
||||
description: 'A GitHub Action to run kubebuilder commands'
|
||||
author: 'Stefan Prodan'
|
||||
branding:
|
||||
icon: 'command'
|
||||
color: 'blue'
|
||||
runs:
|
||||
using: 'docker'
|
||||
image: 'Dockerfile'
|
|
@ -0,0 +1,12 @@
|
|||
#!/bin/sh -l
|
||||
|
||||
VERSION=2.3.1
|
||||
|
||||
curl -sL https://go.kubebuilder.io/dl/${VERSION}/linux/amd64 | tar -xz -C /tmp/
|
||||
|
||||
mkdir -p $GITHUB_WORKSPACE/kubebuilder
|
||||
mv /tmp/kubebuilder_${VERSION}_linux_amd64/* $GITHUB_WORKSPACE/kubebuilder/
|
||||
ls -lh $GITHUB_WORKSPACE/kubebuilder/bin
|
||||
|
||||
echo "::add-path::$GITHUB_WORKSPACE/kubebuilder/bin"
|
||||
echo "::add-path::$RUNNER_WORKSPACE/$(basename $GITHUB_REPOSITORY)/kubebuilder/bin"
|
|
@ -0,0 +1,6 @@
|
|||
FROM giantswarm/tiny-tools
|
||||
|
||||
COPY entrypoint.sh /entrypoint.sh
|
||||
RUN chmod +x /entrypoint.sh
|
||||
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
|
@ -0,0 +1,9 @@
|
|||
name: 'kustomize'
|
||||
description: 'A GitHub Action to run kustomize commands'
|
||||
author: 'Stefan Prodan'
|
||||
branding:
|
||||
icon: 'command'
|
||||
color: 'blue'
|
||||
runs:
|
||||
using: 'docker'
|
||||
image: 'Dockerfile'
|
|
@ -0,0 +1,12 @@
|
|||
#!/bin/sh -l
|
||||
|
||||
VERSION=3.1.0
|
||||
curl -sfLo kustomize https://github.com/kubernetes-sigs/kustomize/releases/download/v${VERSION}/kustomize_${VERSION}_linux_amd64
|
||||
|
||||
mkdir -p $GITHUB_WORKSPACE/bin
|
||||
cp ./kustomize $GITHUB_WORKSPACE/bin
|
||||
chmod +x $GITHUB_WORKSPACE/bin/kustomize
|
||||
ls -lh $GITHUB_WORKSPACE/bin
|
||||
|
||||
echo "::add-path::$GITHUB_WORKSPACE/bin"
|
||||
echo "::add-path::$RUNNER_WORKSPACE/$(basename $GITHUB_REPOSITORY)/bin"
|
|
@ -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"
|
|
@ -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'
|
|
@ -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@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
- name: Create backport PRs
|
||||
uses: korthout/backport-action@ca4972adce8039ff995e618f5fc02d1b7961f27a # v3.3.0
|
||||
# xref: https://github.com/korthout/backport-action#inputs
|
||||
with:
|
||||
# Use token to allow workflows to be triggered for the created PR
|
||||
github_token: ${{ secrets.BOT_GITHUB_TOKEN }}
|
||||
# Match labels with a pattern `backport:<target-branch>`
|
||||
label_pattern: '^backport:([^ ]+)$'
|
||||
# A bit shorter pull-request title than the default
|
||||
pull_title: '[${target_branch}] ${pull_title}'
|
||||
# Simpler PR description than default
|
||||
pull_description: |-
|
||||
Automated backport to `${target_branch}`, triggered by a label in #${pull_number}.
|
|
@ -1,24 +0,0 @@
|
|||
name: fuzz
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
|
||||
permissions:
|
||||
contents: read # for actions/checkout to fetch code
|
||||
|
||||
jobs:
|
||||
smoketest:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
|
||||
with:
|
||||
go-version: 1.25.x
|
||||
cache-dependency-path: |
|
||||
**/go.sum
|
||||
**/go.mod
|
||||
- name: Smoke test Fuzzers
|
||||
run: make fuzz-smoketest
|
|
@ -4,159 +4,64 @@ on:
|
|||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- 'main'
|
||||
- 'release/**'
|
||||
|
||||
permissions:
|
||||
contents: read # for actions/checkout to fetch code
|
||||
- master
|
||||
|
||||
jobs:
|
||||
kind:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
- name: Setup QEMU
|
||||
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0
|
||||
- name: Setup Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
|
||||
- name: Cache Docker layers
|
||||
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
|
||||
id: cache
|
||||
uses: actions/checkout@v2
|
||||
- name: Restore Go cache
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: /tmp/.buildx-cache
|
||||
key: ${{ runner.os }}-buildx-ghcache-${{ github.sha }}
|
||||
path: ~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-buildx-ghcache-
|
||||
${{ runner.os }}-go-
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
|
||||
uses: actions/setup-go@v2-beta
|
||||
with:
|
||||
go-version: 1.25.x
|
||||
cache-dependency-path: |
|
||||
**/go.sum
|
||||
**/go.mod
|
||||
go-version: 1.14.x
|
||||
- name: Setup Kubernetes
|
||||
uses: helm/kind-action@a1b0e391336a6ee6713a0583f8c6240d70863de3 # v1.12.0
|
||||
with:
|
||||
version: v0.20.0
|
||||
cluster_name: kind
|
||||
node_image: kindest/node:v1.27.3@sha256:3966ac761ae0136263ffdb6cfd4db23ef8a83cba8a463690e98317add2c9ba72
|
||||
uses: engineerd/setup-kind@v0.3.0
|
||||
- name: Setup Kustomize
|
||||
uses: fluxcd/pkg/actions/kustomize@main
|
||||
- name: Enable integration tests
|
||||
# Only run integration tests for main branch
|
||||
if: github.ref == 'refs/heads/main'
|
||||
run: |
|
||||
echo 'GO_TEST_ARGS=-tags integration' >> $GITHUB_ENV
|
||||
- name: Run controller tests
|
||||
env:
|
||||
TEST_AZURE_CLIENT_ID: ${{ secrets.TEST_AZURE_CLIENT_ID }}
|
||||
TEST_AZURE_TENANT_ID: ${{ secrets.TEST_AZURE_TENANT_ID }}
|
||||
TEST_AZURE_CLIENT_SECRET: ${{ secrets.TEST_AZURE_CLIENT_SECRET }}
|
||||
TEST_AZURE_VAULT_URL: ${{ secrets.TEST_AZURE_VAULT_URL }}
|
||||
TEST_AZURE_VAULT_KEY_NAME: ${{ secrets.TEST_AZURE_VAULT_KEY_NAME }}
|
||||
TEST_AZURE_VAULT_KEY_VERSION: ${{ secrets.TEST_AZURE_VAULT_KEY_VERSION }}
|
||||
uses: ./.github/actions/kustomize
|
||||
- name: Setup Kubebuilder
|
||||
uses: ./.github/actions/kubebuilder
|
||||
- name: Run tests
|
||||
run: make test
|
||||
env:
|
||||
KUBEBUILDER_ASSETS: ${{ github.workspace }}/kubebuilder/bin
|
||||
- name: Check if working tree is dirty
|
||||
run: |
|
||||
if [[ $(git diff --stat) != '' ]]; then
|
||||
git --no-pager diff
|
||||
echo 'run make test and commit changes'
|
||||
exit 1
|
||||
fi
|
||||
- name: Build container image
|
||||
run: |
|
||||
make docker-build IMG=test/kustomize-controller:latest \
|
||||
BUILD_PLATFORMS=linux/amd64 \
|
||||
BUILD_ARGS="--cache-from=type=local,src=/tmp/.buildx-cache \
|
||||
--cache-to=type=local,dest=/tmp/.buildx-cache-new,mode=max \
|
||||
--load"
|
||||
- # Temp fix
|
||||
# https://github.com/docker/build-push-action/issues/252
|
||||
# https://github.com/moby/buildkit/issues/1896
|
||||
name: Move cache
|
||||
run: |
|
||||
rm -rf /tmp/.buildx-cache
|
||||
mv /tmp/.buildx-cache-new /tmp/.buildx-cache
|
||||
run: make docker-build IMG=test/kustomize-controller:latest
|
||||
env:
|
||||
KUBEBUILDER_ASSETS: ${{ github.workspace }}/kubebuilder/bin
|
||||
- name: Load test image
|
||||
run: kind load docker-image test/kustomize-controller:latest
|
||||
- name: Install CRDs
|
||||
run: make install
|
||||
- name: Run default status test
|
||||
- name: Deploy source-controller
|
||||
run: kustomize build https://github.com/fluxcd/source-controller//config/default?ref=v0.0.1-alpha.1 | kubectl apply -f-
|
||||
- name: Deploy kustomize-controller
|
||||
run: make dev-deploy IMG=test/kustomize-controller:latest
|
||||
env:
|
||||
KUBEBUILDER_ASSETS: ${{ github.workspace }}/kubebuilder/bin
|
||||
- name: Run smoke tests
|
||||
run: |
|
||||
kubectl apply -f config/testdata/status-defaults
|
||||
RESULT=$(kubectl get kustomization status-defaults -o go-template={{.status}})
|
||||
EXPECTED='map[observedGeneration:-1]'
|
||||
if [ "${RESULT}" != "${EXPECTED}" ] ; then
|
||||
echo -e "${RESULT}\n\ndoes not equal\n\n${EXPECTED}"
|
||||
exit 1
|
||||
fi
|
||||
kubectl delete -f config/testdata/status-defaults
|
||||
- name: Deploy controllers
|
||||
run: |
|
||||
make dev-deploy IMG=test/kustomize-controller:latest
|
||||
kubectl -n kustomize-system rollout status deploy/source-controller --timeout=1m
|
||||
kubectl -n kustomize-system rollout status deploy/kustomize-controller --timeout=1m
|
||||
- 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
|
||||
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
|
||||
OUTDATA=$(kubectl -n managed-fields get deploy podinfo --show-managed-fields -oyaml)
|
||||
if echo "$OUTDATA" | grep -q "kubectl";then
|
||||
echo "kubectl client-side manager not removed"
|
||||
exit 1
|
||||
fi
|
||||
kubectl -n managed-fields apply --server-side --force-conflicts -f /tmp/podinfo.yaml
|
||||
kubectl -n managed-fields annotate --overwrite kustomization/podinfo reconcile.fluxcd.io/requestedAt="$(date +%s)"
|
||||
kubectl -n managed-fields wait kustomization/podinfo --for=condition=ready --timeout=4m
|
||||
OUTDATA=$(kubectl -n managed-fields get deploy podinfo --show-managed-fields -oyaml)
|
||||
if echo "$OUTDATA" | grep -q "kubectl";then
|
||||
echo "kubectl server-side manager not removed"
|
||||
exit 1
|
||||
fi
|
||||
kubectl delete ns managed-fields
|
||||
- name: Run overlays tests
|
||||
run: |
|
||||
kubectl -n kustomize-system apply -k ./config/testdata/overlays
|
||||
kubectl -n kustomize-system wait kustomizations/webapp-staging --for=condition=ready --timeout=4m
|
||||
kubectl -n kustomize-system wait kustomizations/webapp-production --for=condition=ready --timeout=4m
|
||||
- name: Run dependencies tests
|
||||
run: |
|
||||
kubectl -n kustomize-system apply -k ./config/testdata/dependencies
|
||||
kubectl -n kustomize-system wait kustomizations/common --for=condition=ready --timeout=4m
|
||||
kubectl -n kustomize-system wait kustomizations/backend --for=condition=ready --timeout=4m
|
||||
kubectl -n kustomize-system wait kustomizations/frontend --for=condition=ready --timeout=4m
|
||||
- name: Run impersonation tests
|
||||
run: |
|
||||
kubectl -n impersonation apply -f ./config/testdata/impersonation
|
||||
kubectl -n impersonation wait kustomizations/podinfo --for=condition=ready --timeout=4m
|
||||
kubectl -n impersonation delete kustomizations/podinfo
|
||||
until kubectl -n impersonation get deploy/podinfo 2>&1 | grep NotFound ; do sleep 2; done
|
||||
- name: Run OCI tests
|
||||
run: |
|
||||
kubectl create ns oci
|
||||
kubectl -n oci apply -f ./config/testdata/oci
|
||||
kubectl -n oci wait kustomizations/oci --for=condition=ready --timeout=4m
|
||||
- name: Run CRDs + CRs tests
|
||||
run: |
|
||||
kubectl -n kustomize-system apply -f ./config/testdata/crds-crs
|
||||
kubectl -n kustomize-system wait kustomizations/certs --for=condition=ready --timeout=4m
|
||||
kubectl -n kustomizer-cert-test wait issuers/my-ca-issuer --for=condition=ready --timeout=1m
|
||||
- name: Logs
|
||||
run: |
|
||||
kubectl -n kustomize-system logs deploy/source-controller
|
||||
kubectl apply -k ./config/testdata/webapp
|
||||
kubectl apply -k ./config/testdata/generate
|
||||
kubectl wait kustomizations/frontend --for=condition=ready --timeout=4m
|
||||
kubectl wait kustomizations/generate --for=condition=ready --timeout=4m
|
||||
kubectl -n kustomize-system logs deploy/kustomize-controller
|
||||
- name: Debug failure
|
||||
if: failure()
|
||||
run: |
|
||||
kubectl -n kustomize-system get gitrepositories -oyaml
|
||||
kubectl -n kustomize-system get kustomizations -oyaml
|
||||
kubectl get gitrepositories -oyaml
|
||||
kubectl get kustomizations -oyaml
|
||||
kubectl -n kustomize-system get all
|
||||
kubectl -n oci get ocirepository/oci -oyaml
|
||||
kubectl -n oci get kustomization/oci -oyaml
|
||||
kubectl -n kustomize-system logs deploy/source-controller
|
||||
kubectl -n kustomize-system logs deploy/kustomize-controller
|
||||
kubectl -n kustomize-system logs deploy/kustomize-controller
|
|
@ -1,35 +0,0 @@
|
|||
name: nightly
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 0 * * *'
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
REPOSITORY: ${{ github.repository }}
|
||||
|
||||
permissions:
|
||||
contents: read # for actions/checkout to fetch code
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
- name: Setup QEMU
|
||||
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0
|
||||
- name: Setup Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
|
||||
with:
|
||||
buildkitd-flags: "--debug"
|
||||
- name: Build multi-arch container image
|
||||
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
|
||||
with:
|
||||
push: false
|
||||
builder: ${{ steps.buildx.outputs.name }}
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
platforms: linux/amd64,linux/arm/v7,linux/arm64
|
||||
tags: |
|
||||
${{ env.REPOSITORY }}:nightly
|
|
@ -3,158 +3,50 @@ on:
|
|||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: 'image tag prefix'
|
||||
default: 'rc'
|
||||
required: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
CONTROLLER: ${{ github.event.repository.name }}
|
||||
|
||||
jobs:
|
||||
release:
|
||||
outputs:
|
||||
hashes: ${{ steps.slsa.outputs.hashes }}
|
||||
image_url: ${{ steps.slsa.outputs.image_url }}
|
||||
image_digest: ${{ steps.slsa.outputs.image_digest }}
|
||||
build-push:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write # for creating the GitHub release.
|
||||
id-token: write # for creating OIDC tokens for signing.
|
||||
packages: write # for pushing and signing container images.
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup Kustomize
|
||||
uses: fluxcd/pkg/actions/kustomize@main
|
||||
- name: Prepare
|
||||
id: prep
|
||||
run: |
|
||||
VERSION="${{ github.event.inputs.tag }}-${GITHUB_SHA::8}"
|
||||
if [[ $GITHUB_REF == refs/tags/* ]]; then
|
||||
VERSION=${GITHUB_REF/refs\/tags\//}
|
||||
fi
|
||||
echo "BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_OUTPUT
|
||||
echo "VERSION=${VERSION}" >> $GITHUB_OUTPUT
|
||||
- name: Setup QEMU
|
||||
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0
|
||||
- name: Setup Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: fluxcdbot
|
||||
password: ${{ secrets.GHCR_TOKEN }}
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0
|
||||
with:
|
||||
username: fluxcdbot
|
||||
password: ${{ secrets.DOCKER_FLUXCD_PASSWORD }}
|
||||
- name: Generate images meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f # v5.8.0
|
||||
with:
|
||||
images: |
|
||||
fluxcd/${{ env.CONTROLLER }}
|
||||
ghcr.io/fluxcd/${{ env.CONTROLLER }}
|
||||
tags: |
|
||||
type=raw,value=${{ steps.prep.outputs.VERSION }}
|
||||
- name: Publish images
|
||||
id: build-push
|
||||
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
|
||||
with:
|
||||
sbom: true
|
||||
provenance: true
|
||||
push: true
|
||||
builder: ${{ steps.buildx.outputs.name }}
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
platforms: linux/amd64,linux/arm/v7,linux/arm64
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
- uses: sigstore/cosign-installer@d58896d6a1865668819e1d91763c7751a165e159 # v3.9.2
|
||||
- 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 }}
|
||||
- name: Generate release artifacts
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
uses: ./.github/actions/kustomize
|
||||
- name: Get version
|
||||
id: get_version
|
||||
run: echo ::set-output name=VERSION::${GITHUB_REF/refs\/tags\//}
|
||||
- name: Generate release asset
|
||||
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@da167eac915b4e86f08b264dbdbc867b61be6f0c # v0.20.5
|
||||
- name: Create release and SBOM
|
||||
id: run-goreleaser
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
uses: goreleaser/goreleaser-action@e435ccd777264be153ace6237001ef4d979d3a7a # v6.4.0
|
||||
cp config/default/* config/release
|
||||
cd config/release
|
||||
kustomize edit set image fluxcd/kustomize-controller=fluxcd/kustomize-controller:${{ steps.get_version.outputs.VERSION }}
|
||||
kustomize build . > kustomize-controller.yaml
|
||||
- name: Push image
|
||||
uses: docker/build-push-action@v1
|
||||
with:
|
||||
version: latest
|
||||
args: release --clean --skip=validate
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
repository: fluxcd/kustomize-controller
|
||||
tag_with_ref: true
|
||||
- name: Create release
|
||||
id: create_release
|
||||
uses: actions/create-release@latest
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Generate SLSA metadata
|
||||
id: slsa
|
||||
with:
|
||||
tag_name: ${{ github.ref }}
|
||||
release_name: ${{ github.ref }}
|
||||
draft: false
|
||||
prerelease: true
|
||||
body: |
|
||||
[CHANGELOG](https://github.com/fluxcd/kustomize-controller/blob/master/CHANGELOG.md)
|
||||
- name: Upload artifacts
|
||||
id: upload-release-asset
|
||||
uses: actions/upload-release-asset@v1
|
||||
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 }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: ./config/release/kustomize-controller.yaml
|
||||
asset_name: kustomize-controller.yaml
|
||||
asset_content_type: text/plain
|
||||
|
|
|
@ -1,52 +0,0 @@
|
|||
name: scan
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
schedule:
|
||||
- cron: '18 10 * * 3'
|
||||
|
||||
permissions:
|
||||
contents: read # for actions/checkout to fetch code
|
||||
security-events: write # for codeQL to write security events
|
||||
|
||||
jobs:
|
||||
fossa:
|
||||
name: FOSSA
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
- name: Run FOSSA scan and upload build data
|
||||
uses: fossa-contrib/fossa-action@3d2ef181b1820d6dcd1972f86a767d18167fa19b # v3.0.1
|
||||
with:
|
||||
# FOSSA Push-Only API Token
|
||||
fossa-api-key: 5ee8bf422db1471e0bcf2bcb289185de
|
||||
github-token: ${{ github.token }}
|
||||
|
||||
codeql:
|
||||
name: CodeQL
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
|
||||
with:
|
||||
go-version: 1.25.x
|
||||
cache-dependency-path: |
|
||||
**/go.sum
|
||||
**/go.mod
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@3c3833e0f8c1c83d449a7478aa59c036a9165498 # v3.29.11
|
||||
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@3c3833e0f8c1c83d449a7478aa59c036a9165498 # v3.29.11
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@3c3833e0f8c1c83d449a7478aa59c036a9165498 # v3.29.11
|
|
@ -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@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
- 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
|
|
@ -1,27 +1,17 @@
|
|||
# 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
|
||||
config/crd/bases/externalartifacts.yaml
|
||||
|
||||
build/
|
||||
|
||||
# CRDs for fuzzing tests.
|
||||
internal/controllers/testdata/crd
|
||||
|
|
|
@ -1,57 +0,0 @@
|
|||
project_name: kustomize-controller
|
||||
|
||||
builds:
|
||||
- skip: true
|
||||
|
||||
release:
|
||||
extra_files:
|
||||
- glob: config/release/*.yaml
|
||||
prerelease: "auto"
|
||||
header: |
|
||||
## Changelog
|
||||
|
||||
[{{.Tag}} changelog](https://github.com/fluxcd/{{.ProjectName}}/blob/{{.Tag}}/CHANGELOG.md)
|
||||
footer: |
|
||||
## Container images
|
||||
|
||||
- `docker.io/fluxcd/{{.ProjectName}}:{{.Tag}}`
|
||||
- `ghcr.io/fluxcd/{{.ProjectName}}:{{.Tag}}`
|
||||
|
||||
Supported architectures: `linux/amd64`, `linux/arm64` and `linux/arm/v7`.
|
||||
|
||||
The container images are built on GitHub hosted runners and are signed with cosign and GitHub OIDC.
|
||||
To verify the images and their provenance (SLSA level 3), please see the [security documentation](https://fluxcd.io/flux/security/).
|
||||
|
||||
changelog:
|
||||
disable: true
|
||||
|
||||
checksum:
|
||||
extra_files:
|
||||
- glob: config/release/*.yaml
|
||||
|
||||
source:
|
||||
enabled: true
|
||||
name_template: "{{ .ProjectName }}_{{ .Version }}_source_code"
|
||||
|
||||
sboms:
|
||||
- id: source
|
||||
artifacts: source
|
||||
documents:
|
||||
- "{{ .ProjectName }}_{{ .Version }}_sbom.spdx.json"
|
||||
|
||||
# signs the checksum file
|
||||
# all files (including the sboms) are included in the checksum
|
||||
# https://goreleaser.com/customization/sign
|
||||
signs:
|
||||
- cmd: cosign
|
||||
env:
|
||||
- COSIGN_EXPERIMENTAL=1
|
||||
certificate: "${artifact}.pem"
|
||||
args:
|
||||
- sign-blob
|
||||
- "--yes"
|
||||
- "--output-certificate=${certificate}"
|
||||
- "--output-signature=${signature}"
|
||||
- "${artifact}"
|
||||
artifacts: checksum
|
||||
output: true
|
2408
CHANGELOG.md
2408
CHANGELOG.md
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,73 @@
|
|||
# Contributing
|
||||
|
||||
Kustomize Controller is [Apache 2.0 licensed](LICENSE) and accepts contributions
|
||||
via GitHub pull requests. This document outlines some of the conventions on
|
||||
to make it easier to get your contribution accepted.
|
||||
|
||||
We gratefully welcome improvements to issues and documentation as well as to
|
||||
code.
|
||||
|
||||
## Certificate of Origin
|
||||
|
||||
By contributing to this project you agree to the Developer Certificate of
|
||||
Origin (DCO). This document was created by the Linux Kernel community and is a
|
||||
simple statement that you, as a contributor, have the legal right to make the
|
||||
contribution. No action from you is required, but it's a good idea to see the
|
||||
[DCO](DCO) file for details before you start contributing code to Kustomize
|
||||
Controller.
|
||||
|
||||
## Communications
|
||||
|
||||
The project uses Slack: To join the conversation, simply join the
|
||||
[CNCF](https://slack.cncf.io/) Slack workspace and use the
|
||||
[#flux](https://cloud-native.slack.com/messages/flux/) channel.
|
||||
|
||||
The developers use a mailing list to discuss development as well.
|
||||
Simply subscribe to [flux-dev on cncf.io](https://lists.cncf.io/g/cncf-flux-dev)
|
||||
to join the conversation (this will also add an invitation to your
|
||||
Google calendar for our [Flux
|
||||
meeting](https://docs.google.com/document/d/1l_M0om0qUEN_NNiGgpqJ2tvsF2iioHkaARDeh6b70B0/edit#)).
|
||||
|
||||
### How to run the test suite
|
||||
|
||||
Prerequisites:
|
||||
* go >= 1.13
|
||||
* kubebuilder >= 2.3
|
||||
* kustomize >= 3.1
|
||||
|
||||
You can run the unit tests by simply doing
|
||||
|
||||
```bash
|
||||
make test
|
||||
```
|
||||
|
||||
## Acceptance policy
|
||||
|
||||
These things will make a PR more likely to be accepted:
|
||||
|
||||
- a well-described requirement
|
||||
- tests for new code
|
||||
- tests for old code!
|
||||
- new code and tests follow the conventions in old code and tests
|
||||
- a good commit message (see below)
|
||||
- all code must abide [Go Code Review Comments](https://github.com/golang/go/wiki/CodeReviewComments)
|
||||
- names should abide [What's in a name](https://talks.golang.org/2014/names.slide#1)
|
||||
- code must build on both Linux and Darwin, via plain `go build`
|
||||
- code should have appropriate test coverage and tests should be written
|
||||
to work with `go test`
|
||||
|
||||
In general, we will merge a PR once one maintainer has endorsed it.
|
||||
For substantial changes, more people may become involved, and you might
|
||||
get asked to resubmit the PR or divide the changes into more than one PR.
|
||||
|
||||
### Format of the Commit Message
|
||||
|
||||
For Kustomize Controller we prefer the following rules for good commit messages:
|
||||
|
||||
- Limit the subject to 50 characters and write as the continuation
|
||||
of the sentence "If applied, this commit will ..."
|
||||
- Explain what and why in the body, if more than a trivial change;
|
||||
wrap it at 72 characters.
|
||||
|
||||
The [following article](https://chris.beams.io/posts/git-commit/#seven-rules)
|
||||
has some more helpful advice on documenting your work.
|
|
@ -1,94 +0,0 @@
|
|||
# Development
|
||||
|
||||
> **Note:** Please take a look at <https://fluxcd.io/contributing/flux/>
|
||||
> to find out about how to contribute to Flux and how to interact with the
|
||||
> Flux Development team.
|
||||
|
||||
## Installing required dependencies
|
||||
|
||||
There are a number of dependencies required to be able to run the controller and its test suite locally:
|
||||
|
||||
- [Install Go](https://golang.org/doc/install)
|
||||
- [Install Kustomize](https://kubernetes-sigs.github.io/kustomize/installation/)
|
||||
- [Install Docker](https://docs.docker.com/engine/install/)
|
||||
- (Optional) [Install Kubebuilder](https://book.kubebuilder.io/quick-start.html#installation)
|
||||
|
||||
## How to run the test suite
|
||||
|
||||
Prerequisites:
|
||||
* Go >= 1.25
|
||||
|
||||
You can run the test suite by simply doing
|
||||
|
||||
```sh
|
||||
make test
|
||||
```
|
||||
|
||||
## How to run the controller locally
|
||||
|
||||
Install the controller's CRDs on your test cluster:
|
||||
|
||||
```sh
|
||||
make install
|
||||
```
|
||||
|
||||
Note that `kustomize-controller` depends on [source-controller](https://github.com/fluxcd/source-controller) to acquire its artifacts. If `source-controller` is not running on your test cluster, you need to tell `kustomize-controller` where to find it.
|
||||
|
||||
Port forward to source-controller artifacts server:
|
||||
|
||||
```sh
|
||||
kubectl -n flux-system port-forward svc/source-controller 8080:80
|
||||
```
|
||||
|
||||
Export the local address as `SOURCE_CONTROLLER_LOCALHOST`:
|
||||
|
||||
```sh
|
||||
export SOURCE_CONTROLLER_LOCALHOST=localhost:8080
|
||||
```
|
||||
|
||||
Alternatively, if your test cluster is already running `source-controller` and `kustomize-controller`, you need to scale down the in-cluster `kustomize-controller`:
|
||||
|
||||
```
|
||||
kubectl -n flux-system scale deployment/kustomize-controller --replicas=0
|
||||
```
|
||||
|
||||
Run the controller locally:
|
||||
|
||||
```sh
|
||||
make run
|
||||
```
|
||||
|
||||
## How to install the controller
|
||||
|
||||
### Building the container image
|
||||
|
||||
Set the name of the container image to be created from the source code. This will be used when building, pushing and referring to the image on YAML files:
|
||||
|
||||
```sh
|
||||
export IMG=registry-path/kustomize-controller:latest
|
||||
```
|
||||
|
||||
Build the container image, tagging it as `$(IMG)`:
|
||||
|
||||
```sh
|
||||
make docker-build
|
||||
```
|
||||
|
||||
Push the image into the repository:
|
||||
|
||||
```sh
|
||||
make docker-push
|
||||
```
|
||||
|
||||
**Note**: `make docker-build` will build an image for the `amd64` architecture.
|
||||
|
||||
|
||||
### Deploying into a cluster
|
||||
|
||||
Deploy `kustomize-controller` into the cluster that is configured in the local kubeconfig file (i.e. `~/.kube/config`):
|
||||
|
||||
```sh
|
||||
make deploy
|
||||
```
|
||||
|
||||
Running the above will also deploy `source-controller` and its CRDs to the cluster.
|
40
Dockerfile
40
Dockerfile
|
@ -1,19 +1,15 @@
|
|||
ARG GO_VERSION=1.25
|
||||
ARG XX_VERSION=1.6.1
|
||||
|
||||
FROM --platform=$BUILDPLATFORM tonistiigi/xx:${XX_VERSION} AS xx
|
||||
|
||||
FROM --platform=$BUILDPLATFORM golang:${GO_VERSION}-alpine AS builder
|
||||
|
||||
# Copy the build utilities.
|
||||
COPY --from=xx / /
|
||||
|
||||
ARG TARGETPLATFORM
|
||||
FROM golang:1.13 as builder
|
||||
|
||||
WORKDIR /workspace
|
||||
|
||||
# copy api submodule
|
||||
COPY api/ api/
|
||||
RUN kustomize_ver=3.5.4 && \
|
||||
kustomize_url=https://github.com/kubernetes-sigs/kustomize/releases/download && \
|
||||
curl -sL ${kustomize_url}/kustomize%2Fv${kustomize_ver}/kustomize_v${kustomize_ver}_linux_amd64.tar.gz | \
|
||||
tar xz && mv kustomize /usr/local/bin/kustomize
|
||||
|
||||
RUN kubectl_ver=1.18.2 && \
|
||||
curl -sL https://storage.googleapis.com/kubernetes-release/release/v${kubectl_ver}/bin/linux/amd64/kubectl \
|
||||
-o /usr/local/bin/kubectl && chmod +x /usr/local/bin/kubectl
|
||||
|
||||
# copy modules manifests
|
||||
COPY go.mod go.mod
|
||||
|
@ -24,23 +20,23 @@ RUN go mod download
|
|||
|
||||
# copy source code
|
||||
COPY main.go main.go
|
||||
COPY api/ api/
|
||||
COPY controllers/ controllers/
|
||||
COPY internal/ internal/
|
||||
|
||||
# build
|
||||
ENV CGO_ENABLED=0
|
||||
RUN xx-go build -trimpath -a -o kustomize-controller main.go
|
||||
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GO111MODULE=on go build -a -o kustomize-controller main.go
|
||||
|
||||
FROM alpine:3.22
|
||||
FROM alpine:3.11
|
||||
|
||||
ARG TARGETPLATFORM
|
||||
|
||||
RUN apk --no-cache add ca-certificates tini git openssh-client gnupg \
|
||||
&& update-ca-certificates
|
||||
RUN apk add --no-cache openssh-client ca-certificates tini 'git>=2.12.0' socat curl bash
|
||||
|
||||
COPY --from=builder /usr/local/bin/kustomize /usr/local/bin/
|
||||
COPY --from=builder /usr/local/bin/kubectl /usr/local/bin/
|
||||
COPY --from=builder /workspace/kustomize-controller /usr/local/bin/
|
||||
|
||||
USER 65534:65534
|
||||
RUN addgroup -S controller && adduser -S -g controller controller
|
||||
|
||||
ENV GNUPGHOME=/tmp
|
||||
USER controller
|
||||
|
||||
ENTRYPOINT [ "/sbin/tini", "--", "kustomize-controller" ]
|
||||
|
|
|
@ -2,7 +2,6 @@ The maintainers are generally available in Slack at
|
|||
https://cloud-native.slack.com in #flux (https://cloud-native.slack.com/messages/CLAJ40HV3)
|
||||
(obtain an invitation at https://slack.cncf.io/).
|
||||
|
||||
This project shares maintainers from the main Flux v2 git repository,
|
||||
as listed in
|
||||
In alphabetical order:
|
||||
|
||||
https://github.com/fluxcd/flux2/blob/main/MAINTAINERS
|
||||
Stefan Prodan, Weaveworks <stefan@weave.works> (github: @stefanprodan, slack: stefanprodan)
|
||||
|
|
194
Makefile
194
Makefile
|
@ -1,105 +1,29 @@
|
|||
|
||||
# Image URL to use all building/pushing image targets
|
||||
IMG ?= fluxcd/kustomize-controller:latest
|
||||
# Produce CRDs that work back to Kubernetes 1.16
|
||||
CRD_OPTIONS ?= crd:crdVersions=v1
|
||||
SOURCE_VER ?= $(shell go list -m all | grep github.com/fluxcd/source-controller/api | awk '{print $$2}')
|
||||
# Produce CRDs that work back to Kubernetes 1.13
|
||||
CRD_OPTIONS ?= crd
|
||||
|
||||
# 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}')
|
||||
|
||||
# Repository root based on Git metadata
|
||||
REPOSITORY_ROOT := $(shell git rev-parse --show-toplevel)
|
||||
BUILD_DIR := $(REPOSITORY_ROOT)/build
|
||||
|
||||
# FUZZ_TIME defines the max amount of time, in Go Duration,
|
||||
# each fuzzer should run for.
|
||||
FUZZ_TIME ?= 1m
|
||||
|
||||
# If gobin not set, create one on ./build and add to path.
|
||||
# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
|
||||
ifeq (,$(shell go env GOBIN))
|
||||
GOBIN=$(BUILD_DIR)/gobin
|
||||
GOBIN=$(shell go env GOPATH)/bin
|
||||
else
|
||||
GOBIN=$(shell go env GOBIN)
|
||||
endif
|
||||
export PATH:=$(GOBIN):${PATH}
|
||||
|
||||
# Allows for defining additional Go test args, e.g. '-tags integration'.
|
||||
GO_TEST_ARGS ?=
|
||||
|
||||
# Allows for defining additional Docker buildx arguments, e.g. '--push'.
|
||||
BUILD_ARGS ?= --load
|
||||
# Architectures to build images for.
|
||||
BUILD_PLATFORMS ?= linux/amd64
|
||||
|
||||
# Architecture to use envtest with
|
||||
ENVTEST_ARCH ?= amd64
|
||||
|
||||
# Paths to download the CRD dependencies at.
|
||||
GITREPO_CRD ?= config/crd/bases/gitrepositories.yaml
|
||||
BUCKET_CRD ?= config/crd/bases/buckets.yaml
|
||||
OCIREPO_CRD ?= config/crd/bases/ocirepositories.yaml
|
||||
EA_CRD ?= config/crd/bases/externalartifacts.yaml
|
||||
|
||||
# Keep a record of the version of the downloaded source CRDs. It is used to
|
||||
# detect and download new CRDs when the SOURCE_VER changes.
|
||||
SOURCE_CRD_VER=$(BUILD_DIR)/.src-crd-$(SOURCE_VER)
|
||||
|
||||
# API (doc) generation utilities
|
||||
CONTROLLER_GEN_VERSION ?= v0.19.0
|
||||
GEN_API_REF_DOCS_VERSION ?= e327d0730470cbd61b06300f81c5fcf91c23c113
|
||||
|
||||
all: manager
|
||||
|
||||
# Download the envtest binaries to testbin
|
||||
ENVTEST_ASSETS_DIR=$(BUILD_DIR)/testbin
|
||||
ENVTEST_KUBERNETES_VERSION?=latest
|
||||
install-envtest: setup-envtest
|
||||
mkdir -p ${ENVTEST_ASSETS_DIR}
|
||||
$(ENVTEST) use $(ENVTEST_KUBERNETES_VERSION) --arch=$(ENVTEST_ARCH) --bin-dir=$(ENVTEST_ASSETS_DIR)
|
||||
|
||||
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))
|
||||
|
||||
# Run controller tests
|
||||
KUBEBUILDER_ASSETS?="$(shell $(ENVTEST) --arch=$(ENVTEST_ARCH) use -i $(ENVTEST_KUBERNETES_VERSION) --bin-dir=$(ENVTEST_ASSETS_DIR) -p path)"
|
||||
test: tidy generate fmt vet manifests api-docs download-crd-deps install-envtest $(SOPS)
|
||||
KUBEBUILDER_ASSETS=$(KUBEBUILDER_ASSETS) go test ./... $(GO_TEST_ARGS) -v -coverprofile cover.out
|
||||
# Run tests
|
||||
test: generate fmt vet manifests
|
||||
go test ./... -coverprofile cover.out
|
||||
|
||||
# Build manager binary
|
||||
manager: generate fmt vet
|
||||
go build -o $(BUILD_DIR)/bin/manager main.go
|
||||
go build -o bin/manager main.go
|
||||
|
||||
# Run against the configured Kubernetes cluster in ~/.kube/config
|
||||
run: generate fmt vet manifests
|
||||
go run ./main.go --metrics-addr=:8089
|
||||
|
||||
# Delete previously downloaded CRDs and record the new version of the source
|
||||
# CRDs.
|
||||
$(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):
|
||||
curl -s https://raw.githubusercontent.com/fluxcd/source-controller/${SOURCE_VER}/config/crd/bases/source.toolkit.fluxcd.io_gitrepositories.yaml -o $(GITREPO_CRD)
|
||||
|
||||
$(BUCKET_CRD):
|
||||
curl -s https://raw.githubusercontent.com/fluxcd/source-controller/${SOURCE_VER}/config/crd/bases/source.toolkit.fluxcd.io_buckets.yaml -o $(BUCKET_CRD)
|
||||
|
||||
$(OCIREPO_CRD):
|
||||
curl -s https://raw.githubusercontent.com/fluxcd/source-controller/${SOURCE_VER}/config/crd/bases/source.toolkit.fluxcd.io_ocirepositories.yaml -o $(OCIREPO_CRD)
|
||||
|
||||
$(EA_CRD):
|
||||
curl -s https://raw.githubusercontent.com/fluxcd/source-controller/${SOURCE_VER}/config/crd/bases/source.toolkit.fluxcd.io_externalartifacts.yaml -o $(EA_CRD)
|
||||
|
||||
# Download the CRDs the controller depends on
|
||||
download-crd-deps: $(SOURCE_CRD_VER) $(GITREPO_CRD) $(BUCKET_CRD) $(OCIREPO_CRD) $(EA_CRD)
|
||||
|
||||
# Delete the downloaded CRD dependencies.
|
||||
cleanup-crd-deps:
|
||||
rm -f $(GITREPO_CRD) $(BUCKET_CRD) $(OCIREPO_CRD) $(EA_CRD)
|
||||
go run ./main.go
|
||||
|
||||
# Install CRDs into a cluster
|
||||
install: manifests
|
||||
|
@ -130,101 +54,41 @@ dev-cleanup: manifests
|
|||
|
||||
# Generate manifests e.g. CRD, RBAC etc.
|
||||
manifests: controller-gen
|
||||
$(CONTROLLER_GEN) $(CRD_OPTIONS) rbac:roleName=manager-role paths="./..." output:crd:artifacts:config="config/crd/bases"
|
||||
cd api; $(CONTROLLER_GEN) $(CRD_OPTIONS) rbac:roleName=manager-role paths="./..." output:crd:artifacts:config="../config/crd/bases"
|
||||
|
||||
# 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
|
||||
|
||||
# Run go mod tidy
|
||||
tidy:
|
||||
cd api; rm -f go.sum; go mod tidy -compat=1.25
|
||||
rm -f go.sum; go mod tidy -compat=1.25
|
||||
$(CONTROLLER_GEN) $(CRD_OPTIONS) rbac:roleName=manager-role paths="./..." output:crd:artifacts:config=config/crd/bases
|
||||
|
||||
# Run go fmt against code
|
||||
fmt:
|
||||
go fmt ./...
|
||||
cd api; go fmt ./...
|
||||
|
||||
# Run go vet against code
|
||||
vet:
|
||||
go vet ./...
|
||||
cd api; go vet ./...
|
||||
|
||||
# Generate code
|
||||
generate: controller-gen
|
||||
cd api; $(CONTROLLER_GEN) object:headerFile="../hack/boilerplate.go.txt" paths="./..."
|
||||
$(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./..."
|
||||
|
||||
# Build the docker image
|
||||
docker-build:
|
||||
docker buildx build \
|
||||
--platform=$(BUILD_PLATFORMS) \
|
||||
-t ${IMG} \
|
||||
${BUILD_ARGS} .
|
||||
docker build . -t ${IMG}
|
||||
|
||||
# Push the docker image
|
||||
docker-push:
|
||||
docker push ${IMG}
|
||||
|
||||
# Set the docker image in-cluster
|
||||
docker-deploy:
|
||||
kubectl -n flux-system set image deployment/kustomize-controller manager=${IMG}
|
||||
|
||||
# Find or download controller-gen
|
||||
CONTROLLER_GEN = $(GOBIN)/controller-gen
|
||||
.PHONY: controller-gen
|
||||
controller-gen: ## Download controller-gen locally if necessary.
|
||||
$(call go-install-tool,$(CONTROLLER_GEN),sigs.k8s.io/controller-tools/cmd/controller-gen@$(CONTROLLER_GEN_VERSION))
|
||||
|
||||
# Find or download gen-crd-api-reference-docs
|
||||
GEN_CRD_API_REFERENCE_DOCS = $(GOBIN)/gen-crd-api-reference-docs
|
||||
.PHONY: gen-crd-api-reference-docs
|
||||
gen-crd-api-reference-docs: ## Download gen-crd-api-reference-docs locally if necessary
|
||||
$(call go-install-tool,$(GEN_CRD_API_REFERENCE_DOCS),github.com/ahmetb/gen-crd-api-reference-docs@$(GEN_API_REF_DOCS_VERSION))
|
||||
|
||||
ENVTEST = $(GOBIN)/setup-envtest
|
||||
.PHONY: envtest
|
||||
setup-envtest: ## Download envtest-setup locally if necessary.
|
||||
$(call go-install-tool,$(ENVTEST),sigs.k8s.io/controller-runtime/tools/setup-envtest@latest)
|
||||
|
||||
# go-install-tool will 'go install' any package $2 and install it to $1.
|
||||
PROJECT_DIR := $(shell dirname $(abspath $(lastword $(MAKEFILE_LIST))))
|
||||
define go-install-tool
|
||||
@[ -f $(1) ] || { \
|
||||
set -e ;\
|
||||
TMP_DIR=$$(mktemp -d) ;\
|
||||
cd $$TMP_DIR ;\
|
||||
go mod init tmp ;\
|
||||
echo "Downloading $(2)" ;\
|
||||
GOBIN=$(GOBIN) go install $(2) ;\
|
||||
rm -rf $$TMP_DIR ;\
|
||||
}
|
||||
endef
|
||||
|
||||
# Build fuzzers used by oss-fuzz.
|
||||
fuzz-build:
|
||||
rm -rf $(BUILD_DIR)/fuzz/
|
||||
mkdir -p $(BUILD_DIR)/fuzz/out/
|
||||
|
||||
docker build . --pull --tag local-fuzzing:latest -f tests/fuzz/Dockerfile.builder
|
||||
docker run --rm \
|
||||
-e FUZZING_LANGUAGE=go -e SANITIZER=address \
|
||||
-e CIFUZZ_DEBUG='True' -e OSS_FUZZ_PROJECT_NAME=fluxcd \
|
||||
-v "$(shell go env GOMODCACHE):/root/go/pkg/mod" \
|
||||
-v "$(BUILD_DIR)/fuzz/out":/out \
|
||||
local-fuzzing:latest
|
||||
|
||||
# Run each fuzzer once to ensure they will work when executed by oss-fuzz.
|
||||
fuzz-smoketest: fuzz-build
|
||||
docker run --rm \
|
||||
-v "$(BUILD_DIR)/fuzz/out":/out \
|
||||
-v "$(shell pwd)/tests/fuzz/oss_fuzz_run.sh":/runner.sh \
|
||||
local-fuzzing:latest \
|
||||
bash -c "/runner.sh"
|
||||
|
||||
# Run fuzz tests for the duration set in FUZZ_TIME.
|
||||
fuzz-native:
|
||||
KUBEBUILDER_ASSETS=$(KUBEBUILDER_ASSETS) \
|
||||
FUZZ_TIME=$(FUZZ_TIME) \
|
||||
./tests/fuzz/native_go_run.sh
|
||||
# find or download controller-gen
|
||||
# download controller-gen if necessary
|
||||
controller-gen:
|
||||
ifeq (, $(shell which controller-gen))
|
||||
@{ \
|
||||
set -e ;\
|
||||
CONTROLLER_GEN_TMP_DIR=$$(mktemp -d) ;\
|
||||
cd $$CONTROLLER_GEN_TMP_DIR ;\
|
||||
go mod init tmp ;\
|
||||
go get sigs.k8s.io/controller-tools/cmd/controller-gen@v0.2.5 ;\
|
||||
rm -rf $$CONTROLLER_GEN_TMP_DIR ;\
|
||||
}
|
||||
CONTROLLER_GEN=$(GOBIN)/controller-gen
|
||||
else
|
||||
CONTROLLER_GEN=$(shell which controller-gen)
|
||||
endif
|
||||
|
|
11
PROJECT
11
PROJECT
|
@ -1,13 +1,10 @@
|
|||
domain: toolkit.fluxcd.io
|
||||
domain: fluxcd.io
|
||||
repo: github.com/fluxcd/kustomize-controller
|
||||
resources:
|
||||
- group: kustomize
|
||||
kind: Kustomization
|
||||
version: v1
|
||||
version: v1alpha1
|
||||
- group: kustomize
|
||||
kind: Kustomization
|
||||
version: v1beta2
|
||||
- group: kustomize
|
||||
kind: Kustomization
|
||||
version: v1beta1
|
||||
kind: Profile
|
||||
version: v1alpha1
|
||||
version: "2"
|
||||
|
|
304
README.md
304
README.md
|
@ -1,55 +1,299 @@
|
|||
# kustomize-controller
|
||||
|
||||
[](https://bestpractices.coreinfrastructure.org/projects/4787)
|
||||
[](https://github.com/fluxcd/kustomize-controller/actions)
|
||||
[](https://goreportcard.com/report/github.com/fluxcd/kustomize-controller)
|
||||
[](https://github.com/fluxcd/kustomize-controller/blob/main/LICENSE)
|
||||
[](https://github.com/fluxcd/kustomize-controller/blob/master/LICENSE)
|
||||
[](https://github.com/fluxcd/kustomize-controller/releases)
|
||||
|
||||
The kustomize-controller is a [Flux](https://github.com/fluxcd/flux2) component,
|
||||
specialized in running continuous delivery pipelines for infrastructure and workloads
|
||||
The kustomize-controller is a Kubernetes operator, specialized in running
|
||||
continuous delivery pipelines for infrastructure and workloads
|
||||
defined with Kubernetes manifests and assembled with Kustomize.
|
||||
|
||||
The cluster desired state is described through a Kubernetes Custom Resource named `Kustomization`.
|
||||
Based on the creation, mutation or removal of a `Kustomization` resource in the cluster,
|
||||
the controller performs actions to reconcile the cluster current state with the desired state.
|
||||
|
||||

|
||||
|
||||
## Features
|
||||
|
||||
Features:
|
||||
* watches for `Kustomization` objects
|
||||
* fetches artifacts produced by [source-controller](https://github.com/fluxcd/source-controller) from `Source` objects
|
||||
* watches `Source` objects for revision changes
|
||||
* generates the `kustomization.yaml` file if needed
|
||||
* generates Kubernetes manifests with Kustomize SDK
|
||||
* decrypts Kubernetes secrets with Mozilla SOPS and KMS
|
||||
* validates the generated manifests with Kubernetes server-side apply dry-run
|
||||
- detects drift between the desired and state and cluster state
|
||||
- corrects drift by patching objects with Kubernetes server-side apply
|
||||
* generates Kubernetes manifests with kustomize build
|
||||
* validates the build output with client-side or APIServer dry-run
|
||||
* applies the generated manifests on the cluster
|
||||
* prunes the Kubernetes objects removed from source
|
||||
* checks the health of the deployed workloads
|
||||
* runs `Kustomizations` in a specific order, taking into account the depends-on relationship
|
||||
* notifies whenever a `Kustomization` status changes
|
||||
* reports on Slack or Discord whenever a `Kustomization` status changes
|
||||
|
||||
## Specifications
|
||||
|
||||
* [API](docs/spec/v1/README.md)
|
||||
Specifications:
|
||||
* [API](docs/spec/v1alpha1/README.md)
|
||||
* [Controller](docs/spec/README.md)
|
||||
|
||||
## Guides
|
||||
## Usage
|
||||
|
||||
* [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/)
|
||||
* [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)
|
||||
The kustomize-controller is part of a composable GitOps toolkit and depends on
|
||||
[source-controller](https://github.com/fluxcd/source-controller) to provide the raw Kubernetes
|
||||
manifests and `kustomization.yaml` file.
|
||||
|
||||
## Roadmap
|
||||
### Install the controllers
|
||||
|
||||
The roadmap for the Flux family of projects can be found at <https://fluxcd.io/roadmap/>.
|
||||
Install source-controller with:
|
||||
|
||||
## Contributing
|
||||
```bash
|
||||
kustomize build https://github.com/fluxcd/source-controller//config/default?ref=v0.0.1-alpha.2 \
|
||||
kubectl apply -f-
|
||||
```
|
||||
|
||||
This project is Apache 2.0 licensed and accepts contributions via GitHub pull requests.
|
||||
To start contributing please see the [development guide](DEVELOPMENT.md).
|
||||
Install kustomize-controller with:
|
||||
|
||||
```bash
|
||||
kustomize build https://github.com/fluxcd/kustomize-controller//config/default?ref=v0.0.1-alpha.4 \
|
||||
kubectl apply -f-
|
||||
```
|
||||
|
||||
### Define a Git repository source
|
||||
|
||||
Create a source object that points to a Git repository containing Kubernetes and Kustomize manifests:
|
||||
|
||||
```yaml
|
||||
apiVersion: source.fluxcd.io/v1alpha1
|
||||
kind: GitRepository
|
||||
metadata:
|
||||
name: podinfo
|
||||
namespace: default
|
||||
spec:
|
||||
interval: 1m
|
||||
url: https://github.com/stefanprodan/podinfo-deploy
|
||||
ref:
|
||||
branch: master
|
||||
```
|
||||
|
||||
For private repositories, SSH or token based authentication can be
|
||||
[configured with Kubernetes secrets](https://github.com/fluxcd/source-controller/blob/master/docs/spec/v1alpha1/gitrepositories.md).
|
||||
|
||||
Save the above file and apply it on the cluster.
|
||||
You can wait for the source controller to assemble an artifact from the head of the repo master branch with:
|
||||
|
||||
```bash
|
||||
kubectl wait gitrepository/podinfo --for=condition=ready
|
||||
```
|
||||
|
||||
The source controller will check for new commits in the master branch every minute. You can force a git sync with:
|
||||
|
||||
```bash
|
||||
kubectl annotate --overwrite gitrepository/podinfo source.fluxcd.io/syncAt="$(date +%s)"
|
||||
```
|
||||
|
||||
### Define a kustomization
|
||||
|
||||
Create a kustomization object that uses the git repository defined above:
|
||||
|
||||
```yaml
|
||||
apiVersion: kustomize.fluxcd.io/v1alpha1
|
||||
kind: Kustomization
|
||||
metadata:
|
||||
name: podinfo-dev
|
||||
spec:
|
||||
interval: 5m
|
||||
path: "./overlays/dev/"
|
||||
prune: "env=dev"
|
||||
sourceRef:
|
||||
kind: GitRepository
|
||||
name: podinfo
|
||||
validation: client
|
||||
healthChecks:
|
||||
- kind: Deployment
|
||||
name: podinfo
|
||||
namespace: dev
|
||||
timeout: 80s
|
||||
```
|
||||
|
||||
> **Note** that if your repository contains only plain Kubernetes manifests,
|
||||
> you can configure the controller to
|
||||
> [automatically generate](docs/spec/v1alpha1/kustomization.md#generate-kustomizationyaml)
|
||||
> a kustomization.yaml file inside the specified path.
|
||||
|
||||
A detailed explanation of the Kustomization object and its fields
|
||||
can be found in the [specification doc](docs/spec/v1alpha1/README.md).
|
||||
|
||||
Based on the above definition, the kustomize-controller fetches the Git repository content from source-controller,
|
||||
generates Kubernetes manifests by running kustomize build inside `./overlays/dev/`,
|
||||
and validates them with a dry-run apply. If the manifests pass validation, the controller will apply them
|
||||
on the cluster and starts the health assessment of the deployed workload. If the health checks are passing, the
|
||||
Kustomization object status transitions to a ready state.
|
||||
|
||||

|
||||
|
||||
You can wait for the kustomize controller to complete the deployment with:
|
||||
|
||||
```bash
|
||||
kubectl wait kustomization/podinfo-dev --for=condition=ready
|
||||
```
|
||||
|
||||
When the controller finishes the reconciliation, it will log the applied objects:
|
||||
|
||||
```bash
|
||||
kubectl -n kustomize-system logs deploy/kustomize-controller | jq .
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"level": "info",
|
||||
"ts": 1587195448.071468,
|
||||
"logger": "controllers.Kustomization",
|
||||
"msg": "Kustomization applied in 1.436096591s",
|
||||
"kustomization": "default/podinfo-dev",
|
||||
"output": {
|
||||
"namespace/dev": "created",
|
||||
"service/podinfo": "created",
|
||||
"deployment.apps/podinfo": "created",
|
||||
"horizontalpodautoscaler.autoscaling/podinfo": "created"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
You can trigger a kustomize build and apply any time with:
|
||||
|
||||
```bash
|
||||
kubectl annotate --overwrite kustomization/podinfo-dev kustomize.fluxcd.io/syncAt="$(date +%s)"
|
||||
```
|
||||
|
||||
When the source controller pulls a new Git revision, the kustomize controller will detect that the
|
||||
source revision changed, and will apply those changes right away.
|
||||
|
||||
If the kustomization build or apply fails, the controller sets the ready condition to `false` and logs the error:
|
||||
|
||||
```yaml
|
||||
status:
|
||||
conditions:
|
||||
- lastTransitionTime: "2020-04-16T07:27:58Z"
|
||||
message: 'apply failed'
|
||||
reason: ApplyFailed
|
||||
status: "False"
|
||||
type: Ready
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"kustomization": "default/podinfo-dev",
|
||||
"error": "Error from server (NotFound): error when creating \"podinfo-dev.yaml\": namespaces \"dev\" not found\n"
|
||||
}
|
||||
```
|
||||
|
||||
### Control the execution order
|
||||
|
||||
When running a kustomization, you may need to make sure other kustomizations have been
|
||||
successfully applied beforehand. A kustomization can specify a list of dependencies with `spec.dependsOn`.
|
||||
When combined with health assessment, a kustomization will run after all its dependencies health checks are passing.
|
||||
|
||||
For example, a service mesh proxy injector should be running before deploying applications inside the mesh:
|
||||
|
||||
```yaml
|
||||
apiVersion: kustomize.fluxcd.io/v1alpha1
|
||||
kind: Kustomization
|
||||
metadata:
|
||||
name: istio
|
||||
spec:
|
||||
interval: 10m
|
||||
path: "./profiles/default/"
|
||||
sourceRef:
|
||||
kind: GitRepository
|
||||
name: istio
|
||||
healthChecks:
|
||||
- kind: Deployment
|
||||
name: istiod
|
||||
namespace: istio-system
|
||||
timeout: 2m
|
||||
---
|
||||
apiVersion: kustomize.fluxcd.io/v1alpha1
|
||||
kind: Kustomization
|
||||
metadata:
|
||||
name: podinfo-dev
|
||||
spec:
|
||||
dependsOn:
|
||||
- istio
|
||||
interval: 5m
|
||||
path: "./overlays/dev/"
|
||||
prune: "env=dev"
|
||||
sourceRef:
|
||||
kind: GitRepository
|
||||
name: podinfo
|
||||
```
|
||||
|
||||
### Deploy releases to production
|
||||
|
||||
For production deployments, instead of synchronizing with a branch you can use a semver range to target stable releases:
|
||||
|
||||
```yaml
|
||||
apiVersion: source.fluxcd.io/v1alpha1
|
||||
kind: GitRepository
|
||||
metadata:
|
||||
name: podinfo-releases
|
||||
spec:
|
||||
interval: 5m
|
||||
url: https://github.com/stefanprodan/podinfo-deploy
|
||||
ref:
|
||||
semver: ">=0.0.1-rc.1 <1.0.0"
|
||||
```
|
||||
|
||||
With `ref.semver` we configure source controller to pull the Git tags and create an artifact from the most recent tag
|
||||
that matches the semver range.
|
||||
|
||||
Create a production kustomization and reference the git source that follows the latest semver release:
|
||||
|
||||
```yaml
|
||||
apiVersion: kustomize.fluxcd.io/v1alpha1
|
||||
kind: Kustomization
|
||||
metadata:
|
||||
name: podinfo-production
|
||||
spec:
|
||||
interval: 10m
|
||||
path: "./overlays/production/"
|
||||
sourceRef:
|
||||
kind: GitRepository
|
||||
name: podinfo-releases
|
||||
```
|
||||
|
||||
Based on the above definition, the kustomize controller will build and apply a kustomization that matches the semver range
|
||||
set in the Git repository manifest.
|
||||
|
||||
### Configure alerting
|
||||
|
||||
The kustomize controller can post message to Slack or Discord whenever a kustomization status changes.
|
||||
|
||||
Alerting can be configured by creating a profile that targets a list of kustomizations:
|
||||
|
||||
```yaml
|
||||
apiVersion: kustomize.fluxcd.io/v1alpha1
|
||||
kind: Profile
|
||||
metadata:
|
||||
name: default
|
||||
spec:
|
||||
alert:
|
||||
type: slack
|
||||
verbosity: info
|
||||
address: https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK
|
||||
username: kustomize-controller
|
||||
channel: general
|
||||
kustomizations:
|
||||
- '*'
|
||||
```
|
||||
|
||||
The alert provider type can be: `slack` or `discord` and the verbosity can be set to `info` or `error`.
|
||||
|
||||
The `*` wildcard tells the controller to use this profile for all kustomizations that are present
|
||||
in the same namespace as the profile.
|
||||
Multiple profiles can be used to send alerts to different channels or Slack organizations.
|
||||
|
||||
When the verbosity is set to `error`, the controller will alert on any error encountered during the
|
||||
reconciliation process. This includes kustomize build and validation errors, apply errors and
|
||||
health check failures.
|
||||
|
||||

|
||||
|
||||
When the verbosity is set to `info`, the controller will alert if:
|
||||
* a Kubernetes object was created, updated or deleted
|
||||
* heath checks are passing
|
||||
* a dependency is delaying the execution
|
||||
* an error occurs
|
||||
|
||||

|
||||
|
|
32
api/go.mod
32
api/go.mod
|
@ -1,32 +0,0 @@
|
|||
module github.com/fluxcd/kustomize-controller/api
|
||||
|
||||
go 1.25.0
|
||||
|
||||
require (
|
||||
github.com/fluxcd/pkg/apis/kustomize v1.12.0
|
||||
github.com/fluxcd/pkg/apis/meta v1.20.0
|
||||
k8s.io/apiextensions-apiserver v0.34.0
|
||||
k8s.io/apimachinery v0.34.0
|
||||
sigs.k8s.io/controller-runtime v0.22.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/kr/pretty v0.3.1 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.2 // indirect
|
||||
golang.org/x/net v0.43.0 // indirect
|
||||
golang.org/x/text v0.28.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
k8s.io/klog/v2 v2.130.1 // indirect
|
||||
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 // 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/v6 v6.3.0 // indirect
|
||||
sigs.k8s.io/yaml v1.6.0 // indirect
|
||||
)
|
119
api/go.sum
119
api/go.sum
|
@ -1,119 +0,0 @@
|
|||
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.12.0 h1:KvZN6xwgP/dNSeckL4a/Uv715XqiN1C3xS+jGcPejtE=
|
||||
github.com/fluxcd/pkg/apis/kustomize v1.12.0/go.mod h1:OojLxIdKm1JAAdh3sL4j4F+vfrLKb7kq1vr8bpyEKgg=
|
||||
github.com/fluxcd/pkg/apis/meta v1.20.0 h1:l9h0kWoDZTcYV0WJkFMgDXq6Q4tSojrJ+bHpFJSsaW0=
|
||||
github.com/fluxcd/pkg/apis/meta v1.20.0/go.mod h1:XUAEUgT4gkWDAEN79E141tmL+v4SV50tVZ/Ojpc/ueg=
|
||||
github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
|
||||
github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
|
||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo=
|
||||
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
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/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8=
|
||||
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/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/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/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/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.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
|
||||
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||
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/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
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.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
|
||||
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
|
||||
golang.org/x/sys v0.35.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.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
|
||||
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0=
|
||||
golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
k8s.io/api v0.34.0 h1:L+JtP2wDbEYPUeNGbeSa/5GwFtIA662EmT2YSLOkAVE=
|
||||
k8s.io/api v0.34.0/go.mod h1:YzgkIzOOlhl9uwWCZNqpw6RJy9L2FK4dlJeayUoydug=
|
||||
k8s.io/apiextensions-apiserver v0.34.0 h1:B3hiB32jV7BcyKcMU5fDaDxk882YrJ1KU+ZSkA9Qxoc=
|
||||
k8s.io/apiextensions-apiserver v0.34.0/go.mod h1:hLI4GxE1BDBy9adJKxUxCEHBGZtGfIg98Q+JmTD7+g0=
|
||||
k8s.io/apimachinery v0.34.0 h1:eR1WO5fo0HyoQZt1wdISpFDffnWOvFLOOeJ7MgIv4z0=
|
||||
k8s.io/apimachinery v0.34.0/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw=
|
||||
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-20250604170112-4c0f3b243397 h1:hwvWFiBzdWw1FhfY1FooPn3kzWuJ8tmbZBHi4zVsl1Y=
|
||||
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||
sigs.k8s.io/controller-runtime v0.22.0 h1:mTOfibb8Hxwpx3xEkR56i7xSjB+nH4hZG37SrlCY5e0=
|
||||
sigs.k8s.io/controller-runtime v0.22.0/go.mod h1:FwiwRjkRPbiN+zp2QRp7wlTCzbUXxZ/D4OzuQUDwBHY=
|
||||
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 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/v6 v6.3.0 h1:jTijUJbW353oVOd9oTlifJqOGEkUw2jB/fXCbTiQEco=
|
||||
sigs.k8s.io/structured-merge-diff/v6 v6.3.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE=
|
||||
sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs=
|
||||
sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4=
|
|
@ -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
|
|
@ -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
|
||||
)
|
|
@ -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"`
|
||||
}
|
|
@ -1,402 +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 kustomize Components.
|
||||
// +optional
|
||||
Components []string `json:"components,omitempty"`
|
||||
|
||||
// IgnoreMissingComponents instructs the controller to ignore Components paths
|
||||
// not found in source by removing them from the generated kustomization.yaml
|
||||
// before running kustomize build.
|
||||
// +optional
|
||||
IgnoreMissingComponents bool `json:"ignoreMissingComponents,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"`
|
||||
|
||||
// History contains a set of snapshots of the last reconciliation attempts
|
||||
// tracking the revision, the state and the duration of each attempt.
|
||||
// +optional
|
||||
History meta.History `json:"history,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{})
|
||||
}
|
|
@ -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;ExternalArtifact
|
||||
// +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"`
|
||||
}
|
|
@ -1,357 +0,0 @@
|
|||
//go:build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
Copyright 2025 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// 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)
|
||||
}
|
||||
if in.History != nil {
|
||||
in, out := &in.History, &out.History
|
||||
*out = make(meta.History, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
Copyright 2020 The Flux CD contributors.
|
||||
|
||||
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 v1alpha1
|
||||
|
||||
import (
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// Condition contains condition information for a kustomization.
|
||||
type Condition struct {
|
||||
// Type of the condition, currently ('Ready').
|
||||
// +required
|
||||
Type string `json:"type"`
|
||||
|
||||
// Status of the condition, one of ('True', 'False', 'Unknown').
|
||||
// +required
|
||||
Status corev1.ConditionStatus `json:"status"`
|
||||
|
||||
// LastTransitionTime is the timestamp corresponding to the last status
|
||||
// change of this condition.
|
||||
// +required
|
||||
LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty"`
|
||||
|
||||
// Reason is a brief machine readable explanation for the condition's last
|
||||
// transition.
|
||||
// +required
|
||||
Reason string `json:"reason,omitempty"`
|
||||
|
||||
// Message is a human readable description of the details of the last
|
||||
// transition, complementing reason.
|
||||
// +optional
|
||||
Message string `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
const (
|
||||
// ReadyCondition represents the fact that a given kustomization has passed
|
||||
// validation and was successfully applied on the cluster.
|
||||
ReadyCondition string = "Ready"
|
||||
)
|
||||
|
||||
const (
|
||||
// ApplySucceedReason represents the fact that the kustomization apply succeed.
|
||||
ApplySucceedReason string = "ApplySucceed"
|
||||
|
||||
// ApplyFailedReason represents the fact that the kustomization apply failed.
|
||||
ApplyFailedReason string = "ApplyFailed"
|
||||
|
||||
// ArtifactFailedReason represents the fact that the artifact download failed.
|
||||
ArtifactFailedReason string = "ArtifactFailed"
|
||||
|
||||
// BuildFailedReason represents the fact that the kustomize build command failed.
|
||||
BuildFailedReason string = "BuildFailed"
|
||||
|
||||
// DependencyNotReady represents the fact that the one of the dependencies is not ready.
|
||||
DependencyNotReadyReason string = "DependencyNotReady"
|
||||
|
||||
// HealthCheckFailedReason represents the fact that the one of the health check failed.
|
||||
HealthCheckFailedReason string = "HealthCheckFailed"
|
||||
|
||||
// InitializedReason represents the fact that a given resource has been initialized.
|
||||
InitializedReason string = "Initialized"
|
||||
|
||||
// SuspendedReason represents the fact that the kustomization execution is suspended.
|
||||
SuspendedReason string = "Suspended"
|
||||
|
||||
// ValidationFailedReason represents the fact that the dry-run apply failed.
|
||||
ValidationFailedReason string = "ValidationFailed"
|
||||
)
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2020 The Flux authors
|
||||
Copyright 2020 The Flux CD contributors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
@ -14,7 +14,10 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1beta1
|
||||
// Package v1alpha1 contains API Schema definitions for the kustomize v1alpha1 API group
|
||||
// +kubebuilder:object:generate=true
|
||||
// +groupName=kustomize.fluxcd.io
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
|
@ -23,7 +26,7 @@ import (
|
|||
|
||||
var (
|
||||
// GroupVersion is group version used to register these objects
|
||||
GroupVersion = schema.GroupVersion{Group: "kustomize.toolkit.fluxcd.io", Version: "v1beta1"}
|
||||
GroupVersion = schema.GroupVersion{Group: "kustomize.fluxcd.io", Version: "v1alpha1"}
|
||||
|
||||
// SchemeBuilder is used to add go types to the GroupVersionKind scheme
|
||||
SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
|
|
@ -0,0 +1,185 @@
|
|||
/*
|
||||
Copyright 2020 The Flux CD contributors.
|
||||
|
||||
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 v1alpha1
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// KustomizationSpec defines the desired state of a kustomization.
|
||||
type KustomizationSpec struct {
|
||||
// A list of kustomizations that must be ready before this
|
||||
// kustomization can be applied.
|
||||
// +optional
|
||||
DependsOn []string `json:"dependsOn,omitempty"`
|
||||
|
||||
// When enabled, the kustomization.yaml is automatically generated
|
||||
// for all the Kubernetes manifests in the specified path and sub-directories.
|
||||
// The generated kustomization.yaml contains a label transformer matching the prune field.
|
||||
// +optional
|
||||
Generate bool `json:"generate,omitempty"`
|
||||
|
||||
// The interval at which to apply the kustomization.
|
||||
// +required
|
||||
Interval metav1.Duration `json:"interval"`
|
||||
|
||||
// Path to the directory containing the kustomization file.
|
||||
// +kubebuilder:validation:Pattern="^\\./"
|
||||
// +required
|
||||
Path string `json:"path"`
|
||||
|
||||
// Label selector used for garbage collection.
|
||||
// +kubebuilder:validation:Pattern="^.*=.*$"
|
||||
// +optional
|
||||
Prune string `json:"prune,omitempty"`
|
||||
|
||||
// A list of workloads (Deployments, DaemonSets and StatefulSets)
|
||||
// to be included in the health assessment.
|
||||
// +optional
|
||||
HealthChecks []WorkloadReference `json:"healthChecks,omitempty"`
|
||||
|
||||
// Reference of the source where the kustomization file is.
|
||||
// +required
|
||||
SourceRef corev1.TypedLocalObjectReference `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"`
|
||||
|
||||
// Timeout for validation, apply and health checking operations.
|
||||
// Defaults to 'Interval' duration.
|
||||
// +optional
|
||||
Timeout *metav1.Duration `json:"timeout,omitempty"`
|
||||
|
||||
// Validate the Kubernetes objects before applying them on the cluster.
|
||||
// The validation strategy can be 'client' (local dry-run) or 'server' (APIServer dry-run).
|
||||
// +kubebuilder:validation:Enum=client;server
|
||||
// +optional
|
||||
Validation string `json:"validation,omitempty"`
|
||||
}
|
||||
|
||||
// WorkloadReference defines a reference to a Deployment, DaemonSet or StatefulSet.
|
||||
type WorkloadReference struct {
|
||||
// Kind is the type of resource being referenced.
|
||||
// +kubebuilder:validation:Enum=Deployment;DaemonSet;StatefulSet
|
||||
// +required
|
||||
Kind string `json:"kind"`
|
||||
|
||||
// Name is the name of resource being referenced.
|
||||
// +required
|
||||
Name string `json:"name"`
|
||||
|
||||
// Namespace is the namespace of resource being referenced.
|
||||
// +required
|
||||
Namespace string `json:"namespace,omitempty"`
|
||||
}
|
||||
|
||||
// KustomizationStatus defines the observed state of a kustomization.
|
||||
type KustomizationStatus struct {
|
||||
// +optional
|
||||
Conditions []Condition `json:"conditions,omitempty"`
|
||||
|
||||
// The last successfully applied revision.
|
||||
// The revision format for Git sources is <branch|tag>/<commit-sha>.
|
||||
// +optional
|
||||
LastAppliedRevision string `json:"lastAppliedRevision,omitempty"`
|
||||
}
|
||||
|
||||
func KustomizationReady(kustomization Kustomization, revision, reason, message string) Kustomization {
|
||||
kustomization.Status.Conditions = []Condition{
|
||||
{
|
||||
Type: ReadyCondition,
|
||||
Status: corev1.ConditionTrue,
|
||||
LastTransitionTime: metav1.Now(),
|
||||
Reason: reason,
|
||||
Message: message,
|
||||
},
|
||||
}
|
||||
kustomization.Status.LastAppliedRevision = revision
|
||||
return kustomization
|
||||
}
|
||||
|
||||
func KustomizationNotReady(kustomization Kustomization, reason, message string) Kustomization {
|
||||
kustomization.Status.Conditions = []Condition{
|
||||
{
|
||||
Type: ReadyCondition,
|
||||
Status: corev1.ConditionFalse,
|
||||
LastTransitionTime: metav1.Now(),
|
||||
Reason: reason,
|
||||
Message: message,
|
||||
},
|
||||
}
|
||||
return kustomization
|
||||
}
|
||||
|
||||
// GetTimeout returns the timeout with default
|
||||
func (in *Kustomization) GetTimeout() time.Duration {
|
||||
duration := in.Spec.Interval.Duration
|
||||
if in.Spec.Timeout != nil {
|
||||
duration = in.Spec.Timeout.Duration
|
||||
}
|
||||
if duration < time.Minute {
|
||||
return time.Minute
|
||||
}
|
||||
return duration
|
||||
}
|
||||
|
||||
const (
|
||||
// SyncAtAnnotation is the annotation used for triggering a
|
||||
// sync outside of the specified schedule.
|
||||
SyncAtAnnotation string = "kustomize.fluxcd.io/syncAt"
|
||||
|
||||
// SourceIndexKey is the key used for indexing kustomizations
|
||||
// based on their sources.
|
||||
SourceIndexKey string = ".metadata.source"
|
||||
|
||||
// DependencyIndexKey is the key used for indexing kustomizations
|
||||
// based on their dependencies.
|
||||
DependencyIndexKey string = ".metadata.dependency"
|
||||
)
|
||||
|
||||
// +kubebuilder:object:root=true
|
||||
// +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=""
|
||||
|
||||
// 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"`
|
||||
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{})
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
Copyright 2020 The Flux CD contributors.
|
||||
|
||||
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 v1alpha1
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// ProfileSpec defines the desired state of Profile
|
||||
type ProfileSpec struct {
|
||||
// Alerting configuration of the kustomizations targeted by this profile.
|
||||
// +optional
|
||||
Alert *AlertProvider `json:"alert"`
|
||||
|
||||
// The list of kustomizations that this profile applies to.
|
||||
// +required
|
||||
Kustomizations []string `json:"kustomizations"`
|
||||
}
|
||||
|
||||
// Alert is the configuration of alerting for a specific provider
|
||||
type AlertProvider struct {
|
||||
// HTTP(S) webhook address of this provider
|
||||
// +required
|
||||
Address string `json:"address"`
|
||||
|
||||
// Alert channel for this provider
|
||||
// +required
|
||||
Channel string `json:"channel"`
|
||||
|
||||
// Bot username for this provider
|
||||
// +required
|
||||
Username string `json:"username"`
|
||||
|
||||
// Filter alerts based on verbosity level, defaults to ('error').
|
||||
// +kubebuilder:validation:Enum=info;error
|
||||
// +optional
|
||||
Verbosity string `json:"verbosity,omitempty"`
|
||||
|
||||
// Type of provider
|
||||
// +kubebuilder:validation:Enum=slack;discord
|
||||
// +required
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
// ProfileStatus defines the observed state of Profile
|
||||
type ProfileStatus struct {
|
||||
// +optional
|
||||
Conditions []Condition `json:"conditions,omitempty"`
|
||||
}
|
||||
|
||||
// +kubebuilder:object:root=true
|
||||
// +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=""
|
||||
|
||||
// Profile is the Schema for the profiles API
|
||||
type Profile struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
Spec ProfileSpec `json:"spec,omitempty"`
|
||||
Status ProfileStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// +kubebuilder:object:root=true
|
||||
|
||||
// ProfileList contains a list of Profile
|
||||
type ProfileList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata,omitempty"`
|
||||
Items []Profile `json:"items"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
SchemeBuilder.Register(&Profile{}, &ProfileList{})
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
//go:build !ignore_autogenerated
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
Copyright 2025 The Flux authors
|
||||
Copyright 2020 The Flux CD contributors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
@ -18,63 +18,40 @@ limitations under the License.
|
|||
|
||||
// Code generated by controller-gen. DO NOT EDIT.
|
||||
|
||||
package v1beta1
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
"github.com/fluxcd/pkg/apis/kustomize"
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
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 *CrossNamespaceSourceReference) DeepCopyInto(out *CrossNamespaceSourceReference) {
|
||||
func (in *AlertProvider) DeepCopyInto(out *AlertProvider) {
|
||||
*out = *in
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CrossNamespaceSourceReference.
|
||||
func (in *CrossNamespaceSourceReference) DeepCopy() *CrossNamespaceSourceReference {
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AlertProvider.
|
||||
func (in *AlertProvider) DeepCopy() *AlertProvider {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CrossNamespaceSourceReference)
|
||||
out := new(AlertProvider)
|
||||
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) {
|
||||
func (in *Condition) DeepCopyInto(out *Condition) {
|
||||
*out = *in
|
||||
if in.SecretRef != nil {
|
||||
in, out := &in.SecretRef, &out.SecretRef
|
||||
*out = new(meta.LocalObjectReference)
|
||||
**out = **in
|
||||
}
|
||||
in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Decryption.
|
||||
func (in *Decryption) DeepCopy() *Decryption {
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Condition.
|
||||
func (in *Condition) DeepCopy() *Condition {
|
||||
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 *KubeConfig) DeepCopyInto(out *KubeConfig) {
|
||||
*out = *in
|
||||
out.SecretRef = in.SecretRef
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeConfig.
|
||||
func (in *KubeConfig) DeepCopy() *KubeConfig {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(KubeConfig)
|
||||
out := new(Condition)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
@ -143,62 +120,16 @@ func (in *KustomizationSpec) DeepCopyInto(out *KustomizationSpec) {
|
|||
*out = *in
|
||||
if in.DependsOn != nil {
|
||||
in, out := &in.DependsOn, &out.DependsOn
|
||||
*out = make([]meta.NamespacedObjectReference, len(*in))
|
||||
*out = make([]string, 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(v1.Duration)
|
||||
**out = **in
|
||||
}
|
||||
if in.KubeConfig != nil {
|
||||
in, out := &in.KubeConfig, &out.KubeConfig
|
||||
*out = new(KubeConfig)
|
||||
**out = **in
|
||||
}
|
||||
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))
|
||||
*out = make([]WorkloadReference, 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.PatchesStrategicMerge != nil {
|
||||
in, out := &in.PatchesStrategicMerge, &out.PatchesStrategicMerge
|
||||
*out = make([]apiextensionsv1.JSON, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.PatchesJSON6902 != nil {
|
||||
in, out := &in.PatchesJSON6902, &out.PatchesJSON6902
|
||||
*out = make([]kustomize.JSON6902Patch, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.Images != nil {
|
||||
in, out := &in.Images, &out.Images
|
||||
*out = make([]kustomize.Image, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
out.SourceRef = in.SourceRef
|
||||
in.SourceRef.DeepCopyInto(&out.SourceRef)
|
||||
if in.Timeout != nil {
|
||||
in, out := &in.Timeout, &out.Timeout
|
||||
*out = new(v1.Duration)
|
||||
|
@ -221,17 +152,11 @@ func (in *KustomizationStatus) DeepCopyInto(out *KustomizationStatus) {
|
|||
*out = *in
|
||||
if in.Conditions != nil {
|
||||
in, out := &in.Conditions, &out.Conditions
|
||||
*out = make([]v1.Condition, len(*in))
|
||||
*out = make([]Condition, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
out.ReconcileRequestStatus = in.ReconcileRequestStatus
|
||||
if in.Snapshot != nil {
|
||||
in, out := &in.Snapshot, &out.Snapshot
|
||||
*out = new(Snapshot)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KustomizationStatus.
|
||||
|
@ -245,87 +170,122 @@ func (in *KustomizationStatus) DeepCopy() *KustomizationStatus {
|
|||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *PostBuild) DeepCopyInto(out *PostBuild) {
|
||||
func (in *Profile) DeepCopyInto(out *Profile) {
|
||||
*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)
|
||||
}
|
||||
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 PostBuild.
|
||||
func (in *PostBuild) DeepCopy() *PostBuild {
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Profile.
|
||||
func (in *Profile) DeepCopy() *Profile {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(PostBuild)
|
||||
out := new(Profile)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *Profile) 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 *Snapshot) DeepCopyInto(out *Snapshot) {
|
||||
func (in *ProfileList) DeepCopyInto(out *ProfileList) {
|
||||
*out = *in
|
||||
if in.Entries != nil {
|
||||
in, out := &in.Entries, &out.Entries
|
||||
*out = make([]SnapshotEntry, len(*in))
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]Profile, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Snapshot.
|
||||
func (in *Snapshot) DeepCopy() *Snapshot {
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProfileList.
|
||||
func (in *ProfileList) DeepCopy() *ProfileList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Snapshot)
|
||||
out := new(ProfileList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *ProfileList) 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 *ProfileSpec) DeepCopyInto(out *ProfileSpec) {
|
||||
*out = *in
|
||||
if in.Alert != nil {
|
||||
in, out := &in.Alert, &out.Alert
|
||||
*out = new(AlertProvider)
|
||||
**out = **in
|
||||
}
|
||||
if in.Kustomizations != nil {
|
||||
in, out := &in.Kustomizations, &out.Kustomizations
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProfileSpec.
|
||||
func (in *ProfileSpec) DeepCopy() *ProfileSpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ProfileSpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *SnapshotEntry) DeepCopyInto(out *SnapshotEntry) {
|
||||
func (in *ProfileStatus) DeepCopyInto(out *ProfileStatus) {
|
||||
*out = *in
|
||||
if in.Kinds != nil {
|
||||
in, out := &in.Kinds, &out.Kinds
|
||||
*out = make(map[string]string, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
if in.Conditions != nil {
|
||||
in, out := &in.Conditions, &out.Conditions
|
||||
*out = make([]Condition, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SnapshotEntry.
|
||||
func (in *SnapshotEntry) DeepCopy() *SnapshotEntry {
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProfileStatus.
|
||||
func (in *ProfileStatus) DeepCopy() *ProfileStatus {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(SnapshotEntry)
|
||||
out := new(ProfileStatus)
|
||||
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) {
|
||||
func (in *WorkloadReference) DeepCopyInto(out *WorkloadReference) {
|
||||
*out = *in
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubstituteReference.
|
||||
func (in *SubstituteReference) DeepCopy() *SubstituteReference {
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkloadReference.
|
||||
func (in *WorkloadReference) DeepCopy() *WorkloadReference {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(SubstituteReference)
|
||||
out := new(WorkloadReference)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
/*
|
||||
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 v1beta1
|
||||
|
||||
const (
|
||||
// HealthyCondition is the condition type used
|
||||
// to record the last health assessment result.
|
||||
HealthyCondition string = "Healthy"
|
||||
|
||||
// PruneFailedReason represents the fact that the
|
||||
// pruning of the Kustomization failed.
|
||||
PruneFailedReason string = "PruneFailed"
|
||||
|
||||
// ArtifactFailedReason represents the fact that the
|
||||
// artifact download of the kustomization failed.
|
||||
ArtifactFailedReason string = "ArtifactFailed"
|
||||
|
||||
// BuildFailedReason represents the fact that the
|
||||
// kustomize build of the Kustomization failed.
|
||||
BuildFailedReason string = "BuildFailed"
|
||||
|
||||
// HealthCheckFailedReason represents the fact that
|
||||
// one of the health checks of the Kustomization failed.
|
||||
HealthCheckFailedReason string = "HealthCheckFailed"
|
||||
|
||||
// ValidationFailedReason represents the fact that the
|
||||
// validation of the Kustomization manifests has failed.
|
||||
ValidationFailedReason string = "ValidationFailed"
|
||||
)
|
|
@ -1,23 +0,0 @@
|
|||
/*
|
||||
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 v1beta1 contains API Schema definitions for the kustomize v1beta1 API group
|
||||
//
|
||||
// Deprecated: v1beta1 is no longer supported, use v1 instead.
|
||||
//
|
||||
// +kubebuilder:object:generate=true
|
||||
// +groupName=kustomize.toolkit.fluxcd.io
|
||||
package v1beta1
|
|
@ -1,306 +0,0 @@
|
|||
/*
|
||||
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 v1beta1
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
|
||||
"github.com/fluxcd/pkg/apis/kustomize"
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
)
|
||||
|
||||
const (
|
||||
KustomizationKind = "Kustomization"
|
||||
KustomizationFinalizer = "finalizers.fluxcd.io"
|
||||
MaxConditionMessageLength = 20000
|
||||
DisabledValue = "disabled"
|
||||
)
|
||||
|
||||
// KustomizationSpec defines the desired state of a kustomization.
|
||||
type KustomizationSpec struct {
|
||||
// DependsOn may contain a meta.NamespacedObjectReference slice
|
||||
// with references to Kustomization resources that must be ready before this
|
||||
// Kustomization can be reconciled.
|
||||
// +optional
|
||||
DependsOn []meta.NamespacedObjectReference `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.
|
||||
// +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.
|
||||
// +optional
|
||||
RetryInterval *metav1.Duration `json:"retryInterval,omitempty"`
|
||||
|
||||
// The KubeConfig for reconciling the Kustomization on a remote cluster.
|
||||
// When specified, KubeConfig takes precedence over ServiceAccountName.
|
||||
// +optional
|
||||
KubeConfig *KubeConfig `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"`
|
||||
|
||||
// A list of resources to be included in the health assessment.
|
||||
// +optional
|
||||
HealthChecks []meta.NamespacedObjectKindReference `json:"healthChecks,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"`
|
||||
|
||||
// Strategic merge patches, defined as inline YAML objects.
|
||||
// +optional
|
||||
PatchesStrategicMerge []apiextensionsv1.JSON `json:"patchesStrategicMerge,omitempty"`
|
||||
|
||||
// JSON 6902 patches, defined as inline YAML objects.
|
||||
// +optional
|
||||
PatchesJSON6902 []kustomize.JSON6902Patch `json:"patchesJson6902,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.
|
||||
// +optional
|
||||
Timeout *metav1.Duration `json:"timeout,omitempty"`
|
||||
|
||||
// Validate the Kubernetes objects before applying them on the cluster.
|
||||
// The validation strategy can be 'client' (local dry-run), 'server'
|
||||
// (APIServer dry-run) or 'none'.
|
||||
// When 'Force' is 'true', validation will fallback to 'client' if set to
|
||||
// 'server' because server-side validation is not supported in this scenario.
|
||||
// +kubebuilder:validation:Enum=none;client;server
|
||||
// +optional
|
||||
Validation string `json:"validation,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"`
|
||||
}
|
||||
|
||||
// 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"`
|
||||
|
||||
// The secret name containing the private OpenPGP keys used for decryption.
|
||||
// +optional
|
||||
SecretRef *meta.LocalObjectReference `json:"secretRef,omitempty"`
|
||||
}
|
||||
|
||||
// KubeConfig references a Kubernetes secret that contains a kubeconfig file.
|
||||
type KubeConfig struct {
|
||||
// SecretRef holds the name to a secret that contains a 'value' key with
|
||||
// the kubeconfig file as the value. It must be in the same namespace as
|
||||
// the Kustomization.
|
||||
// It is recommended that the kubeconfig is self-contained, and the secret
|
||||
// is regularly updated if credentials such as a cloud-access-token expire.
|
||||
// Cloud specific `cmd-path` auth helpers will not function without adding
|
||||
// binaries and credentials to the Pod that is responsible for reconciling
|
||||
// the Kustomization.
|
||||
// +required
|
||||
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"`
|
||||
}
|
||||
|
||||
// KustomizationStatus defines the observed state of a kustomization.
|
||||
type KustomizationStatus struct {
|
||||
// ObservedGeneration is the last reconciled generation.
|
||||
// +optional
|
||||
ObservedGeneration int64 `json:"observedGeneration,omitempty"`
|
||||
|
||||
// +optional
|
||||
Conditions []metav1.Condition `json:"conditions,omitempty"`
|
||||
|
||||
// The last successfully applied revision.
|
||||
// The revision format for Git sources is <branch|tag>/<commit-sha>.
|
||||
// +optional
|
||||
LastAppliedRevision string `json:"lastAppliedRevision,omitempty"`
|
||||
|
||||
// LastAttemptedRevision is the revision of the last reconciliation attempt.
|
||||
// +optional
|
||||
LastAttemptedRevision string `json:"lastAttemptedRevision,omitempty"`
|
||||
|
||||
meta.ReconcileRequestStatus `json:",inline"`
|
||||
|
||||
// The last successfully applied revision metadata.
|
||||
// +optional
|
||||
Snapshot *Snapshot `json:"snapshot,omitempty"`
|
||||
}
|
||||
|
||||
// GetTimeout returns the timeout with default.
|
||||
func (in Kustomization) GetTimeout() time.Duration {
|
||||
duration := in.Spec.Interval.Duration
|
||||
if in.Spec.Timeout != nil {
|
||||
duration = in.Spec.Timeout.Duration
|
||||
}
|
||||
if duration < time.Minute {
|
||||
return time.Minute
|
||||
}
|
||||
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.Spec.Interval.Duration
|
||||
}
|
||||
|
||||
func (in Kustomization) GetDependsOn() (types.NamespacedName, []meta.NamespacedObjectReference) {
|
||||
return types.NamespacedName{
|
||||
Namespace: in.Namespace,
|
||||
Name: in.Name,
|
||||
}, in.Spec.DependsOn
|
||||
}
|
||||
|
||||
// GetStatusConditions returns a pointer to the Status.Conditions slice
|
||||
func (in *Kustomization) GetStatusConditions() *[]metav1.Condition {
|
||||
return &in.Status.Conditions
|
||||
}
|
||||
|
||||
const (
|
||||
// GitRepositoryIndexKey is the key used for indexing kustomizations
|
||||
// based on their Git sources.
|
||||
GitRepositoryIndexKey string = ".metadata.gitRepository"
|
||||
// BucketIndexKey is the key used for indexing kustomizations
|
||||
// based on their S3 sources.
|
||||
BucketIndexKey string = ".metadata.bucket"
|
||||
)
|
||||
|
||||
// +genclient
|
||||
// +kubebuilder:object:root=true
|
||||
// +kubebuilder:skipversion
|
||||
|
||||
// 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{})
|
||||
}
|
||||
|
||||
func trimString(str string, limit int) string {
|
||||
if len(str) <= limit {
|
||||
return str
|
||||
}
|
||||
|
||||
return str[0:limit] + "..."
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
/*
|
||||
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 v1beta1
|
||||
|
||||
import "fmt"
|
||||
|
||||
// CrossNamespaceSourceReference contains enough information to let you locate the
|
||||
// typed referenced 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=GitRepository;Bucket
|
||||
// +required
|
||||
Kind string `json:"kind"`
|
||||
|
||||
// Name of the referent
|
||||
// +required
|
||||
Name string `json:"name"`
|
||||
|
||||
// Namespace of the referent, defaults to the Kustomization namespace
|
||||
// +optional
|
||||
Namespace string `json:"namespace,omitempty"`
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
|
@ -1,139 +0,0 @@
|
|||
/*
|
||||
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 v1beta1
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/yaml"
|
||||
)
|
||||
|
||||
// Snapshot holds the metadata of the Kubernetes objects
|
||||
// generated for a source revision
|
||||
type Snapshot struct {
|
||||
// The manifests sha1 checksum.
|
||||
// +required
|
||||
Checksum string `json:"checksum"`
|
||||
|
||||
// A list of Kubernetes kinds grouped by namespace.
|
||||
// +required
|
||||
Entries []SnapshotEntry `json:"entries"`
|
||||
}
|
||||
|
||||
// Snapshot holds the metadata of namespaced
|
||||
// Kubernetes objects
|
||||
type SnapshotEntry struct {
|
||||
// The namespace of this entry.
|
||||
// +optional
|
||||
Namespace string `json:"namespace"`
|
||||
|
||||
// The list of Kubernetes kinds.
|
||||
// +required
|
||||
Kinds map[string]string `json:"kinds"`
|
||||
}
|
||||
|
||||
func NewSnapshot(manifests []byte, checksum string) (*Snapshot, error) {
|
||||
snapshot := Snapshot{
|
||||
Checksum: checksum,
|
||||
Entries: []SnapshotEntry{},
|
||||
}
|
||||
|
||||
reader := yaml.NewYAMLOrJSONDecoder(bytes.NewReader(manifests), 2048)
|
||||
for {
|
||||
var obj unstructured.Unstructured
|
||||
err := reader.Decode(&obj)
|
||||
if err == io.EOF {
|
||||
break
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if obj.IsList() {
|
||||
err := obj.EachListItem(func(item runtime.Object) error {
|
||||
snapshot.addEntry(item.(*unstructured.Unstructured))
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
snapshot.addEntry(&obj)
|
||||
}
|
||||
}
|
||||
|
||||
return &snapshot, nil
|
||||
}
|
||||
|
||||
func (s *Snapshot) addEntry(item *unstructured.Unstructured) {
|
||||
found := false
|
||||
for _, tracker := range s.Entries {
|
||||
if tracker.Namespace == item.GetNamespace() {
|
||||
tracker.Kinds[item.GroupVersionKind().String()] = item.GetKind()
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
s.Entries = append(s.Entries, SnapshotEntry{
|
||||
Namespace: item.GetNamespace(),
|
||||
Kinds: map[string]string{
|
||||
item.GroupVersionKind().String(): item.GetKind(),
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Snapshot) NonNamespacedKinds() []schema.GroupVersionKind {
|
||||
kinds := make([]schema.GroupVersionKind, 0)
|
||||
|
||||
for _, tracker := range s.Entries {
|
||||
if tracker.Namespace == "" {
|
||||
for gvk, kind := range tracker.Kinds {
|
||||
if strings.Contains(gvk, ",") {
|
||||
gv, err := schema.ParseGroupVersion(strings.Split(gvk, ",")[0])
|
||||
if err == nil {
|
||||
kinds = append(kinds, gv.WithKind(kind))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return kinds
|
||||
}
|
||||
|
||||
func (s *Snapshot) NamespacedKinds() map[string][]schema.GroupVersionKind {
|
||||
nsk := make(map[string][]schema.GroupVersionKind)
|
||||
for _, tracker := range s.Entries {
|
||||
if tracker.Namespace != "" {
|
||||
var kinds []schema.GroupVersionKind
|
||||
for gvk, kind := range tracker.Kinds {
|
||||
if strings.Contains(gvk, ",") {
|
||||
gv, err := schema.ParseGroupVersion(strings.Split(gvk, ",")[0])
|
||||
if err == nil {
|
||||
kinds = append(kinds, gv.WithKind(kind))
|
||||
}
|
||||
}
|
||||
}
|
||||
nsk[tracker.Namespace] = kinds
|
||||
}
|
||||
}
|
||||
return nsk
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
/*
|
||||
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 v1beta2
|
||||
|
||||
const (
|
||||
// HealthyCondition represents the last recorded
|
||||
// health assessment result.
|
||||
HealthyCondition string = "Healthy"
|
||||
|
||||
// PruneFailedReason represents the fact that the
|
||||
// pruning of the Kustomization failed.
|
||||
PruneFailedReason string = "PruneFailed"
|
||||
|
||||
// ArtifactFailedReason represents the fact that the
|
||||
// source artifact download failed.
|
||||
ArtifactFailedReason string = "ArtifactFailed"
|
||||
|
||||
// BuildFailedReason represents the fact that the
|
||||
// kustomize build failed.
|
||||
BuildFailedReason string = "BuildFailed"
|
||||
|
||||
// HealthCheckFailedReason represents the fact that
|
||||
// one of the health checks failed.
|
||||
HealthCheckFailedReason string = "HealthCheckFailed"
|
||||
|
||||
// DependencyNotReadyReason represents the fact that
|
||||
// one of the dependencies is not ready.
|
||||
DependencyNotReadyReason string = "DependencyNotReady"
|
||||
|
||||
// ReconciliationSucceededReason represents the fact that
|
||||
// the reconciliation succeeded.
|
||||
ReconciliationSucceededReason string = "ReconciliationSucceeded"
|
||||
|
||||
// ReconciliationFailedReason represents the fact that
|
||||
// the reconciliation failed.
|
||||
ReconciliationFailedReason string = "ReconciliationFailed"
|
||||
|
||||
// ProgressingWithRetryReason represents the fact that
|
||||
// the reconciliation encountered an error that will be retried.
|
||||
ProgressingWithRetryReason string = "ProgressingWithRetry"
|
||||
)
|
|
@ -1,20 +0,0 @@
|
|||
/*
|
||||
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 v1beta2 contains API Schema definitions for the kustomize.toolkit.fluxcd.io v1beta2 API group.
|
||||
// +kubebuilder:object:generate=true
|
||||
// +groupName=kustomize.toolkit.fluxcd.io
|
||||
package v1beta2
|
|
@ -1,33 +0,0 @@
|
|||
/*
|
||||
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 v1beta2
|
||||
|
||||
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: "v1beta2"}
|
||||
|
||||
// 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
|
||||
)
|
|
@ -1,33 +0,0 @@
|
|||
/*
|
||||
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 v1beta2
|
||||
|
||||
// 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"`
|
||||
}
|
|
@ -1,336 +0,0 @@
|
|||
/*
|
||||
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 v1beta2
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/fluxcd/pkg/apis/kustomize"
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
const (
|
||||
KustomizationKind = "Kustomization"
|
||||
KustomizationFinalizer = "finalizers.fluxcd.io"
|
||||
MaxConditionMessageLength = 20000
|
||||
EnabledValue = "enabled"
|
||||
DisabledValue = "disabled"
|
||||
MergeValue = "merge"
|
||||
)
|
||||
|
||||
// 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.
|
||||
// +optional
|
||||
DependsOn []meta.NamespacedObjectReference `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.
|
||||
// +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"`
|
||||
|
||||
// A list of resources to be included in the health assessment.
|
||||
// +optional
|
||||
HealthChecks []meta.NamespacedObjectKindReference `json:"healthChecks,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"`
|
||||
|
||||
// Strategic merge patches, defined as inline YAML objects.
|
||||
// Deprecated: Use Patches instead.
|
||||
// +optional
|
||||
PatchesStrategicMerge []apiextensionsv1.JSON `json:"patchesStrategicMerge,omitempty"`
|
||||
|
||||
// JSON 6902 patches, defined as inline YAML objects.
|
||||
// Deprecated: Use Patches instead.
|
||||
// +optional
|
||||
PatchesJSON6902 []kustomize.JSON6902Patch `json:"patchesJson6902,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"`
|
||||
|
||||
// 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.
|
||||
// +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"`
|
||||
|
||||
// The secret name containing the private OpenPGP keys used for decryption.
|
||||
// +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"`
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// GetDependsOn returns the list of dependencies across-namespaces.
|
||||
func (in Kustomization) GetDependsOn() []meta.NamespacedObjectReference {
|
||||
return in.Spec.DependsOn
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// GetStatusConditions returns a pointer to the Status.Conditions slice.
|
||||
// Deprecated: use GetConditions instead.
|
||||
func (in *Kustomization) GetStatusConditions() *[]metav1.Condition {
|
||||
return &in.Status.Conditions
|
||||
}
|
||||
|
||||
// +genclient
|
||||
// +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 {
|
||||
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{})
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
/*
|
||||
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 v1beta2
|
||||
|
||||
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"`
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
|
@ -1,345 +0,0 @@
|
|||
//go:build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
Copyright 2025 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Code generated by controller-gen. DO NOT EDIT.
|
||||
|
||||
package v1beta2
|
||||
|
||||
import (
|
||||
"github.com/fluxcd/pkg/apis/kustomize"
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CommonMetadata) DeepCopyInto(out *CommonMetadata) {
|
||||
*out = *in
|
||||
if in.Annotations != nil {
|
||||
in, out := &in.Annotations, &out.Annotations
|
||||
*out = make(map[string]string, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
if in.Labels != nil {
|
||||
in, out := &in.Labels, &out.Labels
|
||||
*out = make(map[string]string, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CommonMetadata.
|
||||
func (in *CommonMetadata) DeepCopy() *CommonMetadata {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CommonMetadata)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *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 *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([]meta.NamespacedObjectReference, 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(v1.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.PatchesStrategicMerge != nil {
|
||||
in, out := &in.PatchesStrategicMerge, &out.PatchesStrategicMerge
|
||||
*out = make([]apiextensionsv1.JSON, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.PatchesJSON6902 != nil {
|
||||
in, out := &in.PatchesJSON6902, &out.PatchesJSON6902
|
||||
*out = make([]kustomize.JSON6902Patch, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.Images != nil {
|
||||
in, out := &in.Images, &out.Images
|
||||
*out = make([]kustomize.Image, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
out.SourceRef = in.SourceRef
|
||||
if in.Timeout != nil {
|
||||
in, out := &in.Timeout, &out.Timeout
|
||||
*out = new(v1.Duration)
|
||||
**out = **in
|
||||
}
|
||||
if in.Components != nil {
|
||||
in, out := &in.Components, &out.Components
|
||||
*out = make([]string, 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([]v1.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
|
||||
}
|
|
@ -0,0 +1,185 @@
|
|||
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1beta1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.2.5
|
||||
creationTimestamp: null
|
||||
name: kustomizations.kustomize.fluxcd.io
|
||||
spec:
|
||||
additionalPrinterColumns:
|
||||
- JSONPath: .status.conditions[?(@.type=="Ready")].status
|
||||
name: Ready
|
||||
type: string
|
||||
- JSONPath: .status.conditions[?(@.type=="Ready")].message
|
||||
name: Status
|
||||
type: string
|
||||
- JSONPath: .metadata.creationTimestamp
|
||||
name: Age
|
||||
type: date
|
||||
group: kustomize.fluxcd.io
|
||||
names:
|
||||
kind: Kustomization
|
||||
listKind: KustomizationList
|
||||
plural: kustomizations
|
||||
singular: kustomization
|
||||
scope: Namespaced
|
||||
subresources:
|
||||
status: {}
|
||||
validation:
|
||||
openAPIV3Schema:
|
||||
description: Kustomization is the Schema for the kustomizations API.
|
||||
properties:
|
||||
apiVersion:
|
||||
description: 'APIVersion defines the versioned schema of this representation
|
||||
of an object. Servers should convert recognized schemas to the latest
|
||||
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
||||
type: string
|
||||
kind:
|
||||
description: 'Kind is a string value representing the REST resource this
|
||||
object represents. Servers may infer this from the endpoint the client
|
||||
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: KustomizationSpec defines the desired state of a kustomization.
|
||||
properties:
|
||||
dependsOn:
|
||||
description: A list of kustomizations that must be ready before this
|
||||
kustomization can be applied.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
generate:
|
||||
description: When enabled, the kustomization.yaml is automatically generated
|
||||
for all the Kubernetes manifests in the specified path and sub-directories.
|
||||
The generated kustomization.yaml contains a label transformer matching
|
||||
the prune field.
|
||||
type: boolean
|
||||
healthChecks:
|
||||
description: A list of workloads (Deployments, DaemonSets and StatefulSets)
|
||||
to be included in the health assessment.
|
||||
items:
|
||||
description: WorkloadReference defines a reference to a Deployment,
|
||||
DaemonSet or StatefulSet.
|
||||
properties:
|
||||
kind:
|
||||
description: Kind is the type of resource being referenced.
|
||||
enum:
|
||||
- Deployment
|
||||
- DaemonSet
|
||||
- StatefulSet
|
||||
type: string
|
||||
name:
|
||||
description: Name is the name of resource being referenced.
|
||||
type: string
|
||||
namespace:
|
||||
description: Namespace is the namespace of resource being referenced.
|
||||
type: string
|
||||
required:
|
||||
- kind
|
||||
- name
|
||||
type: object
|
||||
type: array
|
||||
interval:
|
||||
description: The interval at which to apply the kustomization.
|
||||
type: string
|
||||
path:
|
||||
description: Path to the directory containing the kustomization file.
|
||||
pattern: ^\./
|
||||
type: string
|
||||
prune:
|
||||
description: Label selector used for garbage collection.
|
||||
pattern: ^.*=.*$
|
||||
type: string
|
||||
sourceRef:
|
||||
description: Reference of the source where the kustomization file is.
|
||||
properties:
|
||||
apiGroup:
|
||||
description: APIGroup is the group for the resource being referenced.
|
||||
If APIGroup is not specified, the specified Kind must be in the
|
||||
core API group. For any other third-party types, APIGroup is required.
|
||||
type: string
|
||||
kind:
|
||||
description: Kind is the type of resource being referenced
|
||||
type: string
|
||||
name:
|
||||
description: Name is the name of resource being referenced
|
||||
type: string
|
||||
required:
|
||||
- kind
|
||||
- name
|
||||
type: object
|
||||
suspend:
|
||||
description: This flag tells the controller to suspend subsequent kustomize
|
||||
executions, it does not apply to already started executions. Defaults
|
||||
to false.
|
||||
type: boolean
|
||||
timeout:
|
||||
description: Timeout for validation, apply and health checking operations.
|
||||
Defaults to 'Interval' duration.
|
||||
type: string
|
||||
validation:
|
||||
description: Validate the Kubernetes objects before applying them on
|
||||
the cluster. The validation strategy can be 'client' (local dry-run)
|
||||
or 'server' (APIServer dry-run).
|
||||
enum:
|
||||
- client
|
||||
- server
|
||||
type: string
|
||||
required:
|
||||
- interval
|
||||
- path
|
||||
- sourceRef
|
||||
type: object
|
||||
status:
|
||||
description: KustomizationStatus defines the observed state of a kustomization.
|
||||
properties:
|
||||
conditions:
|
||||
items:
|
||||
description: Condition contains condition information for a kustomization.
|
||||
properties:
|
||||
lastTransitionTime:
|
||||
description: LastTransitionTime is the timestamp corresponding
|
||||
to the last status change of this condition.
|
||||
format: date-time
|
||||
type: string
|
||||
message:
|
||||
description: Message is a human readable description of the details
|
||||
of the last transition, complementing reason.
|
||||
type: string
|
||||
reason:
|
||||
description: Reason is a brief machine readable explanation for
|
||||
the condition's last transition.
|
||||
type: string
|
||||
status:
|
||||
description: Status of the condition, one of ('True', 'False',
|
||||
'Unknown').
|
||||
type: string
|
||||
type:
|
||||
description: Type of the condition, currently ('Ready').
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- type
|
||||
type: object
|
||||
type: array
|
||||
lastAppliedRevision:
|
||||
description: The last successfully applied revision. The revision format
|
||||
for Git sources is <branch|tag>/<commit-sha>.
|
||||
type: string
|
||||
type: object
|
||||
type: object
|
||||
version: v1alpha1
|
||||
versions:
|
||||
- name: v1alpha1
|
||||
served: true
|
||||
storage: true
|
||||
status:
|
||||
acceptedNames:
|
||||
kind: ""
|
||||
plural: ""
|
||||
conditions: []
|
||||
storedVersions: []
|
|
@ -0,0 +1,133 @@
|
|||
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1beta1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.2.5
|
||||
creationTimestamp: null
|
||||
name: profiles.kustomize.fluxcd.io
|
||||
spec:
|
||||
additionalPrinterColumns:
|
||||
- JSONPath: .status.conditions[?(@.type=="Ready")].status
|
||||
name: Ready
|
||||
type: string
|
||||
- JSONPath: .status.conditions[?(@.type=="Ready")].message
|
||||
name: Status
|
||||
type: string
|
||||
- JSONPath: .metadata.creationTimestamp
|
||||
name: Age
|
||||
type: date
|
||||
group: kustomize.fluxcd.io
|
||||
names:
|
||||
kind: Profile
|
||||
listKind: ProfileList
|
||||
plural: profiles
|
||||
singular: profile
|
||||
scope: Namespaced
|
||||
subresources:
|
||||
status: {}
|
||||
validation:
|
||||
openAPIV3Schema:
|
||||
description: Profile is the Schema for the profiles API
|
||||
properties:
|
||||
apiVersion:
|
||||
description: 'APIVersion defines the versioned schema of this representation
|
||||
of an object. Servers should convert recognized schemas to the latest
|
||||
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
||||
type: string
|
||||
kind:
|
||||
description: 'Kind is a string value representing the REST resource this
|
||||
object represents. Servers may infer this from the endpoint the client
|
||||
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: ProfileSpec defines the desired state of Profile
|
||||
properties:
|
||||
alert:
|
||||
description: Alerting configuration of the kustomizations targeted by
|
||||
this profile.
|
||||
properties:
|
||||
address:
|
||||
description: HTTP(S) webhook address of this provider
|
||||
type: string
|
||||
channel:
|
||||
description: Alert channel for this provider
|
||||
type: string
|
||||
type:
|
||||
description: Type of provider
|
||||
enum:
|
||||
- slack
|
||||
- discord
|
||||
type: string
|
||||
username:
|
||||
description: Bot username for this provider
|
||||
type: string
|
||||
verbosity:
|
||||
description: Filter alerts based on verbosity level, defaults to
|
||||
('error').
|
||||
enum:
|
||||
- info
|
||||
- error
|
||||
type: string
|
||||
required:
|
||||
- address
|
||||
- channel
|
||||
- type
|
||||
- username
|
||||
type: object
|
||||
kustomizations:
|
||||
description: The list of kustomizations that this profile applies to.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
required:
|
||||
- kustomizations
|
||||
type: object
|
||||
status:
|
||||
description: ProfileStatus defines the observed state of Profile
|
||||
properties:
|
||||
conditions:
|
||||
items:
|
||||
description: Condition contains condition information for a kustomization.
|
||||
properties:
|
||||
lastTransitionTime:
|
||||
description: LastTransitionTime is the timestamp corresponding
|
||||
to the last status change of this condition.
|
||||
format: date-time
|
||||
type: string
|
||||
message:
|
||||
description: Message is a human readable description of the details
|
||||
of the last transition, complementing reason.
|
||||
type: string
|
||||
reason:
|
||||
description: Reason is a brief machine readable explanation for
|
||||
the condition's last transition.
|
||||
type: string
|
||||
status:
|
||||
description: Status of the condition, one of ('True', 'False',
|
||||
'Unknown').
|
||||
type: string
|
||||
type:
|
||||
description: Type of the condition, currently ('Ready').
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- type
|
||||
type: object
|
||||
type: array
|
||||
type: object
|
||||
type: object
|
||||
version: v1alpha1
|
||||
versions:
|
||||
- name: v1alpha1
|
||||
served: true
|
||||
storage: true
|
||||
status:
|
||||
acceptedNames:
|
||||
kind: ""
|
||||
plural: ""
|
||||
conditions: []
|
||||
storedVersions: []
|
File diff suppressed because it is too large
Load Diff
|
@ -1,6 +1,7 @@
|
|||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- bases/kustomize.toolkit.fluxcd.io_kustomizations.yaml
|
||||
- bases/kustomize.fluxcd.io_kustomizations.yaml
|
||||
- bases/kustomize.fluxcd.io_profiles.yaml
|
||||
# +kubebuilder:scaffold:crdkustomizeresource
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
namespace: kustomize-system
|
||||
resources:
|
||||
- https://github.com/fluxcd/source-controller/releases/download/v1.7.0-rc.3/source-controller.crds.yaml
|
||||
- https://github.com/fluxcd/source-controller/releases/download/v1.7.0-rc.3/source-controller.deployment.yaml
|
||||
bases:
|
||||
- ../crd
|
||||
- ../rbac
|
||||
- ../manager
|
||||
- namespace.yaml
|
||||
resources:
|
||||
- namespace.yaml
|
||||
|
||||
|
|
|
@ -15,13 +15,9 @@ spec:
|
|||
app: kustomize-controller
|
||||
annotations:
|
||||
prometheus.io/scrape: "true"
|
||||
prometheus.io/port: "8080"
|
||||
prometheus.io/port: "8282"
|
||||
spec:
|
||||
terminationGracePeriodSeconds: 60
|
||||
# Required for AWS IAM Role bindings
|
||||
# https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts-technical-overview.html
|
||||
securityContext:
|
||||
fsGroup: 1337
|
||||
terminationGracePeriodSeconds: 10
|
||||
containers:
|
||||
- name: manager
|
||||
image: fluxcd/kustomize-controller
|
||||
|
@ -29,37 +25,16 @@ spec:
|
|||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
readOnlyRootFilesystem: true
|
||||
runAsNonRoot: true
|
||||
capabilities:
|
||||
drop: [ "ALL" ]
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
- containerPort: 8282
|
||||
name: http-prom
|
||||
protocol: TCP
|
||||
- containerPort: 9440
|
||||
name: healthz
|
||||
protocol: TCP
|
||||
env:
|
||||
- name: RUNTIME_NAMESPACE
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.namespace
|
||||
args:
|
||||
- --watch-all-namespaces
|
||||
- --log-level=info
|
||||
- --log-encoding=json
|
||||
- --enable-leader-election
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /readyz
|
||||
port: healthz
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: healthz
|
||||
port: http-prom
|
||||
path: /metrics
|
||||
args:
|
||||
- --enable-leader-election
|
||||
- --log-json
|
||||
resources:
|
||||
limits:
|
||||
cpu: 1000m
|
||||
|
|
|
@ -5,4 +5,4 @@ resources:
|
|||
images:
|
||||
- name: fluxcd/kustomize-controller
|
||||
newName: fluxcd/kustomize-controller
|
||||
newTag: v1.6.0
|
||||
newTag: v0.0.1-alpha.4
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: reconciler-role
|
||||
rules:
|
||||
- apiGroups: ['*']
|
||||
resources: ['*']
|
||||
verbs: ['*']
|
||||
- nonResourceURLs: ['*']
|
||||
verbs: ['*']
|
|
@ -1,11 +1,11 @@
|
|||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: cluster-reconciler
|
||||
name: reconciler-rolebinding
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: cluster-admin
|
||||
name: reconciler-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: default
|
||||
|
|
|
@ -5,5 +5,6 @@ resources:
|
|||
- role_binding.yaml
|
||||
- leader_election_role.yaml
|
||||
- leader_election_role_binding.yaml
|
||||
- cluster_role.yaml
|
||||
- cluster_role_binding.yaml
|
||||
namePrefix: kustomize-
|
||||
|
|
|
@ -5,7 +5,7 @@ metadata:
|
|||
name: kustomization-editor-role
|
||||
rules:
|
||||
- apiGroups:
|
||||
- kustomize.toolkit.fluxcd.io
|
||||
- kustomize.fluxcd.io
|
||||
resources:
|
||||
- kustomizations
|
||||
verbs:
|
||||
|
@ -17,7 +17,7 @@ rules:
|
|||
- update
|
||||
- watch
|
||||
- apiGroups:
|
||||
- kustomize.toolkit.fluxcd.io
|
||||
- kustomize.fluxcd.io
|
||||
resources:
|
||||
- kustomizations/status
|
||||
verbs:
|
||||
|
|
|
@ -5,7 +5,7 @@ metadata:
|
|||
name: kustomization-viewer-role
|
||||
rules:
|
||||
- apiGroups:
|
||||
- kustomize.toolkit.fluxcd.io
|
||||
- kustomize.fluxcd.io
|
||||
resources:
|
||||
- kustomizations
|
||||
verbs:
|
||||
|
@ -13,7 +13,7 @@ rules:
|
|||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- kustomize.toolkit.fluxcd.io
|
||||
- kustomize.fluxcd.io
|
||||
resources:
|
||||
- kustomizations/status
|
||||
verbs:
|
||||
|
|
|
@ -4,41 +4,29 @@ kind: Role
|
|||
metadata:
|
||||
name: leader-election-role
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- configmaps
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- create
|
||||
- update
|
||||
- patch
|
||||
- delete
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- configmaps/status
|
||||
verbs:
|
||||
- get
|
||||
- update
|
||||
- patch
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- events
|
||||
verbs:
|
||||
- create
|
||||
- apiGroups:
|
||||
- "coordination.k8s.io"
|
||||
resources:
|
||||
- leases
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- create
|
||||
- update
|
||||
- patch
|
||||
- delete
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- configmaps
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- create
|
||||
- update
|
||||
- patch
|
||||
- delete
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- configmaps/status
|
||||
verbs:
|
||||
- get
|
||||
- update
|
||||
- patch
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- events
|
||||
verbs:
|
||||
- create
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
# permissions for end users to edit profiles.
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: profile-editor-role
|
||||
rules:
|
||||
- apiGroups:
|
||||
- kustomize.fluxcd.io
|
||||
resources:
|
||||
- profiles
|
||||
verbs:
|
||||
- create
|
||||
- delete
|
||||
- get
|
||||
- list
|
||||
- patch
|
||||
- update
|
||||
- watch
|
||||
- apiGroups:
|
||||
- kustomize.fluxcd.io
|
||||
resources:
|
||||
- profiles/status
|
||||
verbs:
|
||||
- get
|
|
@ -0,0 +1,20 @@
|
|||
# permissions for end users to view profiles.
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: profile-viewer-role
|
||||
rules:
|
||||
- apiGroups:
|
||||
- kustomize.fluxcd.io
|
||||
resources:
|
||||
- profiles
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- kustomize.fluxcd.io
|
||||
resources:
|
||||
- profiles/status
|
||||
verbs:
|
||||
- get
|
|
@ -1,34 +1,13 @@
|
|||
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
name: manager-role
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- configmaps
|
||||
- secrets
|
||||
- serviceaccounts
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- events
|
||||
verbs:
|
||||
- create
|
||||
- patch
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- serviceaccounts/token
|
||||
verbs:
|
||||
- create
|
||||
- apiGroups:
|
||||
- kustomize.toolkit.fluxcd.io
|
||||
- kustomize.fluxcd.io
|
||||
resources:
|
||||
- kustomizations
|
||||
verbs:
|
||||
|
@ -40,17 +19,7 @@ rules:
|
|||
- update
|
||||
- watch
|
||||
- apiGroups:
|
||||
- kustomize.toolkit.fluxcd.io
|
||||
resources:
|
||||
- kustomizations/finalizers
|
||||
verbs:
|
||||
- create
|
||||
- delete
|
||||
- get
|
||||
- patch
|
||||
- update
|
||||
- apiGroups:
|
||||
- kustomize.toolkit.fluxcd.io
|
||||
- kustomize.fluxcd.io
|
||||
resources:
|
||||
- kustomizations/status
|
||||
verbs:
|
||||
|
@ -58,20 +27,36 @@ rules:
|
|||
- patch
|
||||
- update
|
||||
- apiGroups:
|
||||
- source.toolkit.fluxcd.io
|
||||
- kustomize.fluxcd.io
|
||||
resources:
|
||||
- profiles
|
||||
verbs:
|
||||
- create
|
||||
- delete
|
||||
- get
|
||||
- list
|
||||
- patch
|
||||
- update
|
||||
- watch
|
||||
- apiGroups:
|
||||
- kustomize.fluxcd.io
|
||||
resources:
|
||||
- profiles/status
|
||||
verbs:
|
||||
- get
|
||||
- patch
|
||||
- update
|
||||
- apiGroups:
|
||||
- source.fluxcd.io
|
||||
resources:
|
||||
- buckets
|
||||
- gitrepositories
|
||||
- ocirepositories
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- source.toolkit.fluxcd.io
|
||||
- source.fluxcd.io
|
||||
resources:
|
||||
- buckets/status
|
||||
- gitrepositories/status
|
||||
- ocirepositories/status
|
||||
verbs:
|
||||
- get
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
apiVersion: kustomize.toolkit.fluxcd.io/v1
|
||||
kind: Kustomization
|
||||
metadata:
|
||||
name: webapp-dev
|
||||
spec:
|
||||
interval: 5m
|
||||
path: "./deploy/webapp/"
|
||||
prune: true
|
||||
sourceRef:
|
||||
kind: GitRepository
|
||||
name: webapp-latest
|
||||
wait: true
|
||||
timeout: 2m
|
||||
---
|
||||
apiVersion: kustomize.toolkit.fluxcd.io/v1
|
||||
kind: Kustomization
|
||||
metadata:
|
||||
name: webapp-production
|
||||
spec:
|
||||
interval: 15m
|
||||
path: "./deploy/overlays/production/"
|
||||
prune: true
|
||||
sourceRef:
|
||||
kind: GitRepository
|
||||
name: webapp-releases
|
||||
healthChecks:
|
||||
- kind: Deployment
|
||||
name: backend
|
||||
namespace: production
|
||||
- kind: Deployment
|
||||
name: frontend
|
||||
namespace: production
|
||||
timeout: 2m
|
|
@ -0,0 +1,43 @@
|
|||
apiVersion: kustomize.fluxcd.io/v1alpha1
|
||||
kind: Kustomization
|
||||
metadata:
|
||||
name: podinfo-dev
|
||||
spec:
|
||||
interval: 5m
|
||||
path: "./overlays/dev/"
|
||||
prune: "env=dev"
|
||||
suspend: false
|
||||
sourceRef:
|
||||
kind: GitRepository
|
||||
name: podinfo
|
||||
healthChecks:
|
||||
- kind: Deployment
|
||||
name: podinfo
|
||||
namespace: dev
|
||||
timeout: 80s
|
||||
---
|
||||
apiVersion: kustomize.fluxcd.io/v1alpha1
|
||||
kind: Kustomization
|
||||
metadata:
|
||||
name: podinfo-staging
|
||||
spec:
|
||||
interval: 5m
|
||||
path: "./overlays/staging/"
|
||||
prune: "env=staging"
|
||||
sourceRef:
|
||||
kind: GitRepository
|
||||
name: podinfo
|
||||
validation: client
|
||||
---
|
||||
apiVersion: kustomize.fluxcd.io/v1alpha1
|
||||
kind: Kustomization
|
||||
metadata:
|
||||
name: podinfo-production
|
||||
spec:
|
||||
interval: 5m
|
||||
path: "./overlays/production/"
|
||||
prune: "env=production"
|
||||
sourceRef:
|
||||
kind: GitRepository
|
||||
name: podinfo-releases
|
||||
validation: client
|
|
@ -0,0 +1,13 @@
|
|||
apiVersion: kustomize.fluxcd.io/v1alpha1
|
||||
kind: Profile
|
||||
metadata:
|
||||
name: default
|
||||
spec:
|
||||
alert:
|
||||
type: slack
|
||||
address: https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK
|
||||
username: kustomize-controller
|
||||
channel: general
|
||||
verbosity: info
|
||||
kustomizations:
|
||||
- '*'
|
|
@ -1,19 +0,0 @@
|
|||
apiVersion: source.toolkit.fluxcd.io/v1
|
||||
kind: GitRepository
|
||||
metadata:
|
||||
name: webapp-latest
|
||||
spec:
|
||||
interval: 1m
|
||||
url: https://github.com/stefanprodan/podinfo
|
||||
ref:
|
||||
branch: master
|
||||
---
|
||||
apiVersion: source.toolkit.fluxcd.io/v1
|
||||
kind: GitRepository
|
||||
metadata:
|
||||
name: webapp-releases
|
||||
spec:
|
||||
interval: 1m
|
||||
url: https://github.com/stefanprodan/podinfo
|
||||
ref:
|
||||
semver: ">=3.2.3"
|
|
@ -0,0 +1,19 @@
|
|||
apiVersion: source.fluxcd.io/v1alpha1
|
||||
kind: GitRepository
|
||||
metadata:
|
||||
name: podinfo
|
||||
spec:
|
||||
interval: 1m
|
||||
url: https://github.com/stefanprodan/podinfo-deploy
|
||||
ref:
|
||||
branch: master
|
||||
---
|
||||
apiVersion: source.fluxcd.io/v1alpha1
|
||||
kind: GitRepository
|
||||
metadata:
|
||||
name: podinfo-releases
|
||||
spec:
|
||||
interval: 1m
|
||||
url: https://github.com/stefanprodan/podinfo-deploy
|
||||
ref:
|
||||
semver: ">=0.0.1"
|
|
@ -1,23 +0,0 @@
|
|||
apiVersion: source.toolkit.fluxcd.io/v1
|
||||
kind: GitRepository
|
||||
metadata:
|
||||
name: certs
|
||||
spec:
|
||||
interval: 15m
|
||||
url: https://github.com/stefanprodan/kustomizer
|
||||
ref:
|
||||
tag: "v1.1.0"
|
||||
---
|
||||
apiVersion: kustomize.toolkit.fluxcd.io/v1
|
||||
kind: Kustomization
|
||||
metadata:
|
||||
name: certs
|
||||
spec:
|
||||
interval: 10m
|
||||
path: "./testdata/certs"
|
||||
prune: true
|
||||
sourceRef:
|
||||
kind: GitRepository
|
||||
name: certs
|
||||
wait: true
|
||||
timeout: 2m
|
|
@ -1,19 +0,0 @@
|
|||
apiVersion: kustomize.toolkit.fluxcd.io/v1
|
||||
kind: Kustomization
|
||||
metadata:
|
||||
name: frontend
|
||||
spec:
|
||||
dependsOn:
|
||||
- name: common
|
||||
- name: backend
|
||||
interval: 5m
|
||||
path: "./deploy/webapp/frontend/"
|
||||
prune: true
|
||||
sourceRef:
|
||||
kind: GitRepository
|
||||
name: webapp
|
||||
healthChecks:
|
||||
- kind: Deployment
|
||||
name: frontend
|
||||
namespace: webapp
|
||||
timeout: 2m
|
|
@ -1,9 +0,0 @@
|
|||
apiVersion: source.toolkit.fluxcd.io/v1
|
||||
kind: GitRepository
|
||||
metadata:
|
||||
name: webapp
|
||||
spec:
|
||||
interval: 10m
|
||||
url: https://github.com/stefanprodan/podinfo
|
||||
ref:
|
||||
semver: ">=6.3.5"
|
|
@ -0,0 +1,19 @@
|
|||
apiVersion: kustomize.fluxcd.io/v1alpha1
|
||||
kind: Kustomization
|
||||
metadata:
|
||||
name: generate
|
||||
spec:
|
||||
interval: 5m
|
||||
generate: true
|
||||
path: "./plain/"
|
||||
prune: "env=test"
|
||||
sourceRef:
|
||||
kind: GitRepository
|
||||
name: webapp
|
||||
healthChecks:
|
||||
- kind: Deployment
|
||||
name: backend
|
||||
namespace: test
|
||||
- kind: Deployment
|
||||
name: frontend
|
||||
namespace: test
|
|
@ -0,0 +1,9 @@
|
|||
apiVersion: source.fluxcd.io/v1alpha1
|
||||
kind: GitRepository
|
||||
metadata:
|
||||
name: webapp
|
||||
spec:
|
||||
interval: 10m
|
||||
url: https://github.com/stefanprodan/podinfo-deploy
|
||||
ref:
|
||||
branch: master
|
|
@ -1,6 +1,6 @@
|
|||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- deployment.yaml
|
||||
|
||||
- gitrepository.yaml
|
||||
- generate.yaml
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: impersonation
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: gotk-reconciler
|
||||
namespace: impersonation
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: gotk-reconciler
|
||||
namespace: impersonation
|
||||
rules:
|
||||
- apiGroups: ['*']
|
||||
resources: ['*']
|
||||
verbs: ['*']
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: gotk-reconciler
|
||||
namespace: impersonation
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: gotk-reconciler
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: gotk-reconciler
|
||||
namespace: impersonation
|
||||
---
|
||||
apiVersion: source.toolkit.fluxcd.io/v1
|
||||
kind: GitRepository
|
||||
metadata:
|
||||
name: podinfo
|
||||
namespace: impersonation
|
||||
spec:
|
||||
interval: 5m
|
||||
url: https://github.com/stefanprodan/podinfo
|
||||
ref:
|
||||
tag: "6.3.5"
|
||||
---
|
||||
apiVersion: kustomize.toolkit.fluxcd.io/v1
|
||||
kind: Kustomization
|
||||
metadata:
|
||||
name: podinfo
|
||||
namespace: impersonation
|
||||
spec:
|
||||
targetNamespace: impersonation
|
||||
serviceAccountName: gotk-reconciler
|
||||
interval: 5m
|
||||
path: "./kustomize"
|
||||
prune: true
|
||||
sourceRef:
|
||||
kind: GitRepository
|
||||
name: podinfo
|
||||
patches:
|
||||
- patch: |
|
||||
apiVersion: autoscaling/v2
|
||||
kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
name: podinfo
|
||||
spec:
|
||||
minReplicas: 1
|
||||
target:
|
||||
kind: HorizontalPodAutoscaler
|
||||
wait: true
|
||||
timeout: 1m
|
|
@ -1,23 +0,0 @@
|
|||
apiVersion: kustomize.toolkit.fluxcd.io/v1
|
||||
kind: Kustomization
|
||||
metadata:
|
||||
name: podinfo
|
||||
spec:
|
||||
interval: 15m
|
||||
path: "./kustomize/"
|
||||
prune: true
|
||||
sourceRef:
|
||||
kind: GitRepository
|
||||
name: podinfo
|
||||
timeout: 1m
|
||||
targetNamespace: managed-fields
|
||||
---
|
||||
apiVersion: source.toolkit.fluxcd.io/v1
|
||||
kind: GitRepository
|
||||
metadata:
|
||||
name: podinfo
|
||||
spec:
|
||||
interval: 5m
|
||||
url: https://github.com/stefanprodan/podinfo
|
||||
ref:
|
||||
semver: "6.3.5"
|
|
@ -1,37 +0,0 @@
|
|||
apiVersion: source.toolkit.fluxcd.io/v1
|
||||
kind: OCIRepository
|
||||
metadata:
|
||||
name: oci
|
||||
namespace: oci
|
||||
spec:
|
||||
interval: 10m
|
||||
url: oci://ghcr.io/stefanprodan/manifests/podinfo
|
||||
ref:
|
||||
tag: "6.3.5"
|
||||
---
|
||||
apiVersion: kustomize.toolkit.fluxcd.io/v1
|
||||
kind: Kustomization
|
||||
metadata:
|
||||
name: oci
|
||||
namespace: oci
|
||||
spec:
|
||||
targetNamespace: oci
|
||||
interval: 10m
|
||||
path: "./"
|
||||
prune: true
|
||||
sourceRef:
|
||||
kind: OCIRepository
|
||||
name: oci
|
||||
wait: true
|
||||
timeout: 2m
|
||||
patches:
|
||||
- patch: |-
|
||||
apiVersion: autoscaling/v2
|
||||
kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
name: podinfo
|
||||
spec:
|
||||
minReplicas: 1
|
||||
target:
|
||||
name: podinfo
|
||||
kind: HorizontalPodAutoscaler
|
|
@ -1,6 +0,0 @@
|
|||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- staging.yaml
|
||||
- production.yaml
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
apiVersion: kustomize.toolkit.fluxcd.io/v1
|
||||
kind: Kustomization
|
||||
metadata:
|
||||
name: webapp-production
|
||||
spec:
|
||||
interval: 15m
|
||||
path: "./deploy/overlays/production/"
|
||||
prune: true
|
||||
sourceRef:
|
||||
kind: GitRepository
|
||||
name: webapp-releases
|
||||
healthChecks:
|
||||
- kind: Deployment
|
||||
name: backend
|
||||
namespace: production
|
||||
- kind: Deployment
|
||||
name: frontend
|
||||
namespace: production
|
||||
timeout: 2m
|
||||
---
|
||||
apiVersion: source.toolkit.fluxcd.io/v1
|
||||
kind: GitRepository
|
||||
metadata:
|
||||
name: webapp-releases
|
||||
spec:
|
||||
interval: 5m
|
||||
url: https://github.com/stefanprodan/podinfo
|
||||
ref:
|
||||
semver: ">=6.3.5"
|
|
@ -1,29 +0,0 @@
|
|||
apiVersion: kustomize.toolkit.fluxcd.io/v1
|
||||
kind: Kustomization
|
||||
metadata:
|
||||
name: webapp-staging
|
||||
spec:
|
||||
interval: 5m
|
||||
path: "./deploy/overlays/staging/"
|
||||
prune: true
|
||||
sourceRef:
|
||||
kind: GitRepository
|
||||
name: webapp-releases
|
||||
healthChecks:
|
||||
- kind: Deployment
|
||||
name: backend
|
||||
namespace: staging
|
||||
- kind: Deployment
|
||||
name: frontend
|
||||
namespace: staging
|
||||
timeout: 2m
|
||||
---
|
||||
apiVersion: source.toolkit.fluxcd.io/v1
|
||||
kind: GitRepository
|
||||
metadata:
|
||||
name: webapp-latest
|
||||
spec:
|
||||
interval: 5m
|
||||
url: https://github.com/stefanprodan/podinfo
|
||||
ref:
|
||||
branch: master
|
|
@ -1,4 +0,0 @@
|
|||
apiVersion: kustomize.toolkit.fluxcd.io/v1
|
||||
kind: Kustomization
|
||||
metadata:
|
||||
name: status-defaults
|
|
@ -1,13 +1,13 @@
|
|||
apiVersion: kustomize.toolkit.fluxcd.io/v1
|
||||
apiVersion: kustomize.fluxcd.io/v1alpha1
|
||||
kind: Kustomization
|
||||
metadata:
|
||||
name: backend
|
||||
spec:
|
||||
dependsOn:
|
||||
- name: common
|
||||
- common
|
||||
interval: 5m
|
||||
path: "./deploy/webapp/backend/"
|
||||
prune: true
|
||||
path: "./webapp/backend/"
|
||||
prune: "part-of=webapp,component=backend"
|
||||
sourceRef:
|
||||
kind: GitRepository
|
||||
name: webapp
|
||||
|
@ -15,4 +15,3 @@ spec:
|
|||
- kind: Deployment
|
||||
name: backend
|
||||
namespace: webapp
|
||||
timeout: 2m
|
|
@ -1,11 +1,12 @@
|
|||
apiVersion: kustomize.toolkit.fluxcd.io/v1
|
||||
apiVersion: kustomize.fluxcd.io/v1alpha1
|
||||
kind: Kustomization
|
||||
metadata:
|
||||
name: common
|
||||
spec:
|
||||
interval: 5m
|
||||
path: "./deploy/webapp/common/"
|
||||
prune: true
|
||||
path: "./webapp/common/"
|
||||
prune: "part-of=webapp"
|
||||
sourceRef:
|
||||
kind: GitRepository
|
||||
name: webapp
|
||||
validate: client
|
|
@ -0,0 +1,14 @@
|
|||
apiVersion: kustomize.fluxcd.io/v1alpha1
|
||||
kind: Kustomization
|
||||
metadata:
|
||||
name: frontend
|
||||
spec:
|
||||
dependsOn:
|
||||
- common
|
||||
- backend
|
||||
interval: 5m
|
||||
path: "./webapp/frontend/"
|
||||
prune: "part-of=webapp,component=frontend"
|
||||
sourceRef:
|
||||
kind: GitRepository
|
||||
name: webapp
|
|
@ -0,0 +1,9 @@
|
|||
apiVersion: source.fluxcd.io/v1alpha1
|
||||
kind: GitRepository
|
||||
metadata:
|
||||
name: webapp
|
||||
spec:
|
||||
interval: 10m
|
||||
url: https://github.com/stefanprodan/podinfo-deploy
|
||||
ref:
|
||||
branch: master
|
|
@ -1,7 +1,7 @@
|
|||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- source.yaml
|
||||
- gitrepository.yaml
|
||||
- common.yaml
|
||||
- backend.yaml
|
||||
- frontend.yaml
|
|
@ -0,0 +1,14 @@
|
|||
apiVersion: kustomize.fluxcd.io/v1alpha1
|
||||
kind: Kustomization
|
||||
metadata:
|
||||
name: test
|
||||
spec:
|
||||
dependsOn:
|
||||
- common
|
||||
interval: 5m
|
||||
path: "./webapp/test/"
|
||||
prune: "part-of=webapp,component=test"
|
||||
sourceRef:
|
||||
kind: GitRepository
|
||||
name: webapp
|
||||
validation: client
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
Copyright 2020 The Flux CD contributors.
|
||||
|
||||
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"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1alpha1"
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1alpha1"
|
||||
)
|
||||
|
||||
// KustomizationReconciler watches a GitRepository object
|
||||
type GitRepositoryWatcher struct {
|
||||
client.Client
|
||||
Log logr.Logger
|
||||
Scheme *runtime.Scheme
|
||||
}
|
||||
|
||||
// +kubebuilder:rbac:groups=source.fluxcd.io,resources=gitrepositories,verbs=get;list;watch
|
||||
// +kubebuilder:rbac:groups=source.fluxcd.io,resources=gitrepositories/status,verbs=get
|
||||
|
||||
func (r *GitRepositoryWatcher) Reconcile(req ctrl.Request) (ctrl.Result, error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
||||
defer cancel()
|
||||
|
||||
var repo sourcev1.GitRepository
|
||||
if err := r.Get(ctx, req.NamespacedName, &repo); err != nil {
|
||||
return ctrl.Result{}, client.IgnoreNotFound(err)
|
||||
}
|
||||
|
||||
log := r.Log.WithValues(strings.ToLower(repo.Kind), req.NamespacedName)
|
||||
log.Info("New artifact detected")
|
||||
|
||||
// get the list of kustomizations that are using this Git repository
|
||||
var list kustomizev1.KustomizationList
|
||||
if err := r.List(ctx, &list, client.InNamespace(req.Namespace),
|
||||
client.MatchingFields{kustomizev1.SourceIndexKey: req.Name}); err != nil {
|
||||
log.Error(err, "unable to list kustomizations")
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
|
||||
// trigger apply for each kustomization using this Git repository
|
||||
for _, kustomization := range list.Items {
|
||||
kustomization.Annotations[kustomizev1.SyncAtAnnotation] = metav1.Now().String()
|
||||
if kustomization.Spec.SourceRef.APIGroup == nil {
|
||||
emptyAPIGroup := ""
|
||||
kustomization.Spec.SourceRef.APIGroup = &emptyAPIGroup
|
||||
}
|
||||
if err := r.Update(ctx, &kustomization); err != nil {
|
||||
log.Error(err, "unable to annotate kustomization", "kustomization", kustomization.GetName())
|
||||
}
|
||||
log.Info("Run kustomization", "kustomization", kustomization.GetName())
|
||||
}
|
||||
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
func (r *GitRepositoryWatcher) SetupWithManager(mgr ctrl.Manager) error {
|
||||
// create a kustomization index based on Git repository name
|
||||
err := mgr.GetFieldIndexer().IndexField(&kustomizev1.Kustomization{}, kustomizev1.SourceIndexKey,
|
||||
func(rawObj runtime.Object) []string {
|
||||
k := rawObj.(*kustomizev1.Kustomization)
|
||||
if k.Spec.SourceRef.Kind == "GitRepository" {
|
||||
return []string{k.Spec.SourceRef.Name}
|
||||
}
|
||||
return nil
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return ctrl.NewControllerManagedBy(mgr).
|
||||
For(&sourcev1.GitRepository{}).
|
||||
WithEventFilter(GitRepositoryRevisionChangePredicate{}).
|
||||
Complete(r)
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
Copyright 2020 The Flux CD contributors.
|
||||
|
||||
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 (
|
||||
"sigs.k8s.io/controller-runtime/pkg/event"
|
||||
"sigs.k8s.io/controller-runtime/pkg/predicate"
|
||||
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1alpha1"
|
||||
)
|
||||
|
||||
type GitRepositoryRevisionChangePredicate struct {
|
||||
predicate.Funcs
|
||||
}
|
||||
|
||||
func (GitRepositoryRevisionChangePredicate) Update(e event.UpdateEvent) bool {
|
||||
if e.MetaOld == nil || e.MetaNew == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
oldRepo, ok := e.ObjectOld.(*sourcev1.GitRepository)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
newRepo, ok := e.ObjectNew.(*sourcev1.GitRepository)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
if oldRepo.GetArtifact() == nil && newRepo.GetArtifact() != nil {
|
||||
return true
|
||||
}
|
||||
|
||||
if oldRepo.GetArtifact() != nil && newRepo.GetArtifact() != nil &&
|
||||
oldRepo.GetArtifact().Revision != newRepo.GetArtifact().Revision {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (GitRepositoryRevisionChangePredicate) Create(e event.CreateEvent) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (GitRepositoryRevisionChangePredicate) Delete(e event.DeleteEvent) bool {
|
||||
return false
|
||||
}
|
|
@ -0,0 +1,605 @@
|
|||
/*
|
||||
Copyright 2020 The Flux CD contributors.
|
||||
|
||||
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 (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"strings"
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller"
|
||||
|
||||
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1alpha1"
|
||||
"github.com/fluxcd/kustomize-controller/internal/alert"
|
||||
"github.com/fluxcd/kustomize-controller/internal/lockedfile"
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1alpha1"
|
||||
)
|
||||
|
||||
// KustomizationReconciler reconciles a Kustomization object
|
||||
type KustomizationReconciler struct {
|
||||
client.Client
|
||||
Log logr.Logger
|
||||
Scheme *runtime.Scheme
|
||||
}
|
||||
|
||||
// +kubebuilder:rbac:groups=kustomize.fluxcd.io,resources=kustomizations,verbs=get;list;watch;create;update;patch;delete
|
||||
// +kubebuilder:rbac:groups=kustomize.fluxcd.io,resources=kustomizations/status,verbs=get;update;patch
|
||||
|
||||
func (r *KustomizationReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
|
||||
ctx := context.Background()
|
||||
syncStart := time.Now()
|
||||
|
||||
var kustomization kustomizev1.Kustomization
|
||||
if err := r.Get(ctx, req.NamespacedName, &kustomization); err != nil {
|
||||
return ctrl.Result{}, client.IgnoreNotFound(err)
|
||||
}
|
||||
|
||||
log := r.Log.WithValues(strings.ToLower(kustomization.Kind), req.NamespacedName)
|
||||
|
||||
if kustomization.Spec.Suspend {
|
||||
msg := "Kustomization is suspended, skipping execution"
|
||||
kustomization = kustomizev1.KustomizationNotReady(kustomization, kustomizev1.SuspendedReason, msg)
|
||||
if err := r.Status().Update(ctx, &kustomization); err != nil {
|
||||
log.Error(err, "unable to update Kustomization status")
|
||||
return ctrl.Result{Requeue: true}, err
|
||||
}
|
||||
log.Info(msg)
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
var source sourcev1.Source
|
||||
|
||||
// get artifact source from Git repository
|
||||
if kustomization.Spec.SourceRef.Kind == "GitRepository" {
|
||||
var repository sourcev1.GitRepository
|
||||
repositoryName := types.NamespacedName{
|
||||
Namespace: kustomization.GetNamespace(),
|
||||
Name: kustomization.Spec.SourceRef.Name,
|
||||
}
|
||||
err := r.Client.Get(ctx, repositoryName, &repository)
|
||||
if err != nil {
|
||||
log.Error(err, "GitRepository not found", "gitrepository", repositoryName)
|
||||
return ctrl.Result{Requeue: true}, err
|
||||
}
|
||||
source = &repository
|
||||
}
|
||||
|
||||
if source == nil {
|
||||
err := fmt.Errorf("source `%s` kind '%s' not supported",
|
||||
kustomization.Spec.SourceRef.Name, kustomization.Spec.SourceRef.Kind)
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
|
||||
// check source readiness
|
||||
if source.GetArtifact() == nil {
|
||||
msg := "Source is not ready"
|
||||
kustomization = kustomizev1.KustomizationNotReady(kustomization, kustomizev1.ArtifactFailedReason, msg)
|
||||
if err := r.Status().Update(ctx, &kustomization); err != nil {
|
||||
log.Error(err, "unable to update Kustomization status")
|
||||
return ctrl.Result{Requeue: true}, err
|
||||
}
|
||||
log.Info(msg)
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
// check dependencies
|
||||
if len(kustomization.Spec.DependsOn) > 0 {
|
||||
if err := r.checkDependencies(kustomization); err != nil {
|
||||
kustomization = kustomizev1.KustomizationNotReady(kustomization, kustomizev1.DependencyNotReadyReason, err.Error())
|
||||
if err := r.Status().Update(ctx, &kustomization); err != nil {
|
||||
log.Error(err, "unable to update Kustomization status")
|
||||
return ctrl.Result{Requeue: true}, err
|
||||
}
|
||||
// we can't rely on exponential backoff because it will prolong the execution too much,
|
||||
// instead we requeue every half a minute.
|
||||
requeueAfter := 30 * time.Second
|
||||
msg := fmt.Sprintf("Dependencies do not meet ready condition, retrying in %s", requeueAfter.String())
|
||||
log.Error(err, msg)
|
||||
r.alert(kustomization, msg, "info")
|
||||
return ctrl.Result{RequeueAfter: requeueAfter}, nil
|
||||
}
|
||||
log.Info("All dependencies area ready, proceeding with apply")
|
||||
}
|
||||
|
||||
// try sync
|
||||
syncedKustomization, err := r.sync(*kustomization.DeepCopy(), source)
|
||||
if err != nil {
|
||||
log.Error(err, "Kustomization apply failed")
|
||||
r.alert(kustomization, err.Error(), "error")
|
||||
}
|
||||
|
||||
// update status
|
||||
if err := r.Status().Update(ctx, &syncedKustomization); err != nil {
|
||||
log.Error(err, "unable to update Kustomization status")
|
||||
return ctrl.Result{Requeue: true}, err
|
||||
}
|
||||
|
||||
// log sync duration
|
||||
log.Info(fmt.Sprintf("Kustomization sync finished in %s, next run in %s",
|
||||
time.Now().Sub(syncStart).String(),
|
||||
kustomization.Spec.Interval.Duration.String(),
|
||||
))
|
||||
|
||||
// requeue kustomization
|
||||
return ctrl.Result{RequeueAfter: kustomization.Spec.Interval.Duration}, nil
|
||||
}
|
||||
|
||||
func (r *KustomizationReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
||||
return ctrl.NewControllerManagedBy(mgr).
|
||||
For(&kustomizev1.Kustomization{}).
|
||||
WithEventFilter(KustomizationGarbageCollectPredicate{Log: r.Log}).
|
||||
WithEventFilter(KustomizationSyncAtPredicate{}).
|
||||
WithOptions(controller.Options{MaxConcurrentReconciles: 4}).
|
||||
Complete(r)
|
||||
}
|
||||
|
||||
func (r *KustomizationReconciler) sync(
|
||||
kustomization kustomizev1.Kustomization,
|
||||
source sourcev1.Source) (kustomizev1.Kustomization, error) {
|
||||
// acquire lock
|
||||
unlock, err := r.lock(fmt.Sprintf("%s-%s", kustomization.GetName(), kustomization.GetNamespace()))
|
||||
if err != nil {
|
||||
err = fmt.Errorf("tmp dir error: %w", err)
|
||||
return kustomizev1.KustomizationNotReady(kustomization, sourcev1.StorageOperationFailedReason, err.Error()), err
|
||||
}
|
||||
defer unlock()
|
||||
|
||||
// create tmp dir
|
||||
tmpDir, err := ioutil.TempDir("", kustomization.Name)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("tmp dir error: %w", err)
|
||||
return kustomizev1.KustomizationNotReady(kustomization, sourcev1.StorageOperationFailedReason, err.Error()), err
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
// download artifact and extract files
|
||||
err = r.download(kustomization, source.GetArtifact().URL, tmpDir)
|
||||
if err != nil {
|
||||
return kustomizev1.KustomizationNotReady(
|
||||
kustomization,
|
||||
kustomizev1.ArtifactFailedReason,
|
||||
"artifact acquisition failed",
|
||||
), err
|
||||
}
|
||||
|
||||
// check build path exists
|
||||
if _, err := os.Stat(path.Join(tmpDir, kustomization.Spec.Path)); err != nil {
|
||||
err = fmt.Errorf("kustomization path not found: %w", err)
|
||||
return kustomizev1.KustomizationNotReady(
|
||||
kustomization,
|
||||
kustomizev1.ArtifactFailedReason,
|
||||
err.Error(),
|
||||
), err
|
||||
}
|
||||
|
||||
// generate kustomization.yaml
|
||||
err = r.generate(kustomization, tmpDir)
|
||||
if err != nil {
|
||||
return kustomizev1.KustomizationNotReady(
|
||||
kustomization,
|
||||
kustomizev1.BuildFailedReason,
|
||||
"kustomize create failed",
|
||||
), err
|
||||
}
|
||||
|
||||
// kustomize build
|
||||
err = r.build(kustomization, tmpDir)
|
||||
if err != nil {
|
||||
return kustomizev1.KustomizationNotReady(
|
||||
kustomization,
|
||||
kustomizev1.BuildFailedReason,
|
||||
"kustomize build failed",
|
||||
), err
|
||||
}
|
||||
|
||||
// dry-run apply
|
||||
err = r.validate(kustomization, tmpDir)
|
||||
if err != nil {
|
||||
return kustomizev1.KustomizationNotReady(
|
||||
kustomization,
|
||||
kustomizev1.ValidationFailedReason,
|
||||
fmt.Sprintf("%s-side validation failed", kustomization.Spec.Validation),
|
||||
), err
|
||||
}
|
||||
|
||||
// apply
|
||||
err = r.apply(kustomization, tmpDir)
|
||||
if err != nil {
|
||||
return kustomizev1.KustomizationNotReady(
|
||||
kustomization,
|
||||
kustomizev1.ApplyFailedReason,
|
||||
"apply failed",
|
||||
), err
|
||||
}
|
||||
|
||||
// health assessment
|
||||
err = r.checkHealth(kustomization)
|
||||
if err != nil {
|
||||
return kustomizev1.KustomizationNotReady(
|
||||
kustomization,
|
||||
kustomizev1.HealthCheckFailedReason,
|
||||
"health check failed",
|
||||
), err
|
||||
}
|
||||
|
||||
return kustomizev1.KustomizationReady(
|
||||
kustomization,
|
||||
source.GetArtifact().Revision,
|
||||
kustomizev1.ApplySucceedReason,
|
||||
"kustomization was successfully applied",
|
||||
), nil
|
||||
}
|
||||
|
||||
func (r *KustomizationReconciler) download(kustomization kustomizev1.Kustomization, url string, tmpDir string) error {
|
||||
timeout := kustomization.GetTimeout() + (time.Second * 1)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
cmd := fmt.Sprintf("cd %s && curl -sL %s | tar -xz --strip-components=1 -C .",
|
||||
tmpDir, url)
|
||||
command := exec.CommandContext(ctx, "/bin/sh", "-c", cmd)
|
||||
output, err := command.CombinedOutput()
|
||||
if err != nil {
|
||||
if errors.Is(err, context.DeadlineExceeded) {
|
||||
return err
|
||||
}
|
||||
return fmt.Errorf("artifact `%s` download failed: %s", url, string(output))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *KustomizationReconciler) generate(kustomization kustomizev1.Kustomization, tmpDir string) error {
|
||||
if !kustomization.Spec.Generate {
|
||||
return nil
|
||||
}
|
||||
|
||||
timeout := kustomization.GetTimeout() + (time.Second * 1)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
dirPath := path.Join(tmpDir, kustomization.Spec.Path)
|
||||
cmd := fmt.Sprintf("cd %s && kustomize create --autodetect --recursive", dirPath)
|
||||
command := exec.CommandContext(ctx, "/bin/sh", "-c", cmd)
|
||||
output, err := command.CombinedOutput()
|
||||
if err != nil {
|
||||
if errors.Is(err, context.DeadlineExceeded) {
|
||||
return err
|
||||
}
|
||||
return fmt.Errorf("kustomize create failed: %s", string(output))
|
||||
}
|
||||
|
||||
if err := r.generateLabelTransformer(kustomization, dirPath); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *KustomizationReconciler) generateLabelTransformer(kustomization kustomizev1.Kustomization, dirPath string) error {
|
||||
labelTransformer := `
|
||||
apiVersion: builtin
|
||||
kind: LabelTransformer
|
||||
metadata:
|
||||
name: labels
|
||||
labels:
|
||||
{{- range $key, $value := . }}
|
||||
{{ $key }}: {{ $value }}
|
||||
{{- end }}
|
||||
fieldSpecs:
|
||||
- path: metadata/labels
|
||||
create: true
|
||||
`
|
||||
|
||||
transformers := `
|
||||
transformers:
|
||||
- gc-labels.yaml
|
||||
`
|
||||
|
||||
prune := kustomization.Spec.Prune
|
||||
if prune == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
// transform prune into label selectors
|
||||
selectors := make(map[string]string)
|
||||
for _, ls := range strings.Split(prune, ",") {
|
||||
if kv := strings.Split(ls, "="); len(kv) == 2 {
|
||||
selectors[kv[0]] = kv[1]
|
||||
}
|
||||
}
|
||||
|
||||
t, err := template.New("tmpl").Parse(labelTransformer)
|
||||
if err != nil {
|
||||
return fmt.Errorf("labelTransformer template parsing failed: %w", err)
|
||||
}
|
||||
|
||||
var data bytes.Buffer
|
||||
writer := bufio.NewWriter(&data)
|
||||
if err := t.Execute(writer, selectors); err != nil {
|
||||
return fmt.Errorf("labelTransformer template excution failed: %w", err)
|
||||
}
|
||||
|
||||
if err := writer.Flush(); err != nil {
|
||||
return fmt.Errorf("labelTransformer flush failed: %w", err)
|
||||
}
|
||||
|
||||
file, err := os.Create(path.Join(dirPath, "gc-labels.yaml"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("labelTransformer create failed: %w", err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
if _, err := file.WriteString(data.String()); err != nil {
|
||||
return fmt.Errorf("labelTransformer write failed: %w", err)
|
||||
}
|
||||
|
||||
if err := file.Sync(); err != nil {
|
||||
return fmt.Errorf("labelTransformer sync failed: %w", err)
|
||||
}
|
||||
|
||||
kfile, err := os.OpenFile(path.Join(dirPath, "kustomization.yaml"), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
return fmt.Errorf("kustomization file open failed: %w", err)
|
||||
}
|
||||
defer kfile.Close()
|
||||
|
||||
if _, err := kfile.WriteString(transformers); err != nil {
|
||||
return fmt.Errorf("kustomization file append failed: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *KustomizationReconciler) build(kustomization kustomizev1.Kustomization, tmpDir string) error {
|
||||
timeout := kustomization.GetTimeout() + (time.Second * 1)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
cmd := fmt.Sprintf("cd %s && kustomize build %s > %s.yaml",
|
||||
tmpDir, kustomization.Spec.Path, kustomization.GetName())
|
||||
command := exec.CommandContext(ctx, "/bin/sh", "-c", cmd)
|
||||
output, err := command.CombinedOutput()
|
||||
if err != nil {
|
||||
if errors.Is(err, context.DeadlineExceeded) {
|
||||
return err
|
||||
}
|
||||
return fmt.Errorf("kustomize build failed: %s", string(output))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *KustomizationReconciler) validate(kustomization kustomizev1.Kustomization, tmpDir string) error {
|
||||
if kustomization.Spec.Validation == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
timeout := kustomization.GetTimeout() + (time.Second * 1)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
cmd := fmt.Sprintf("cd %s && kubectl apply -f %s.yaml --timeout=%s --dry-run=%s",
|
||||
tmpDir, kustomization.GetName(), kustomization.GetTimeout().String(), kustomization.Spec.Validation)
|
||||
command := exec.CommandContext(ctx, "/bin/sh", "-c", cmd)
|
||||
output, err := command.CombinedOutput()
|
||||
if err != nil {
|
||||
if errors.Is(err, context.DeadlineExceeded) {
|
||||
return fmt.Errorf("validation timeout: %w", err)
|
||||
}
|
||||
return fmt.Errorf("validation failed: %s", string(output))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *KustomizationReconciler) apply(kustomization kustomizev1.Kustomization, tmpDir string) error {
|
||||
start := time.Now()
|
||||
timeout := kustomization.GetTimeout() + (time.Second * 1)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
cmd := fmt.Sprintf("cd %s && kubectl apply -f %s.yaml --timeout=%s",
|
||||
tmpDir, kustomization.GetName(), kustomization.Spec.Interval.Duration.String())
|
||||
if kustomization.Spec.Prune != "" {
|
||||
cmd = fmt.Sprintf("%s --prune -l %s", cmd, kustomization.Spec.Prune)
|
||||
}
|
||||
command := exec.CommandContext(ctx, "/bin/sh", "-c", cmd)
|
||||
output, err := command.CombinedOutput()
|
||||
if err != nil {
|
||||
if errors.Is(err, context.DeadlineExceeded) {
|
||||
return fmt.Errorf("apply timeout: %w", err)
|
||||
}
|
||||
return fmt.Errorf("apply failed: %s", string(output))
|
||||
}
|
||||
|
||||
resources := r.parseApplyOutput(output)
|
||||
r.Log.WithValues(
|
||||
strings.ToLower(kustomization.Kind),
|
||||
fmt.Sprintf("%s/%s", kustomization.GetNamespace(), kustomization.GetName()),
|
||||
).Info(
|
||||
fmt.Sprintf("Kustomization applied in %s",
|
||||
time.Now().Sub(start).String()),
|
||||
"output", resources,
|
||||
)
|
||||
|
||||
var diff bool
|
||||
for _, action := range resources {
|
||||
if action != "unchanged" {
|
||||
diff = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if diff {
|
||||
r.alert(kustomization, string(output), "info")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *KustomizationReconciler) checkHealth(kustomization kustomizev1.Kustomization) error {
|
||||
timeout := kustomization.GetTimeout() + (time.Second * 1)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
var alerts string
|
||||
|
||||
for _, check := range kustomization.Spec.HealthChecks {
|
||||
cmd := fmt.Sprintf("kubectl -n %s rollout status %s %s --timeout=%s",
|
||||
check.Namespace, check.Kind, check.Name, kustomization.GetTimeout())
|
||||
command := exec.CommandContext(ctx, "/bin/sh", "-c", cmd)
|
||||
output, err := command.CombinedOutput()
|
||||
if err != nil {
|
||||
if errors.Is(err, context.DeadlineExceeded) {
|
||||
return fmt.Errorf("health check timeout for %s '%s/%s': %w",
|
||||
check.Kind, check.Namespace, check.Name, err)
|
||||
}
|
||||
return fmt.Errorf("health check failed for %s '%s/%s': %s",
|
||||
check.Kind, check.Namespace, check.Name, string(output))
|
||||
} else {
|
||||
msg := fmt.Sprintf("Health check passed for %s '%s/%s'",
|
||||
check.Kind, check.Namespace, check.Name)
|
||||
r.Log.WithValues(
|
||||
strings.ToLower(kustomization.Kind),
|
||||
fmt.Sprintf("%s/%s", kustomization.GetNamespace(), kustomization.GetName()),
|
||||
).Info(msg)
|
||||
alerts += msg + "\n"
|
||||
}
|
||||
}
|
||||
|
||||
if alerts != "" {
|
||||
r.alert(kustomization, alerts, "info")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *KustomizationReconciler) lock(name string) (unlock func(), err error) {
|
||||
lockFile := path.Join(os.TempDir(), name+".lock")
|
||||
mutex := lockedfile.MutexAt(lockFile)
|
||||
return mutex.Lock()
|
||||
}
|
||||
|
||||
func (r *KustomizationReconciler) parseApplyOutput(in []byte) map[string]string {
|
||||
result := make(map[string]string)
|
||||
input := strings.Split(string(in), "\n")
|
||||
if len(input) == 0 {
|
||||
return result
|
||||
}
|
||||
var parts []string
|
||||
for _, str := range input {
|
||||
if str != "" {
|
||||
parts = append(parts, str)
|
||||
}
|
||||
}
|
||||
for _, str := range parts {
|
||||
kv := strings.Split(str, " ")
|
||||
if len(kv) > 1 {
|
||||
result[kv[0]] = kv[1]
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (r *KustomizationReconciler) checkDependencies(kustomization kustomizev1.Kustomization) error {
|
||||
for _, dep := range kustomization.Spec.DependsOn {
|
||||
depName := types.NamespacedName{
|
||||
Namespace: kustomization.GetNamespace(),
|
||||
Name: dep,
|
||||
}
|
||||
var k kustomizev1.Kustomization
|
||||
err := r.Get(context.Background(), depName, &k)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to get '%s' dependency: %w", depName, err)
|
||||
}
|
||||
|
||||
if len(k.Status.Conditions) == 0 {
|
||||
return fmt.Errorf("dependency '%s' is not ready", depName)
|
||||
}
|
||||
|
||||
for _, condition := range k.Status.Conditions {
|
||||
if condition.Type == kustomizev1.ReadyCondition && condition.Status != corev1.ConditionTrue {
|
||||
return fmt.Errorf("dependency '%s' is not ready", depName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *KustomizationReconciler) getProfiles(kustomization kustomizev1.Kustomization) ([]kustomizev1.Profile, error) {
|
||||
list := make([]kustomizev1.Profile, 0)
|
||||
var profiles kustomizev1.ProfileList
|
||||
err := r.List(context.TODO(), &profiles, client.InNamespace(kustomization.GetNamespace()))
|
||||
if err != nil {
|
||||
return list, err
|
||||
}
|
||||
|
||||
// filter profiles that match this kustomization taking into account '*' wildcard
|
||||
for _, profile := range profiles.Items {
|
||||
for _, name := range profile.Spec.Kustomizations {
|
||||
if name == kustomization.GetName() || name == "*" {
|
||||
list = append(list, profile)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list, nil
|
||||
}
|
||||
|
||||
func (r *KustomizationReconciler) alert(kustomization kustomizev1.Kustomization, msg string, verbosity string) {
|
||||
profiles, err := r.getProfiles(kustomization)
|
||||
if err != nil {
|
||||
r.Log.WithValues(
|
||||
strings.ToLower(kustomization.Kind),
|
||||
fmt.Sprintf("%s/%s", kustomization.GetNamespace(), kustomization.GetName()),
|
||||
).Error(err, "unable to list profiles")
|
||||
return
|
||||
}
|
||||
|
||||
for _, profile := range profiles {
|
||||
if settings := profile.Spec.Alert; settings != nil {
|
||||
provider, err := alert.NewProvider(settings.Type, settings.Address, settings.Username, settings.Channel)
|
||||
if err != nil {
|
||||
r.Log.WithValues(
|
||||
strings.ToLower(kustomization.Kind),
|
||||
fmt.Sprintf("%s/%s", kustomization.GetNamespace(), kustomization.GetName()),
|
||||
).Error(err, "unable to configure alert provider")
|
||||
continue
|
||||
}
|
||||
if settings.Verbosity == verbosity || verbosity == "error" {
|
||||
err = provider.Post(kustomization.GetName(), kustomization.GetNamespace(), msg, verbosity)
|
||||
if err != nil {
|
||||
r.Log.WithValues(
|
||||
strings.ToLower(kustomization.Kind),
|
||||
fmt.Sprintf("%s/%s", kustomization.GetNamespace(), kustomization.GetName()),
|
||||
).Error(err, "unable to send alert")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
Copyright 2020 The Flux CD contributors.
|
||||
|
||||
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/exec"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
"sigs.k8s.io/controller-runtime/pkg/event"
|
||||
"sigs.k8s.io/controller-runtime/pkg/predicate"
|
||||
|
||||
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1alpha1"
|
||||
)
|
||||
|
||||
type KustomizationSyncAtPredicate struct {
|
||||
predicate.Funcs
|
||||
}
|
||||
|
||||
func (KustomizationSyncAtPredicate) Update(e event.UpdateEvent) bool {
|
||||
if e.MetaOld == nil || e.MetaNew == nil {
|
||||
// ignore objects without metadata
|
||||
return false
|
||||
}
|
||||
if e.MetaNew.GetGeneration() != e.MetaOld.GetGeneration() {
|
||||
// reconcile on spec changes
|
||||
return true
|
||||
}
|
||||
|
||||
// handle syncAt annotation
|
||||
if val, ok := e.MetaNew.GetAnnotations()[kustomizev1.SyncAtAnnotation]; ok {
|
||||
if valOld, okOld := e.MetaOld.GetAnnotations()[kustomizev1.SyncAtAnnotation]; okOld {
|
||||
if val != valOld {
|
||||
return true
|
||||
}
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
type KustomizationGarbageCollectPredicate struct {
|
||||
predicate.Funcs
|
||||
Log logr.Logger
|
||||
}
|
||||
|
||||
// Delete removes all Kubernetes objects based on the prune label selector.
|
||||
func (gc KustomizationGarbageCollectPredicate) Delete(e event.DeleteEvent) bool {
|
||||
if k, ok := e.Object.(*kustomizev1.Kustomization); ok {
|
||||
if k.Spec.Prune != "" && !k.Spec.Suspend {
|
||||
timeout := k.GetTimeout()
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
resources := `$(kubectl api-resources --verbs=delete -o name | tr "\n" "," | sed -e 's/,$//')`
|
||||
cmd := fmt.Sprintf("kubectl delete %s --all-namespaces --timeout=%s -l %s",
|
||||
resources, timeout.String(), k.Spec.Prune)
|
||||
command := exec.CommandContext(ctx, "/bin/sh", "-c", cmd)
|
||||
if output, err := command.CombinedOutput(); err != nil {
|
||||
gc.Log.Error(err, "Garbage collection failed",
|
||||
"kustomization", fmt.Sprintf("%s/%s", k.GetNamespace(), k.GetName()),
|
||||
"output", string(output))
|
||||
} else {
|
||||
gc.Log.Info("Garbage collection completed",
|
||||
"kustomization", fmt.Sprintf("%s/%s", k.GetNamespace(), k.GetName()),
|
||||
"output", string(output))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
Copyright 2020 The Flux CD contributors.
|
||||
|
||||
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"
|
||||
"strings"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1alpha1"
|
||||
)
|
||||
|
||||
// ProfileReconciler reconciles a Profile object
|
||||
type ProfileReconciler struct {
|
||||
client.Client
|
||||
Log logr.Logger
|
||||
Scheme *runtime.Scheme
|
||||
}
|
||||
|
||||
// +kubebuilder:rbac:groups=kustomize.fluxcd.io,resources=profiles,verbs=get;list;watch;create;update;patch;delete
|
||||
// +kubebuilder:rbac:groups=kustomize.fluxcd.io,resources=profiles/status,verbs=get;update;patch
|
||||
|
||||
func (r *ProfileReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
|
||||
ctx := context.Background()
|
||||
|
||||
var profile kustomizev1.Profile
|
||||
if err := r.Get(ctx, req.NamespacedName, &profile); err != nil {
|
||||
return ctrl.Result{}, client.IgnoreNotFound(err)
|
||||
}
|
||||
|
||||
log := r.Log.WithValues(strings.ToLower(profile.Kind), req.NamespacedName)
|
||||
|
||||
init := true
|
||||
for _, condition := range profile.Status.Conditions {
|
||||
if condition.Type == kustomizev1.ReadyCondition && condition.Status == corev1.ConditionTrue {
|
||||
init = false
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if init {
|
||||
profile.Status.Conditions = []kustomizev1.Condition{
|
||||
{
|
||||
Type: kustomizev1.ReadyCondition,
|
||||
Status: corev1.ConditionTrue,
|
||||
LastTransitionTime: metav1.Now(),
|
||||
Reason: kustomizev1.InitializedReason,
|
||||
Message: kustomizev1.InitializedReason,
|
||||
},
|
||||
}
|
||||
if err := r.Status().Update(ctx, &profile); err != nil {
|
||||
return ctrl.Result{Requeue: true}, err
|
||||
}
|
||||
log.Info("Profile initialised")
|
||||
}
|
||||
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
func (r *ProfileReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
||||
return ctrl.NewControllerManagedBy(mgr).
|
||||
For(&kustomizev1.Profile{}).
|
||||
Complete(r)
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
"k8s.io/client-go/rest"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/envtest"
|
||||
"sigs.k8s.io/controller-runtime/pkg/envtest/printer"
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log/zap"
|
||||
|
||||
kustomizev1alpha1 "github.com/fluxcd/kustomize-controller/api/v1alpha1"
|
||||
// +kubebuilder:scaffold:imports
|
||||
)
|
||||
|
||||
// These tests use Ginkgo (BDD-style Go testing framework). Refer to
|
||||
// http://onsi.github.io/ginkgo/ to learn more about Ginkgo.
|
||||
|
||||
var cfg *rest.Config
|
||||
var k8sClient client.Client
|
||||
var testEnv *envtest.Environment
|
||||
|
||||
func TestAPIs(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
|
||||
RunSpecsWithDefaultAndCustomReporters(t,
|
||||
"Controller Suite",
|
||||
[]Reporter{printer.NewlineReporter{}})
|
||||
}
|
||||
|
||||
var _ = BeforeSuite(func(done Done) {
|
||||
logf.SetLogger(zap.LoggerTo(GinkgoWriter, true))
|
||||
|
||||
By("bootstrapping test environment")
|
||||
testEnv = &envtest.Environment{
|
||||
CRDDirectoryPaths: []string{filepath.Join("..", "config", "crd", "bases")},
|
||||
}
|
||||
|
||||
var err error
|
||||
cfg, err = testEnv.Start()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(cfg).ToNot(BeNil())
|
||||
|
||||
err = kustomizev1alpha1.AddToScheme(scheme.Scheme)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
// +kubebuilder:scaffold:scheme
|
||||
|
||||
k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(k8sClient).ToNot(BeNil())
|
||||
|
||||
close(done)
|
||||
}, 60)
|
||||
|
||||
var _ = AfterSuite(func() {
|
||||
By("tearing down the test environment")
|
||||
err := testEnv.Stop()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 43 KiB |
Binary file not shown.
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 14 KiB |
Binary file not shown.
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 26 KiB |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue