1 Commits

Author SHA1 Message Date
be49afa5da Update dock.mau.dev/mautrix/whatsapp Docker tag to v0.2512.0
Some checks are pending
renovate/stability-days Updates have not met minimum release age requirement
lint-test-helm / lint-helm (pull_request) Successful in 15s
render-manifests-automerge / render-manifests-automerge (pull_request) Has been skipped
render-manifests-merge / render-manifests-merge (pull_request) Successful in 35s
2025-12-17 16:28:50 +00:00
581 changed files with 13256 additions and 11743 deletions

View File

@@ -14,21 +14,21 @@ on:
- 'hosts/**'
env:
BASE_BRANCH: "origin/${{ github.base_ref }}"
BASE_BRANCH: "origin/${{ gitea.base_ref }}"
jobs:
lint-docker-compose:
runs-on: ubuntu-js
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Check Branch Exists
id: check-branch-exists
if: github.event_name == 'pull_request'
uses: GuillaumeFalourd/branch-exists@009290475dc3d75b5d7ec680c0c5b614b0d9855d # v1.1
uses: GuillaumeFalourd/branch-exists@v1.1
with:
branch: "${{ github.base_ref }}"
@@ -36,22 +36,21 @@ jobs:
id: branch-exists
if: github.event_name == 'push' || steps.check-branch-exists.outputs.exists == 'true' && github.event_name == 'pull_request'
run: |
if [ "${{ github.event_name }}" == "push" ]; then
if [ ${{ github.event_name == 'push' }} ]; then
echo ">> Action is from a push event, will continue with linting"
else
echo ">> Branch ${{ github.base_ref }} exists, will continue with linting"
echo ">> Branch ${{ gitea.base_ref }} exists, will continue with linting"
fi
echo ""
echo "----"
echo "exists=true" >> $GITHUB_OUTPUT
echo "exists=true" >> $GITEA_OUTPUT
- name: Set Up Node.js
- name: Set up Node.js
if: steps.branch-exists.outputs.exists == 'true'
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
uses: actions/setup-node@v6
with:
node-version: '24'
@@ -59,48 +58,58 @@ jobs:
id: check-dir-changes
if: steps.branch-exists.outputs.exists == 'true'
run: |
CHANGED_COMPOSE=()
echo ">> Target branch for diff is: ${BASE_BRANCH}"
if [ "${{ github.event_name }}" == "pull_request" ]; then
DIFF_TARGET="${BASE_BRANCH}"
echo ""
echo ">> Checking for changes in a pull request ..."
GIT_DIFF=$(git diff --name-only "${BASE_BRANCH}" | xargs -I {} dirname {} | sort -u)
else
DIFF_TARGET="${{ github.event.before }}..HEAD"
echo ""
echo ">> Checking for changes from a push ..."
GIT_DIFF=$(git diff --name-only ${{ gitea.event.before }}..HEAD | xargs -I {} dirname {} | sort -u)
fi
CHANGED_COMPOSE=$(git diff --name-only "${DIFF_TARGET}" | grep -E "^hosts/[^/]+/[^/]+/" | cut -d/ -f1,2,3 | sort -u || true)
if [ -n "${GIT_DIFF}" ]; then
echo ""
echo ">> Changes detected:"
echo "$GIT_DIFF"
for path in $GIT_DIFF; do
if echo "$path" | grep -q -E "hosts/[^/]+/[^/]+"; then
echo ""
echo ">> Adding path: $path"
CHANGED_COMPOSE+=$(echo "$path")
CHANGED_COMPOSE+=$(echo " ")
fi
done
else
echo ""
echo ">> No changes detected"
fi
if [ -n "${CHANGED_COMPOSE}" ]; then
echo ""
echo ">> Compose to Lint:"
echo ""
echo "${CHANGED_COMPOSE}"
echo "$(echo "${CHANGED_COMPOSE}" | sort -u)"
CHANGED_COMPOSE_CSV=$(echo "$CHANGED_COMPOSE" | paste -sd ',' -)
echo ""
echo "----"
echo "changes-detected=true" >> $GITHUB_OUTPUT
echo "compose-dir-csv=${CHANGED_COMPOSE_CSV}" >> $GITHUB_OUTPUT
echo "compose-dir<<EOF" >> $GITHUB_OUTPUT
echo "${CHANGED_COMPOSE}" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
echo "changes-detected=true" >> $GITEA_OUTPUT
echo "compose-dir<<EOF" >> $GITEA_OUTPUT
echo "$(echo "${CHANGED_COMPOSE}" | sort -u)" >> $GITEA_OUTPUT
echo "EOF" >> $GITEA_OUTPUT
else
echo ""
echo ">> Did not find any docker compose files to lint"
echo ""
echo "----"
echo "changes-detected=false" >> $GITHUB_OUTPUT
echo "changes-detected=false" >> $GITEA_OUTPUT
fi
- name: Lint Docker Compose
@@ -108,27 +117,25 @@ jobs:
env:
CHANGED_COMPOSE: ${{ steps.check-dir-changes.outputs.compose-dir }}
run: |
echo ">> Running dclint on changed compose files ..."
for COMPOSE in $CHANGED_COMPOSE; do
echo ">> Linting ${COMPOSE} ..."
npx dclint ${COMPOSE}
echo ">> Running dclint on changed compose files:"
echo "$CHANGED_COMPOSE"
for compose in $CHANGED_COMPOSE; do
echo ">> Linting $compose ..."
npx dclint $compose
done
echo ""
echo "----"
- name: ntfy Failed
uses: niniyas/ntfy-action@96acac57fdc91d4c4f50b78486c1ed6f03f9f61c # master
uses: niniyas/ntfy-action@master
if: failure()
with:
url: '${{ secrets.NTFY_URL }}'
topic: '${{ secrets.NTFY_TOPIC }}'
title: 'Docker Compose Test Failure'
title: 'Test Failure - Infrastructure'
priority: 3
headers: '{"Authorization": "Bearer ${{ secrets.NTFY_CRED }}"}'
tags: action,failed
details: "Docker linting for compose dirs: ${{ steps.check-dir-changes.outputs.compose-dir-csv }}"
details: 'Docker linting on Pull Request for Infrastructure has failed!'
icon: 'https://cdn.jsdelivr.net/gh/selfhst/icons/png/gitea.png'
actions: '[{"action": "view", "label": "View Logs", "url": "${{ vars.USER_URL }}/${{ github.repository }}/actions/runs/${{ github.run_id }}", "clear": true}]'
actions: '[{"action": "view", "label": "Open Gitea", "url": "https://gitea.alexlebens.dev/alexlebens/infrastructure/actions?workflow=lint-test-docker-pull.yaml", "clear": true}]'
image: true

View File

@@ -15,113 +15,103 @@ on:
env:
CLUSTER: cl01tl
BASE_BRANCH: "origin/${{ github.base_ref }}"
# renovate: datasource=github-releases depName=yannh/kubeconform
KUBECONFORM_VERSION: "v0.6.7"
BASE_BRANCH: "origin/${{ gitea.base_ref }}"
jobs:
lint-helm:
runs-on: ubuntu-js
outputs:
chart-dir: ${{ steps.check-dir-changes.outputs.chart-dir }}
chart-dir-csv: ${{ steps.check-dir-changes.outputs.chart-dir-csv }}
changes-detected: ${{ steps.check-dir-changes.outputs.changes-detected }}
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Check Branch Exists
id: check-branch-exists
if: github.event_name == 'pull_request'
uses: GuillaumeFalourd/branch-exists@009290475dc3d75b5d7ec680c0c5b614b0d9855d # v1.1
uses: GuillaumeFalourd/branch-exists@v1.1
with:
branch: ${{ github.base_ref }}
branch: ${{ gitea.base_ref }}
- name: Report Branch Exists
id: branch-exists
if: github.event_name == 'push' || steps.check-branch-exists.outputs.exists == 'true' && github.event_name == 'pull_request'
run: |
if [ "${{ github.event_name }}" == "push" ]; then
if [ ${{ github.event_name == 'push' }} ]; then
echo ">> Action is from a push event, will continue with linting"
else
echo ">> Branch ${{ github.base_ref }} exists, will continue with linting"
echo ">> Branch ${{ gitea.base_ref }} exists, will continue with linting"
fi
echo ""
echo "----"
echo "exists=true" >> $GITHUB_OUTPUT
echo "exists=true" >> $GITEA_OUTPUT
- name: Set Up Helm
- name: Set up Helm
if: steps.branch-exists.outputs.exists == 'true'
uses: azure/setup-helm@dda3372f752e03dde6b3237bc9431cdc2f7a02a2 # v5
uses: azure/setup-helm@v4
with:
token: ${{ secrets.GITEA_TOKEN }}
# renovate: datasource=github-releases depName=helm/helm
version: v4.1.3
cache: true
- name: Cache Helm Dependencies
if: steps.branch-exists.outputs.exists == 'true'
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5
with:
path: |
~/.cache/helm
~/.config/helm
key: helm-cache-${{ runner.os }}-${{ hashFiles('infrastructure/clusters/cl01tl/helm/**/Chart.yaml', 'infrastructure/clusters/cl01tl/helm/**/Chart.lock') }}
restore-keys: |
helm-cache-${{ runner.os }}-
version: v3.19.2
- name: Check Directories for Changes
id: check-dir-changes
if: steps.branch-exists.outputs.exists == 'true'
run: |
CHANGED_CHARTS=()
echo ">> Target branch for diff is: ${BASE_BRANCH}"
if [ "${{ github.event_name }}" == "pull_request" ]; then
DIFF_TARGET="${BASE_BRANCH}"
echo ""
echo ">> Checking for changes in a pull request ..."
GIT_DIFF=$(git diff --name-only "${BASE_BRANCH}" | xargs -I {} dirname {} | sort -u)
else
DIFF_TARGET="${{ github.event.before }}..HEAD"
echo ""
echo ">> Checking for changes from a push ..."
GIT_DIFF=$(git diff --name-only ${{ gitea.event.before }}..HEAD | xargs -I {} dirname {} | sort -u)
fi
CHANGED_CHARTS=$(git diff --name-only "${DIFF_TARGET}" | grep -E "^clusters/${CLUSTER}/helm/" | awk -F '/' '{print $4}' | sort -u || true)
if [ -n "${GIT_DIFF}" ]; then
echo ""
echo ">> Changes detected:"
echo "$GIT_DIFF"
for path in $GIT_DIFF; do
if echo "$path" | grep -q -E "clusters/[^/]+/helm/[^/]+"; then
echo ""
echo ">> Adding path: $path"
CHANGED_CHARTS+=$(echo "$path" | awk -F '/' '{print $4}')
CHANGED_CHARTS+=$(echo "\n")
fi
done
else
echo ""
echo ">> No changes detected"
fi
if [ -n "${CHANGED_CHARTS}" ]; then
echo ""
echo ">> Chart to Lint:"
echo ""
echo "${CHANGED_CHARTS}"
echo "$(echo "${CHANGED_CHARTS}" | sort -u)"
CHANGED_CHARTS_CSV=$(echo "$CHANGED_CHARTS" | paste -sd ',' -)
echo ""
echo "----"
echo "changes-detected=true" >> $GITHUB_OUTPUT
echo "chart-dir-csv=${CHANGED_CHARTS_CSV}" >> $GITHUB_OUTPUT
echo "chart-dir<<EOF" >> $GITHUB_OUTPUT
echo "${CHANGED_CHARTS}" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
echo "changes-detected=true" >> $GITEA_OUTPUT
echo "chart-dir<<EOF" >> $GITEA_OUTPUT
echo "$(echo "${CHANGED_CHARTS}" | sort -u)" >> $GITEA_OUTPUT
echo "EOF" >> $GITEA_OUTPUT
else
echo ""
echo ">> Did not find any helm charts files to lint"
echo ""
echo "----"
echo "changes-detected=false" >> $GITHUB_OUTPUT
echo "changes-detected=false" >> $GITEA_OUTPUT
fi
- name: Add Repositories
@@ -130,238 +120,68 @@ jobs:
CHANGED_CHARTS: ${{ steps.check-dir-changes.outputs.chart-dir }}
run: |
echo ">> Adding repositories for chart dependencies ..."
echo ""
for DIR in ${CHANGED_CHARTS}; do
helm dependency list --max-col-width 120 clusters/${CLUSTER}/helm/${DIR} 2> /dev/null \
| tail -n +2 \
| awk 'NF > 0 { print $1, $3 }' \
| while read -r REPO_NAME REPO_URL; do
if [[ "${REPO_URL}" == oci://* ]]; then
echo ">> Ignoring OCI repo: ${REPO_URL}"
elif [[ -n "${REPO_NAME}" && -n "${REPO_URL}" ]]; then
helm repo add "${REPO_NAME}" "${REPO_URL}"
for dir in ${CHANGED_CHARTS}; do
helm dependency list --max-col-width 120 clusters/${CLUSTER}/helm/$dir 2> /dev/null \
| tail +2 | head -n -1 \
| awk '{ print "helm repo add " $1 " " $3 }' \
| while read cmd; do
if [[ "$cmd" == "*oci://*" ]]; then
echo ">> Ignoring OCI repo"
else
echo ">> Command: $cmd"
echo "$cmd" | sh;
fi
done || true
done
if helm repo list > /dev/null 2>&1; then
if helm repo list | tail +2 | read -r; then
echo ""
echo ">> Update repository cache ..."
helm repo update
fi
echo ""
echo "----"
- name: Lint Helm Chart
id: lint
if: steps.check-dir-changes.outputs.changes-detected == 'true'
env:
CHANGED_CHARTS: ${{ steps.check-dir-changes.outputs.chart-dir }}
run: |
EXIT_CODE=0
FAILED_CHARTS=""
echo ">> Running linting on changed charts ..."
for DIR in ${CHANGED_CHARTS}; do
CHART_PATH="clusters/${CLUSTER}/helm/${DIR}"
CHART_NAME=$(basename "${CHART_PATH}")
for dir in ${CHANGED_CHARTS}; do
chart_path=clusters/${CLUSTER}/helm/$dir
chart_name=$(basename "$chart_path")
if [ -f "${CHART_PATH}/Chart.yaml" ]; then
echo ""
echo ">> Building helm dependency for ${CHART_NAME} ..."
helm dependency build "${CHART_PATH}" --skip-refresh
if [ -f "$chart_path/Chart.yaml" ]; then
cd $chart_path
echo ""
echo ">> Linting helm chart ${CHART_NAME} ..."
echo ">> Building helm dependency ..."
helm dependency build --skip-refresh
if ! helm lint "${CHART_PATH}" --namespace "default"; then
EXIT_CODE=1
if [ -z "${FAILED_CHARTS}" ]; then
FAILED_CHARTS="${DIR}"
else
FAILED_CHARTS="${FAILED_CHARTS}, ${DIR}"
fi
fi
echo ""
echo ">> Linting helm ..."
helm lint --namespace "$chart_name"
else
echo ""
echo ">> Directory ${CHART_PATH} does not contain a Chart.yaml. Skipping ..."
echo ">> Directory $chart_path does not contain a Chart.yaml. Skipping ..."
echo ""
fi
done
echo ""
echo "----"
echo "failed-charts=${FAILED_CHARTS}" >> "$GITHUB_OUTPUT"
exit $EXIT_CODE
- name: ntfy Failed
uses: niniyas/ntfy-action@96acac57fdc91d4c4f50b78486c1ed6f03f9f61c # master
uses: niniyas/ntfy-action@master
if: failure()
with:
url: '${{ secrets.NTFY_URL }}'
topic: '${{ secrets.NTFY_TOPIC }}'
title: 'Helm Test Failure'
title: 'Test Failure - Infrastructure'
priority: 3
headers: '{"Authorization": "Bearer ${{ secrets.NTFY_CRED }}"}'
tags: action,failed
details: "Helm linting for cluster '${{ env.CLUSTER }}' failed on charts: ${{ steps.lint.outputs.failed-charts }}"
details: 'Helm linting on Pull Request for Infrastructure has failed!'
icon: 'https://cdn.jsdelivr.net/gh/selfhst/icons/png/gitea.png'
actions: '[{"action": "view", "label": "View Run", "url": "${{ vars.USER_URL }}/${{ github.repository }}/actions/runs/${{ github.run_id }}", "clear": true}]'
image: true
validate-kubeconform:
needs: lint-helm
runs-on: ubuntu-js
if: |
needs.lint-helm.result == 'success' &&
needs.lint-helm.outputs.changes-detected == 'true' &&
github.event_name == 'pull_request'
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
fetch-depth: 0
- name: Install Kubeconform
run: |
echo ">> Downloading Kubeconform ${{ env.KUBECONFORM_VERSION }} ..."
wget -q https://github.com/yannh/kubeconform/releases/download/${{ env.KUBECONFORM_VERSION }}/kubeconform-linux-amd64.tar.gz
echo ""
echo ">> Extracting Kubeconform ..."
tar xf kubeconform-linux-amd64.tar.gz
echo ""
echo ">> Installing Kubeconform ..."
sudo mv kubeconform /usr/local/bin/
echo ""
echo ">> Verifying installation ..."
kubeconform -v
echo ""
echo "----"
- name: Set Up Helm
uses: azure/setup-helm@dda3372f752e03dde6b3237bc9431cdc2f7a02a2 # v5
with:
token: ${{ secrets.GITEA_TOKEN }}
# renovate: datasource=github-releases depName=helm/helm
version: v4.1.3
cache: true
- name: Cache Helm Dependencies
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5
with:
path: |
~/.cache/helm
~/.config/helm
key: helm-cache-${{ runner.os }}-${{ hashFiles('infrastructure/clusters/cl01tl/helm/**/Chart.yaml', 'infrastructure/clusters/cl01tl/helm/**/Chart.lock') }}
restore-keys: |
helm-cache-${{ runner.os }}-
- name: Add Repositories
env:
CHANGED_CHARTS: ${{ needs.lint-helm.outputs.chart-dir }}
run: |
echo ">> Adding repositories for chart dependencies ..."
echo ""
for DIR in ${CHANGED_CHARTS}; do
helm dependency list --max-col-width 120 clusters/${CLUSTER}/helm/${DIR} 2> /dev/null \
| tail -n +2 \
| awk 'NF > 0 { print $1, $3 }' \
| while read -r REPO_NAME REPO_URL; do
if [[ "${REPO_URL}" == oci://* ]]; then
echo ">> Ignoring OCI repo: ${REPO_URL}"
elif [[ -n "${REPO_NAME}" && -n "${REPO_URL}" ]]; then
helm repo add "${REPO_NAME}" "${REPO_URL}"
fi
done || true
done
if helm repo list > /dev/null 2>&1; then
echo ""
echo ">> Update repository cache ..."
helm repo update
fi
echo ""
echo "----"
- name: Validate Rendered Templates
id: validate
env:
CHANGED_CHARTS: ${{ needs.lint-helm.outputs.chart-dir }}
run: |
SCHEMA_LOCATIONS="-schema-location default -schema-location https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/{{.Group}}/{{.ResourceKind}}_{{.ResourceAPIVersion}}.json"
EXIT_CODE=0
FAILED_CHARTS=""
for DIR in ${CHANGED_CHARTS}; do
CHART_PATH="clusters/${CLUSTER}/helm/${DIR}"
echo ""
echo ">> Validating: ${DIR}"
helm dependency build "${CHART_PATH}" --skip-refresh
if ! helm template "${DIR}" "${CHART_PATH}" --include-crds --namespace default --api-versions "gateway.networking.k8s.io/v1/HTTPRoute" | \
kubeconform \
${SCHEMA_LOCATIONS} \
-ignore-missing-schemas \
-strict \
-summary; then
EXIT_CODE=1
if [ -z "${FAILED_CHARTS}" ]; then
FAILED_CHARTS="${DIR}"
else
FAILED_CHARTS="${FAILED_CHARTS}, ${DIR}"
fi
fi
done
echo ""
echo "----"
echo "failed-charts=${FAILED_CHARTS}" >> "$GITHUB_OUTPUT"
exit $EXIT_CODE
- name: ntfy Failed
uses: niniyas/ntfy-action@96acac57fdc91d4c4f50b78486c1ed6f03f9f61c # master
if: failure()
with:
url: '${{ secrets.NTFY_URL }}'
topic: '${{ secrets.NTFY_TOPIC }}'
title: 'Kubeconform Test Failure'
priority: 3
headers: '{"Authorization": "Bearer ${{ secrets.NTFY_CRED }}"}'
tags: action,failed
details: "Kubeconform for cluster '${{ env.CLUSTER }}' failed on charts: ${{ steps.validate.outputs.failed-charts }}"
icon: 'https://cdn.jsdelivr.net/gh/selfhst/icons/png/gitea.png'
actions: '[{"action": "view", "label": "View Run", "url": "${{ vars.USER_URL }}/${{ github.repository }}/actions/runs/${{ github.run_id }}", "clear": true}]'
actions: '[{"action": "view", "label": "Open Gitea", "url": "https://gitea.alexlebens.dev/alexlebens/infrastructure/actions?workflow=lint-test-helm-pull.yaml", "clear": true}]'
image: true

View File

@@ -0,0 +1,433 @@
name: render-manifests-automerge
on:
pull_request:
branches:
- main
paths:
- 'clusters/cl01tl/helm/**'
types:
- closed
env:
CLUSTER: cl01tl
BASE_BRANCH: manifests
BRANCH_NAME_BASE: auto/update-manifests-automerge
MAIN_DIR: /workspace/alexlebens/infrastructure/infrastructure
MANIFEST_DIR: /workspace/alexlebens/infrastructure/infrastructure-manifests
jobs:
render-manifests-automerge:
runs-on: ubuntu-js
if: ${{ (github.event.pull_request.merged == true) && (contains(github.event.pull_request.labels.*.name, 'automerge')) }}
steps:
- name: Checkout Main
uses: actions/checkout@v6
with:
path: infrastructure
fetch-depth: 0
- name: Checkout Manifests
uses: actions/checkout@v6
with:
ref: manifests
path: infrastructure-manifests
- name: Set up Helm
uses: azure/setup-helm@v4
with:
token: ${{ secrets.GITEA_TOKEN }}
version: v3.17.2 # Pending https://github.com/helm/helm/pull/30743
- name: Prepare Manifest Branch
id: prepare-manifest-branch
run: |
cd ${MANIFEST_DIR}
BRANCH_NAME="${BRANCH_NAME_BASE}-$(date +%Y%m%d%H%M%S)"
echo ">> Configure git to use gitea-bot as user ..."
git config user.name "gitea-bot"
git config user.email "gitea-bot@alexlebens.net"
echo ">> Creating branch ..."
git checkout -b $BRANCH_NAME
echo "----"
echo "BRANCH_NAME=${BRANCH_NAME}" >> $GITEA_OUTPUT
- name: Check which Directories have Changes
id: check-dir-changes
run: |
cd ${MAIN_DIR}
RENDER_DIR=()
echo ">> Checking for changes from HEAD^..HEAD ..."
GIT_DIFF=$(git diff --name-only HEAD^..HEAD | xargs -I {} dirname {} | sort -u | grep -E "clusters/[^/]+/helm/[^/]+")
if [ -n "${GIT_DIFF}" ]; then
echo ">> Changes detected:"
echo "$GIT_DIFF"
for path in $GIT_DIFF; do
RENDER_DIR+=$(echo "$path" | awk -F '/' '{print $4}')
RENDER_DIR+=$(echo " ")
done
else
echo ">> No changes detected"
fi
if [ -n "${RENDER_DIR}" ]; then
echo ">> Directories to Render:"
echo "$(echo "${RENDER_DIR}" | sort -u)"
echo "----"
echo "changes-detected=true" >> $GITEA_OUTPUT
echo "render-dir<<EOF" >> $GITEA_OUTPUT
echo "$(echo "${RENDER_DIR}" | sort -u)" >> $GITEA_OUTPUT
echo "EOF" >> $GITEA_OUTPUT
else
echo "changes-detected=false" >> $GITEA_OUTPUT
fi
- name: Add Repositories
if: steps.check-dir-changes.outputs.changes-detected == 'true'
env:
RENDER_DIR: ${{ steps.check-dir-changes.outputs.render-dir }}
run: |
cd ${MAIN_DIR}
echo ">> Adding repositories for chart dependencies ..."
for dir in ${RENDER_DIR}; do
helm dependency list --max-col-width 120 ${MAIN_DIR}/clusters/${CLUSTER}/helm/$dir 2> /dev/null \
| tail +2 | head -n -1 \
| awk '{ print "helm repo add " $1 " " $3 }' \
| while read cmd; do
if [[ "$cmd" == "*oci://*" ]]; then
echo ">> Ignoring OCI repo"
else
echo "$cmd" | sh;
fi
done || true
done
if helm repo list | tail +2 | read -r; then
echo ">> Update repository cache ..."
helm repo update
fi
echo "----"
- name: Remove Changed Manifest Files
if: steps.check-dir-changes.outputs.changes-detected == 'true'
env:
RENDER_DIR: ${{ steps.check-dir-changes.outputs.render-dir }}
run: |
cd ${MANIFEST_DIR}
echo ">> Remove manfiest files and rebuild from source ..."
for dir in ${RENDER_DIR}; do
chart_path=${MANIFEST_DIR}/clusters/${CLUSTER}/manifests/$dir
echo "$chart_path"
rm -rf $chart_path/*
done
echo "----"
- name: Render Helm Manifests
id: render-manifests
if: steps.check-dir-changes.outputs.changes-detected == 'true'
env:
RENDER_DIR: ${{ steps.check-dir-changes.outputs.render-dir }}
run: |
cd ${MAIN_DIR}
echo ">> Rendering Manifests ..."
for dir in ${RENDER_DIR}; do
chart_path=${MAIN_DIR}/clusters/${CLUSTER}/helm/$dir
chart_name=$(basename "$chart_path")
echo ""
echo ""
echo ">> Rendering chart: $chart_name"
echo ">> Chart path $chart_path"
if [ -f "$chart_path/Chart.yaml" ]; then
OUTPUT_FOLDER="${MANIFEST_DIR}/clusters/${CLUSTER}/manifests/$chart_name/"
TEMPLATE=""
mkdir -p ${MANIFEST_DIR}/clusters/${CLUSTER}/manifests/$chart_name
cd $chart_path
echo ""
echo ">> Updating helm dependency ..."
helm dependency update --skip-refresh
echo ""
echo ">> Building helm dependency ..."
helm dependency build --skip-refresh
echo ""
echo ">> Linting helm ..."
helm lint --namespace "$chart_name"
echo ""
echo ">> Rendering templates ..."
case "$chart_name" in
"stack")
echo ""
echo ">> Special Rendering for stack into argocd namespace ..."
TEMPLATE=$(helm template $chart_name ./ --namespace argocd --include-crds --dry-run)
;;
"cilium" | "coredns" | "metrics-server" |"prometheus-operator-crds")
echo ""
echo ">> Special Rendering for $chart_name into kube-system namespace ..."
TEMPLATE=$(helm template $chart_name ./ --namespace kube-system --include-crds --dry-run)
;;
*)
echo ""
echo ">> Standard Rendering for $chart_name ..."
TEMPLATE=$(helm template "$chart_name" ./ --namespace "$chart_name" --include-crds --dry-run)
;;
esac
echo ""
echo ">> Formating rendered template ..."
echo "$TEMPLATE" | yq '... comments=""' | yq 'select(. != null)' | yq -s '"'"$OUTPUT_FOLDER"'" + .kind + "-" + .metadata.name + ".yaml"'
# Strip comments again to ensure formatting correctness
for file in "$OUTPUT_FOLDER"/*; do
yq -i '... comments=""' $file
done
echo ""
echo ">> Manifests for $chart_name rendered to $OUTPUT_FOLDER"
ls $OUTPUT_FOLDER
echo ""
else
echo ""
echo ">> Directory $chart_path does not contain a Chart.yaml. Skipping ..."
echo ""
fi
done
echo "----"
- name: Check for Changes
id: check-changes
if: steps.check-dir-changes.outputs.changes-detected == 'true'
run: |
cd ${MANIFEST_DIR}
GIT_CHANGES=$(git status --porcelain)
if [ -n "$GIT_CHANGES" ]; then
echo ">> Changes detected"
git status --porcelain
echo "changes-detected=true" >> $GITEA_OUTPUT
else
echo ">> No changes detected, skipping PR creation"
fi
echo "----"
- name: Commit and Push Changes
id: commit-push
if: steps.check-changes.outputs.changes-detected == 'true'
env:
BRANCH_NAME: ${{ steps.prepare-manifest-branch.outputs.BRANCH_NAME }}
run: |
cd ${MANIFEST_DIR}
echo ">> Commiting changes to ${BRANCH_NAME} ..."
git add .
git commit -m "chore: Update manifests after automerge"
REPO_URL="${{ secrets.REPO_URL }}/${{ gitea.repository }}"
echo ">> Pushing changes to $REPO_URL ..."
git push -u "https://oauth2:${{ secrets.BOT_TOKEN }}@$(echo $REPO_URL | sed -e 's|https://||')" ${BRANCH_NAME}
echo "----"
echo "push=true" >> $GITEA_OUTPUT
- name: Create Pull Request
id: create-pull-request
if: steps.commit-push.outputs.push == 'true'
env:
GITEA_TOKEN: ${{ secrets.BOT_TOKEN }}
GITEA_URL: ${{ secrets.REPO_URL }}
BRANCH_NAME: ${{ steps.prepare-manifest-branch.outputs.BRANCH_NAME }}
run: |
cd ${MANIFEST_DIR}
API_ENDPOINT="${GITEA_URL}/api/v1/repos/${{ gitea.repository }}/pulls"
PAYLOAD=$( jq -n \
--arg head "${BRANCH_NAME}" \
--arg base "${BASE_BRANCH}" \
--arg title "Automated Manifest Update - Automerge" \
--arg body "This PR contains newly rendered Kubernetes manifests automatically generated by the CI workflow. This is expected to be automerged." \
'{head: $head, base: $base, title: $title, body: $body}' )
echo ">> Creating PR from branch ${BRANCH_NAME} into ${BASE_BRANCH}"
echo ">> With Endpoint of:"
echo "$API_ENDPOINT"
echo ">> With Payload of:"
echo "$PAYLOAD"
HTTP_STATUS=$(
curl -X POST \
--silent \
--write-out '%{http_code}' \
--output response_body.json \
--dump-header response_headers.txt \
--data "$PAYLOAD" \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
"$API_ENDPOINT" 2> response_errors.txt
)
echo ">> HTTP Status Code: $HTTP_STATUS"
echo ">> Response Output ..."
echo "----"
cat response_body.json
echo "----"
cat response_headers.txt
echo "----"
cat response_errors.txt
echo "----"
if [ "$HTTP_STATUS" == "201" ]; then
echo ">> Pull Request created successfully!"
PR_URL=$(cat response_body.json | jq -r .html_url)
echo ">> Pull Request URL: $PR_URL"
echo "pull-request-url=${PR_URL}" >> $GITEA_OUTPUT
PR_NUMBER=$(cat response_body.json | jq -r .number)
echo ">> Pull Request Number: $PR_NUMBER"
echo "pull-request-number=${PR_NUMBER}" >> $GITEA_OUTPUT
echo "pull-request-operation=created" >> $GITEA_OUTPUT
elif [ "$HTTP_STATUS" == "422" ]; then
echo ">> Failed to create PR (HTTP 422: Unprocessable Entity), PR may already exist"
elif [ "$HTTP_STATUS" == "409" ]; then
echo ">> Failed to create PR (HTTP 409: Conflict), PR already exists"
else
echo ">> Failed to create PR, HTTP status code: $HTTP_STATUS"
exit 1
fi
echo "----"
- name: Merge Changes
id: merge-changes
if: steps.commit-push.outputs.push == 'true'
env:
GITEA_TOKEN: ${{ secrets.BOT_TOKEN }}
GITEA_URL: ${{ secrets.REPO_URL }}
BRANCH_NAME: ${{ steps.prepare-manifest-branch.outputs.BRANCH_NAME }}
PR_NUMBER: ${{ steps.create-pull-request.outputs.pull-request-number }}
run: |
cd ${MANIFEST_DIR}
API_ENDPOINT="${GITEA_URL}/api/v1/repos/${{ gitea.repository }}/pulls/${PR_NUMBER}/merge"
PAYLOAD=$( jq -n \
--arg Do "merge" \
'{Do: $Do}' )
echo ">> Merging PR with ID: ${PR_NUMBER}"
echo ">> With Endpoint of:"
echo "$API_ENDPOINT"
echo ">> With Payload of:"
echo "$PAYLOAD"
HTTP_STATUS=$(
curl -X POST \
--silent \
--write-out '%{http_code}' \
--output response_body.json \
--dump-header response_headers.txt \
--data "$PAYLOAD" \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
"$API_ENDPOINT" 2> response_errors.txt
)
echo ">> HTTP Status Code: $HTTP_STATUS"
echo ">> Response Output ..."
echo "----"
cat response_body.json
echo "----"
cat response_headers.txt
echo "----"
cat response_errors.txt
echo "----"
if [ "$HTTP_STATUS" == "200" ]; then
echo ">> Pull Request merged successfully!"
echo "pull-request-operation=merged" >> $GITEA_OUTPUT
else
echo ">> Failed to create PR, HTTP status code: $HTTP_STATUS"
echo "pull-request-operation=failed" >> $GITEA_OUTPUT
exit 1
fi
echo "----"
- name: Cleanup Branch
if: failure()
env:
BRANCH_NAME: ${{ steps.prepare-manifest-branch.outputs.BRANCH_NAME }}
run: |
cd ${MANIFEST_DIR}
echo ">> Removing branch: ${BRANCH_NAME}"
git push origin --delete ${BRANCH_NAME}
echo "----"
- name: ntfy Merged
uses: niniyas/ntfy-action@master
if: steps.merge-changes.outputs.pull-request-operation == 'merged'
with:
url: "${{ secrets.NTFY_URL }}"
topic: "${{ secrets.NTFY_TOPIC }}"
title: "Manifest Render PR Merged - Infrastructure"
priority: 3
headers: '{"Authorization": "Bearer ${{ secrets.NTFY_CRED }}"}'
tags: action,successfully,completed
details: "Automerge Manifest rendering for Infrastructure!"
icon: "https://cdn.jsdelivr.net/gh/selfhst/icons/png/gitea.png"
actions: '[{"action": "view", "label": "Open Gitea", "url": "${{ steps.create-pull-request.outputs.pull-request-url }}", "clear": true}]'
- name: ntfy Failed
uses: niniyas/ntfy-action@master
if: failure()
with:
url: "${{ secrets.NTFY_URL }}"
topic: "${{ secrets.NTFY_TOPIC }}"
title: "Manifest Render Failure - Infrastructure"
priority: 4
headers: '{"Authorization": "Bearer ${{ secrets.NTFY_CRED }}"}'
tags: action,failed
details: "Automerge Manifest rendering for Infrastructure has failed!"
icon: "https://cdn.jsdelivr.net/gh/selfhst/icons/png/gitea.png"
actions: '[{"action": "view", "label": "Open Gitea", "url": "https://gitea.alexlebens.dev/alexlebens/infrastructure/actions?workflow=render-manifests-automerge.yaml", "clear": true}]'
image: true

View File

@@ -0,0 +1,398 @@
name: render-manifests-dispatch
on:
workflow_dispatch:
env:
CLUSTER: cl01tl
BASE_BRANCH: manifests
BRANCH_NAME: auto/update-manifests
ASSIGNEE: alexlebens
MAIN_DIR: /workspace/alexlebens/infrastructure/infrastructure
MANIFEST_DIR: /workspace/alexlebens/infrastructure/infrastructure-manifests
jobs:
render-manifests-dispatch:
runs-on: ubuntu-js
steps:
- name: Checkout Main
uses: actions/checkout@v6
with:
path: infrastructure
fetch-depth: 0
- name: Checkout Manifests
uses: actions/checkout@v6
with:
ref: manifests
path: infrastructure-manifests
- name: Set up Helm
uses: azure/setup-helm@v4
with:
token: ${{ secrets.GITEA_TOKEN }}
version: v3.17.2 # Pending https://github.com/helm/helm/pull/30743
- name: Prepare Manifest Branch
run: |
cd ${MANIFEST_DIR}
echo ">> Configure git to use gitea-bot as user ..."
git config user.name "gitea-bot"
git config user.email "gitea-bot@alexlebens.net"
echo ">> Checking if PR branch exists ..."
if [[ $(git ls-remote --heads origin "${BRANCH_NAME}" | wc -l) -gt 0 ]]; then
echo ">> Branch '${BRANCH_NAME}' exists, pulling changes ..."
git fetch origin "${BRANCH_NAME}"
git checkout "${BRANCH_NAME}"
git pull --rebase
else
echo ">> Branch '${BRANCH_NAME}' does not exist, creating ..."
git checkout -b $BRANCH_NAME
fi
echo "----"
- name: Check which Directories have Changes
id: check-dir-changes
run: |
cd ${MAIN_DIR}
RENDER_DIR=()
echo ">> Triggered on dispatch, will check all paths ..."
RENDER_DIR+=$(ls clusters/cl01tl/helm/)
if [ -n "${RENDER_DIR}" ]; then
echo ">> Directories to Render:"
echo "$(echo "${RENDER_DIR}" | sort -u)"
echo "----"
echo "changes-detected=true" >> $GITEA_OUTPUT
echo "render-dir<<EOF" >> $GITEA_OUTPUT
echo "$(echo "${RENDER_DIR}" | sort -u)" >> $GITEA_OUTPUT
echo "EOF" >> $GITEA_OUTPUT
else
echo "changes-detected=false" >> $GITEA_OUTPUT
fi
- name: Add Repositories
if: steps.check-dir-changes.outputs.changes-detected == 'true'
env:
RENDER_DIR: ${{ steps.check-dir-changes.outputs.render-dir }}
run: |
cd ${MAIN_DIR}
echo ">> Adding repositories for chart dependencies ..."
for dir in ${RENDER_DIR}; do
helm dependency list --max-col-width 120 ${MAIN_DIR}/clusters/${CLUSTER}/helm/$dir 2> /dev/null \
| tail +2 | head -n -1 \
| awk '{ print "helm repo add " $1 " " $3 }' \
| while read cmd; do
if [[ "$cmd" == "*oci://*" ]]; then
echo ">> Ignoring OCI repo"
else
echo "$cmd" | sh;
fi
done || true
done
if helm repo list | tail +2 | read -r; then
echo ">> Update repository cache ..."
helm repo update
fi
echo "----"
- name: Remove Changed Manifest Files
if: steps.check-dir-changes.outputs.changes-detected == 'true'
env:
RENDER_DIR: ${{ steps.check-dir-changes.outputs.render-dir }}
run: |
cd ${MANIFEST_DIR}
echo ">> Remove manfiest files and rebuild from source ..."
for dir in ${RENDER_DIR}; do
chart_path=${MANIFEST_DIR}/clusters/${CLUSTER}/manifests/$dir
echo "$chart_path"
rm -rf $chart_path/*
done
echo "----"
- name: Render Helm Manifests
id: render-manifests
if: steps.check-dir-changes.outputs.changes-detected == 'true'
env:
RENDER_DIR: ${{ steps.check-dir-changes.outputs.render-dir }}
run: |
cd ${MAIN_DIR}
echo ">> Rendering Manifests ..."
for dir in ${RENDER_DIR}; do
chart_path=${MAIN_DIR}/clusters/${CLUSTER}/helm/$dir
chart_name=$(basename "$chart_path")
echo ""
echo ""
echo ">> Rendering chart: $chart_name"
echo ">> Chart path $chart_path"
if [ -f "$chart_path/Chart.yaml" ]; then
OUTPUT_FOLDER="${MANIFEST_DIR}/clusters/${CLUSTER}/manifests/$chart_name/"
TEMPLATE=""
mkdir -p ${MANIFEST_DIR}/clusters/${CLUSTER}/manifests/$chart_name
cd $chart_path
echo ""
echo ">> Updating helm dependency ..."
helm dependency update --skip-refresh
echo ""
echo ">> Building helm dependency ..."
helm dependency build --skip-refresh
echo ""
echo ">> Linting helm ..."
helm lint --namespace "$chart_name"
echo ""
echo ">> Rendering templates ..."
case "$chart_name" in
"stack")
echo ""
echo ">> Special Rendering for stack into argocd namespace ..."
TEMPLATE=$(helm template $chart_name ./ --namespace argocd --include-crds --dry-run)
;;
"cilium" | "coredns" | "metrics-server" |"prometheus-operator-crds")
echo ""
echo ">> Special Rendering for $chart_name into kube-system namespace ..."
TEMPLATE=$(helm template $chart_name ./ --namespace kube-system --include-crds --dry-run)
;;
*)
echo ""
echo ">> Standard Rendering for $chart_name ..."
TEMPLATE=$(helm template "$chart_name" ./ --namespace "$chart_name" --include-crds --dry-run)
;;
esac
echo ""
echo ">> Formating rendered template ..."
echo "$TEMPLATE" | yq '... comments=""' | yq 'select(. != null)' | yq -s '"'"$OUTPUT_FOLDER"'" + .kind + "-" + .metadata.name + ".yaml"'
# Strip comments again to ensure formatting correctness
for file in "$OUTPUT_FOLDER"/*; do
yq -i '... comments=""' $file
done
echo ""
echo ">> Manifests for $chart_name rendered to $OUTPUT_FOLDER"
ls $OUTPUT_FOLDER
echo ""
else
echo ""
echo ">> Directory $chart_path does not contain a Chart.yaml. Skipping ..."
echo ""
fi
done
echo "----"
- name: Check for Changes
id: check-changes
if: steps.check-dir-changes.outputs.changes-detected == 'true'
run: |
cd ${MANIFEST_DIR}
GIT_CHANGES=$(git status --porcelain)
if [ -n "$GIT_CHANGES" ]; then
echo ">> Changes detected"
git status --porcelain
echo "changes-detected=true" >> $GITEA_OUTPUT
else
echo ">> No changes detected, skipping PR creation"
fi
echo "----"
- name: Commit and Push Changes
id: commit-push
if: steps.check-changes.outputs.changes-detected == 'true'
run: |
cd ${MANIFEST_DIR}
echo ">> Commiting changes to ${BRANCH_NAME} ..."
git add .
git commit -m "chore: Update manifests after change"
REPO_URL="${{ secrets.REPO_URL }}/${{ gitea.repository }}"
echo ">> Pushing changes to $REPO_URL ..."
git push -u "https://oauth2:${{ secrets.BOT_TOKEN }}@$(echo $REPO_URL | sed -e 's|https://||')" ${BRANCH_NAME}
echo "----"
echo "HEAD_BRANCH=${BRANCH_NAME}" >> $GITEA_OUTPUT
echo "push=true" >> $GITEA_OUTPUT
- name: Check for Pull Request
id: check-for-pull-requst
if: steps.commit-push.outputs.push == 'true'
env:
GITEA_TOKEN: ${{ secrets.BOT_TOKEN }}
GITEA_URL: ${{ secrets.REPO_URL }}
HEAD_BRANCH: ${{ steps.commit-push.outputs.HEAD_BRANCH }}
run: |
cd ${MANIFEST_DIR}
API_ENDPOINT="${GITEA_URL}/api/v1/repos/${{ gitea.repository }}/pulls?base_branch=${BASE_BRANCH}&state=open&page=1"
echo ">> Checking if PR from branch ${HEAD_BRANCH} into ${BASE_BRANCH}"
echo ">> With Endpoint of:"
echo "$API_ENDPOINT"
HTTP_STATUS=$(
curl -X GET \
--silent \
--write-out '%{http_code}' \
--output response_body.json \
--dump-header response_headers.txt \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
"$API_ENDPOINT" 2> response_errors.txt
)
echo ">> HTTP Status Code: $HTTP_STATUS"
echo ">> Response Output ..."
echo "----"
cat response_body.json
echo "----"
cat response_headers.txt
echo "----"
cat response_errors.txt
echo "----"
if [ "$HTTP_STATUS" == "200" ] && [ "$(cat response_body.json | jq -r .[0].state)" == "open" ]; then
echo ">> Pull Request has been found open, will update"
PR_INDEX=$(cat response_body.json | jq -r .[0].number)
echo "pull-request-exists=${PR_INDEX}" >> $GITEA_OUTPUT
echo "pull-request-index=true" >> $GITEA_OUTPUT
elif [ "$HTTP_STATUS" == "200" ] && [ "$(cat response_body.json | jq -r .[0].state)" == "closed" ]; then
echo ">> Pull Request found, but was closed"
echo "pull-request-exists=false" >> $GITEA_OUTPUT
else
echo ">> Pull Request not found"
echo "pull-request-exists=false" >> $GITEA_OUTPUT
fi
echo "----"
- name: Create Pull Request
id: create-pull-request
if: steps.commit-push.outputs.push == 'true' && steps.check-for-pull-requst.outputs.pull-request-exists == 'false'
env:
GITEA_TOKEN: ${{ secrets.BOT_TOKEN }}
GITEA_URL: ${{ secrets.REPO_URL }}
HEAD_BRANCH: ${{ steps.commit-push.outputs.HEAD_BRANCH }}
run: |
cd ${MANIFEST_DIR}
API_ENDPOINT="${GITEA_URL}/api/v1/repos/${{ gitea.repository }}/pulls"
PAYLOAD=$( jq -n \
--arg head "${HEAD_BRANCH}" \
--arg base "${BASE_BRANCH}" \
--arg assignee "${ASSIGNEE}" \
--arg title "Automated Manifest Update" \
--arg body "This PR contains newly rendered Kubernetes manifests automatically generated by the CI workflow." \
'{head: $head, base: $base, assignee: $assignee, title: $title, body: $body}' )
echo ">> Creating PR from branch ${HEAD_BRANCH} into ${BASE_BRANCH}"
echo ">> With Endpoint of:"
echo "$API_ENDPOINT"
echo ">> With Payload of:"
echo "$PAYLOAD"
HTTP_STATUS=$(
curl -X POST \
--silent \
--write-out '%{http_code}' \
--output response_body.json \
--dump-header response_headers.txt \
--data "$PAYLOAD" \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
"$API_ENDPOINT" 2> response_errors.txt
)
echo ">> HTTP Status Code: $HTTP_STATUS"
echo ">> Response Output ..."
echo "----"
cat response_body.json
echo "----"
cat response_headers.txt
echo "----"
cat response_errors.txt
echo "----"
if [ "$HTTP_STATUS" == "201" ]; then
echo ">> Pull Request created successfully!"
PR_URL=$(cat response_body.json | jq -r .html_url)
echo "pull-request-url=${PR_URL}" >> $GITEA_OUTPUT
PR_ID=$(cat response_body.json | jq -r .id)
echo "pull-request-id=${PR_ID}" >> $GITEA_OUTPUT
echo "pull-request-operation=created" >> $GITEA_OUTPUT
elif [ "$HTTP_STATUS" == "422" ]; then
echo ">> Failed to create PR (HTTP 422: Unprocessable Entity), PR may already exist"
elif [ "$HTTP_STATUS" == "409" ]; then
echo ">> Failed to create PR (HTTP 409: Conflict), PR already exists"
else
echo ">> Failed to create PR, HTTP status code: $HTTP_STATUS"
exit 1
fi
echo "----"
- name: ntfy Created
uses: niniyas/ntfy-action@master
if: steps.create-pull-request.outputs.pull-request-operation == 'created'
with:
url: "${{ secrets.NTFY_URL }}"
topic: "${{ secrets.NTFY_TOPIC }}"
title: "Manifest Render PR Created - Infrastructure"
priority: 3
headers: '{"Authorization": "Bearer ${{ secrets.NTFY_CRED }}"}'
tags: action,successfully,completed
details: "Manifest rendering for Infrastructure has created a new Pull Request with ID: ${{ steps.create-pull-request.outputs.pull-request-id }}!"
icon: "https://cdn.jsdelivr.net/gh/selfhst/icons/png/gitea.png"
actions: '[{"action": "view", "label": "Open Gitea", "url": "${{ steps.create-pull-request.outputs.pull-request-url }}", "clear": true}]'
- name: ntfy Failed
uses: niniyas/ntfy-action@master
if: failure()
with:
url: "${{ secrets.NTFY_URL }}"
topic: "${{ secrets.NTFY_TOPIC }}"
title: "Manifest Render Failure - Infrastructure"
priority: 4
headers: '{"Authorization": "Bearer ${{ secrets.NTFY_CRED }}"}'
tags: action,failed
details: "Manifest rendering for Infrastructure has failed!"
icon: "https://cdn.jsdelivr.net/gh/selfhst/icons/png/gitea.png"
actions: '[{"action": "view", "label": "Open Gitea", "url": "https://gitea.alexlebens.dev/alexlebens/infrastructure/actions?workflow=render-manifests.yaml", "clear": true}]'
image: true

View File

@@ -0,0 +1,418 @@
name: render-manifests-merge
on:
pull_request:
branches:
- main
paths:
- 'clusters/cl01tl/helm/**'
types:
- closed
env:
CLUSTER: cl01tl
BASE_BRANCH: manifests
BRANCH_NAME: auto/update-manifests
ASSIGNEE: alexlebens
MAIN_DIR: /workspace/alexlebens/infrastructure/infrastructure
MANIFEST_DIR: /workspace/alexlebens/infrastructure/infrastructure-manifests
jobs:
render-manifests-merge:
runs-on: ubuntu-js
if: ${{ (github.event.pull_request.merged == true) && !(contains(github.event.pull_request.labels.*.name, 'automerge')) }}
steps:
- name: Checkout Main
uses: actions/checkout@v6
with:
path: infrastructure
fetch-depth: 0
- name: Checkout Manifests
uses: actions/checkout@v6
with:
ref: manifests
path: infrastructure-manifests
- name: Set up Helm
uses: azure/setup-helm@v4
with:
token: ${{ secrets.GITEA_TOKEN }}
version: v3.17.2 # Pending https://github.com/helm/helm/pull/30743
- name: Prepare Manifest Branch
run: |
cd ${MANIFEST_DIR}
echo ">> Configure git to use gitea-bot as user ..."
git config user.name "gitea-bot"
git config user.email "gitea-bot@alexlebens.net"
echo ">> Checking if PR branch exists ..."
if [[ $(git ls-remote --heads origin "${BRANCH_NAME}" | wc -l) -gt 0 ]]; then
echo ">> Branch '${BRANCH_NAME}' exists, pulling changes ..."
git fetch origin "${BRANCH_NAME}"
git checkout "${BRANCH_NAME}"
git pull --rebase
else
echo ">> Branch '${BRANCH_NAME}' does not exist, creating ..."
git checkout -b $BRANCH_NAME
fi
echo "----"
- name: Check which Directories have Changes
id: check-dir-changes
run: |
cd ${MAIN_DIR}
RENDER_DIR=()
echo ">> Checking for changes from HEAD^..HEAD ..."
GIT_DIFF=$(git diff --name-only HEAD^..HEAD | xargs -I {} dirname {} | sort -u | grep -E "clusters/[^/]+/helm/[^/]+")
if [ -n "${GIT_DIFF}" ]; then
echo ">> Changes detected:"
echo "$GIT_DIFF"
for path in $GIT_DIFF; do
RENDER_DIR+=$(echo "$path" | awk -F '/' '{print $4}')
RENDER_DIR+=$(echo " ")
done
else
echo ">> No changes detected"
fi
if [ -n "${RENDER_DIR}" ]; then
echo ">> Directories to Render:"
echo "$(echo "${RENDER_DIR}" | sort -u)"
echo "----"
echo "changes-detected=true" >> $GITEA_OUTPUT
echo "render-dir<<EOF" >> $GITEA_OUTPUT
echo "$(echo "${RENDER_DIR}" | sort -u)" >> $GITEA_OUTPUT
echo "EOF" >> $GITEA_OUTPUT
else
echo "changes-detected=false" >> $GITEA_OUTPUT
fi
- name: Add Repositories
if: steps.check-dir-changes.outputs.changes-detected == 'true'
env:
RENDER_DIR: ${{ steps.check-dir-changes.outputs.render-dir }}
run: |
cd ${MAIN_DIR}
echo ">> Adding repositories for chart dependencies ..."
for dir in ${RENDER_DIR}; do
helm dependency list --max-col-width 120 ${MAIN_DIR}/clusters/${CLUSTER}/helm/$dir 2> /dev/null \
| tail +2 | head -n -1 \
| awk '{ print "helm repo add " $1 " " $3 }' \
| while read cmd; do
if [[ "$cmd" == "*oci://*" ]]; then
echo ">> Ignoring OCI repo"
else
echo "$cmd" | sh;
fi
done || true
done
if helm repo list | tail +2 | read -r; then
echo ">> Update repository cache ..."
helm repo update
fi
echo "----"
- name: Remove Changed Manifest Files
if: steps.check-dir-changes.outputs.changes-detected == 'true'
env:
RENDER_DIR: ${{ steps.check-dir-changes.outputs.render-dir }}
run: |
cd ${MANIFEST_DIR}
echo ">> Remove manfiest files and rebuild from source ..."
for dir in ${RENDER_DIR}; do
chart_path=${MANIFEST_DIR}/clusters/${CLUSTER}/manifests/$dir
echo "$chart_path"
rm -rf $chart_path/*
done
echo "----"
- name: Render Helm Manifests
id: render-manifests
if: steps.check-dir-changes.outputs.changes-detected == 'true'
env:
RENDER_DIR: ${{ steps.check-dir-changes.outputs.render-dir }}
run: |
cd ${MAIN_DIR}
echo ">> Rendering Manifests ..."
for dir in ${RENDER_DIR}; do
chart_path=${MAIN_DIR}/clusters/${CLUSTER}/helm/$dir
chart_name=$(basename "$chart_path")
echo ""
echo ""
echo ">> Rendering chart: $chart_name"
echo ">> Chart path $chart_path"
if [ -f "$chart_path/Chart.yaml" ]; then
OUTPUT_FOLDER="${MANIFEST_DIR}/clusters/${CLUSTER}/manifests/$chart_name/"
TEMPLATE=""
mkdir -p ${MANIFEST_DIR}/clusters/${CLUSTER}/manifests/$chart_name
cd $chart_path
echo ""
echo ">> Updating helm dependency ..."
helm dependency update --skip-refresh
echo ""
echo ">> Building helm dependency ..."
helm dependency build --skip-refresh
echo ""
echo ">> Linting helm ..."
helm lint --namespace "$chart_name"
echo ""
echo ">> Rendering templates ..."
case "$chart_name" in
"stack")
echo ""
echo ">> Special Rendering for stack into argocd namespace ..."
TEMPLATE=$(helm template $chart_name ./ --namespace argocd --include-crds --dry-run)
;;
"cilium" | "coredns" | "metrics-server" |"prometheus-operator-crds")
echo ""
echo ">> Special Rendering for $chart_name into kube-system namespace ..."
TEMPLATE=$(helm template $chart_name ./ --namespace kube-system --include-crds --dry-run)
;;
*)
echo ""
echo ">> Standard Rendering for $chart_name ..."
TEMPLATE=$(helm template "$chart_name" ./ --namespace "$chart_name" --include-crds --dry-run)
;;
esac
echo ""
echo ">> Formating rendered template ..."
echo "$TEMPLATE" | yq '... comments=""' | yq 'select(. != null)' | yq -s '"'"$OUTPUT_FOLDER"'" + .kind + "-" + .metadata.name + ".yaml"'
# Strip comments again to ensure formatting correctness
for file in "$OUTPUT_FOLDER"/*; do
yq -i '... comments=""' $file
done
echo ""
echo ">> Manifests for $chart_name rendered to $OUTPUT_FOLDER"
ls $OUTPUT_FOLDER
echo ""
else
echo ""
echo ">> Directory $chart_path does not contain a Chart.yaml. Skipping ..."
echo ""
fi
done
echo "----"
- name: Check for Changes
id: check-changes
if: steps.check-dir-changes.outputs.changes-detected == 'true'
run: |
cd ${MANIFEST_DIR}
GIT_CHANGES=$(git status --porcelain)
if [ -n "$GIT_CHANGES" ]; then
echo ">> Changes detected"
git status --porcelain
echo "changes-detected=true" >> $GITEA_OUTPUT
else
echo ">> No changes detected, skipping PR creation"
fi
echo "----"
- name: Commit and Push Changes
id: commit-push
if: steps.check-changes.outputs.changes-detected == 'true'
run: |
cd ${MANIFEST_DIR}
echo ">> Commiting changes to ${BRANCH_NAME} ..."
git add .
git commit -m "chore: Update manifests after change"
REPO_URL="${{ secrets.REPO_URL }}/${{ gitea.repository }}"
echo ">> Pushing changes to $REPO_URL ..."
git push -u "https://oauth2:${{ secrets.BOT_TOKEN }}@$(echo $REPO_URL | sed -e 's|https://||')" ${BRANCH_NAME}
echo "----"
echo "HEAD_BRANCH=${BRANCH_NAME}" >> $GITEA_OUTPUT
echo "push=true" >> $GITEA_OUTPUT
- name: Check for Pull Request
id: check-for-pull-requst
if: steps.commit-push.outputs.push == 'true'
env:
GITEA_TOKEN: ${{ secrets.BOT_TOKEN }}
GITEA_URL: ${{ secrets.REPO_URL }}
HEAD_BRANCH: ${{ steps.commit-push.outputs.HEAD_BRANCH }}
run: |
cd ${MANIFEST_DIR}
API_ENDPOINT="${GITEA_URL}/api/v1/repos/${{ gitea.repository }}/pulls?base_branch=${BASE_BRANCH}&state=open&page=1"
echo ">> Checking if PR from branch ${HEAD_BRANCH} into ${BASE_BRANCH}"
echo ">> With Endpoint of:"
echo "$API_ENDPOINT"
HTTP_STATUS=$(
curl -X GET \
--silent \
--write-out '%{http_code}' \
--output response_body.json \
--dump-header response_headers.txt \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
"$API_ENDPOINT" 2> response_errors.txt
)
echo ">> HTTP Status Code: $HTTP_STATUS"
echo ">> Response Output ..."
echo "----"
cat response_body.json
echo "----"
cat response_headers.txt
echo "----"
cat response_errors.txt
echo "----"
if [ "$HTTP_STATUS" == "200" ] && [ "$(cat response_body.json | jq -r .[0].state)" == "open" ]; then
echo ">> Pull Request has been found open, will update"
PR_INDEX=$(cat response_body.json | jq -r .[0].number)
echo "pull-request-exists=${PR_INDEX}" >> $GITEA_OUTPUT
echo "pull-request-index=true" >> $GITEA_OUTPUT
elif [ "$HTTP_STATUS" == "200" ] && [ "$(cat response_body.json | jq -r .[0].state)" == "closed" ]; then
echo ">> Pull Request found, but was closed"
echo "pull-request-exists=false" >> $GITEA_OUTPUT
else
echo ">> Pull Request not found"
echo "pull-request-exists=false" >> $GITEA_OUTPUT
fi
echo "----"
- name: Create Pull Request
id: create-pull-request
if: steps.commit-push.outputs.push == 'true' && steps.check-for-pull-requst.outputs.pull-request-exists == 'false'
env:
GITEA_TOKEN: ${{ secrets.BOT_TOKEN }}
GITEA_URL: ${{ secrets.REPO_URL }}
HEAD_BRANCH: ${{ steps.commit-push.outputs.HEAD_BRANCH }}
run: |
cd ${MANIFEST_DIR}
API_ENDPOINT="${GITEA_URL}/api/v1/repos/${{ gitea.repository }}/pulls"
PAYLOAD=$( jq -n \
--arg head "${HEAD_BRANCH}" \
--arg base "${BASE_BRANCH}" \
--arg assignee "${ASSIGNEE}" \
--arg title "Automated Manifest Update" \
--arg body "This PR contains newly rendered Kubernetes manifests automatically generated by the CI workflow." \
'{head: $head, base: $base, assignee: $assignee, title: $title, body: $body}' )
echo ">> Creating PR from branch ${HEAD_BRANCH} into ${BASE_BRANCH}"
echo ">> With Endpoint of:"
echo "$API_ENDPOINT"
echo ">> With Payload of:"
echo "$PAYLOAD"
HTTP_STATUS=$(
curl -X POST \
--silent \
--write-out '%{http_code}' \
--output response_body.json \
--dump-header response_headers.txt \
--data "$PAYLOAD" \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
"$API_ENDPOINT" 2> response_errors.txt
)
echo ">> HTTP Status Code: $HTTP_STATUS"
echo ">> Response Output ..."
echo "----"
cat response_body.json
echo "----"
cat response_headers.txt
echo "----"
cat response_errors.txt
echo "----"
if [ "$HTTP_STATUS" == "201" ]; then
echo ">> Pull Request created successfully!"
PR_URL=$(cat response_body.json | jq -r .html_url)
echo "pull-request-url=${PR_URL}" >> $GITEA_OUTPUT
PR_ID=$(cat response_body.json | jq -r .id)
echo "pull-request-id=${PR_ID}" >> $GITEA_OUTPUT
echo "pull-request-operation=created" >> $GITEA_OUTPUT
elif [ "$HTTP_STATUS" == "422" ]; then
echo ">> Failed to create PR (HTTP 422: Unprocessable Entity), PR may already exist"
elif [ "$HTTP_STATUS" == "409" ]; then
echo ">> Failed to create PR (HTTP 409: Conflict), PR already exists"
else
echo ">> Failed to create PR, HTTP status code: $HTTP_STATUS"
exit 1
fi
echo "----"
- name: ntfy Created
uses: niniyas/ntfy-action@master
if: steps.create-pull-request.outputs.pull-request-operation == 'created'
with:
url: "${{ secrets.NTFY_URL }}"
topic: "${{ secrets.NTFY_TOPIC }}"
title: "Manifest Render PR Created - Infrastructure"
priority: 3
headers: '{"Authorization": "Bearer ${{ secrets.NTFY_CRED }}"}'
tags: action,successfully,completed
details: "Manifest rendering for Infrastructure has created a new Pull Request with ID: ${{ steps.create-pull-request.outputs.pull-request-id }}!"
icon: "https://cdn.jsdelivr.net/gh/selfhst/icons/png/gitea.png"
actions: '[{"action": "view", "label": "Open Gitea", "url": "${{ steps.create-pull-request.outputs.pull-request-url }}", "clear": true}]'
- name: ntfy Failed
uses: niniyas/ntfy-action@master
if: failure()
with:
url: "${{ secrets.NTFY_URL }}"
topic: "${{ secrets.NTFY_TOPIC }}"
title: "Manifest Render Failure - Infrastructure"
priority: 4
headers: '{"Authorization": "Bearer ${{ secrets.NTFY_CRED }}"}'
tags: action,failed
details: "Manifest rendering for Infrastructure has failed!"
icon: "https://cdn.jsdelivr.net/gh/selfhst/icons/png/gitea.png"
actions: '[{"action": "view", "label": "Open Gitea", "url": "https://gitea.alexlebens.dev/alexlebens/infrastructure/actions?workflow=render-manifests.yaml", "clear": true}]'
image: true

View File

@@ -0,0 +1,416 @@
name: render-manifests-push
on:
push:
branches:
- main
paths:
- 'clusters/cl01tl/helm/**'
env:
CLUSTER: cl01tl
BASE_BRANCH: manifests
BRANCH_NAME: auto/update-manifests
ASSIGNEE: alexlebens
MAIN_DIR: /workspace/alexlebens/infrastructure/infrastructure
MANIFEST_DIR: /workspace/alexlebens/infrastructure/infrastructure-manifests
jobs:
render-manifests-push:
runs-on: ubuntu-js
if: gitea.event.commits[0].author.username != 'renovate-bot'
steps:
- name: Checkout Main
uses: actions/checkout@v6
with:
path: infrastructure
fetch-depth: 0
- name: Checkout Manifests
uses: actions/checkout@v6
with:
ref: manifests
path: infrastructure-manifests
- name: Set up Helm
uses: azure/setup-helm@v4
with:
token: ${{ secrets.GITEA_TOKEN }}
version: v3.17.2 # Pending https://github.com/helm/helm/pull/30743
- name: Prepare Manifest Branch
run: |
cd ${MANIFEST_DIR}
echo ">> Configure git to use gitea-bot as user ..."
git config user.name "gitea-bot"
git config user.email "gitea-bot@alexlebens.net"
echo ">> Checking if PR branch exists ..."
if [[ $(git ls-remote --heads origin "${BRANCH_NAME}" | wc -l) -gt 0 ]]; then
echo ">> Branch '${BRANCH_NAME}' exists, pulling changes ..."
git fetch origin "${BRANCH_NAME}"
git checkout "${BRANCH_NAME}"
git pull --rebase
else
echo ">> Branch '${BRANCH_NAME}' does not exist, creating ..."
git checkout -b $BRANCH_NAME
fi
echo "----"
- name: Check which Directories have Changes
id: check-dir-changes
run: |
cd ${MAIN_DIR}
RENDER_DIR=()
echo ">> Checking for changes ..."
GIT_DIFF=$(git diff --name-only ${{ gitea.event.before }}..HEAD | xargs -I {} dirname {} | sort -u | grep -E "clusters/[^/]+/helm/[^/]+")
if [ -n "${GIT_DIFF}" ]; then
echo ">> Changes detected:"
echo "$GIT_DIFF"
for path in $GIT_DIFF; do
RENDER_DIR+=$(echo "$path" | awk -F '/' '{print $4}')
RENDER_DIR+=$(echo " ")
done
else
echo ">> No changes detected"
fi
if [ -n "${RENDER_DIR}" ]; then
echo ">> Directories to Render:"
echo "$(echo "${RENDER_DIR}" | sort -u)"
echo "----"
echo "changes-detected=true" >> $GITEA_OUTPUT
echo "render-dir<<EOF" >> $GITEA_OUTPUT
echo "$(echo "${RENDER_DIR}" | sort -u)" >> $GITEA_OUTPUT
echo "EOF" >> $GITEA_OUTPUT
else
echo "changes-detected=false" >> $GITEA_OUTPUT
fi
- name: Add Repositories
if: steps.check-dir-changes.outputs.changes-detected == 'true'
env:
RENDER_DIR: ${{ steps.check-dir-changes.outputs.render-dir }}
run: |
cd ${MAIN_DIR}
echo ">> Adding repositories for chart dependencies ..."
for dir in ${RENDER_DIR}; do
helm dependency list --max-col-width 120 ${MAIN_DIR}/clusters/${CLUSTER}/helm/$dir 2> /dev/null \
| tail +2 | head -n -1 \
| awk '{ print "helm repo add " $1 " " $3 }' \
| while read cmd; do
if [[ "$cmd" == "*oci://*" ]]; then
echo ">> Ignoring OCI repo"
else
echo "$cmd" | sh;
fi
done || true
done
if helm repo list | tail +2 | read -r; then
echo ">> Update repository cache ..."
helm repo update
fi
echo "----"
- name: Remove Changed Manifest Files
if: steps.check-dir-changes.outputs.changes-detected == 'true'
env:
RENDER_DIR: ${{ steps.check-dir-changes.outputs.render-dir }}
run: |
cd ${MANIFEST_DIR}
echo ">> Remove manfiest files and rebuild from source ..."
for dir in ${RENDER_DIR}; do
chart_path=${MANIFEST_DIR}/clusters/${CLUSTER}/manifests/$dir
echo "$chart_path"
rm -rf $chart_path/*
done
echo "----"
- name: Render Helm Manifests
id: render-manifests
if: steps.check-dir-changes.outputs.changes-detected == 'true'
env:
RENDER_DIR: ${{ steps.check-dir-changes.outputs.render-dir }}
run: |
cd ${MAIN_DIR}
echo ">> Rendering Manifests ..."
for dir in ${RENDER_DIR}; do
chart_path=${MAIN_DIR}/clusters/${CLUSTER}/helm/$dir
chart_name=$(basename "$chart_path")
echo ""
echo ""
echo ">> Rendering chart: $chart_name"
echo ">> Chart path $chart_path"
if [ -f "$chart_path/Chart.yaml" ]; then
OUTPUT_FOLDER="${MANIFEST_DIR}/clusters/${CLUSTER}/manifests/$chart_name/"
TEMPLATE=""
mkdir -p ${MANIFEST_DIR}/clusters/${CLUSTER}/manifests/$chart_name
cd $chart_path
echo ""
echo ">> Updating helm dependency ..."
helm dependency update --skip-refresh
echo ""
echo ">> Building helm dependency ..."
helm dependency build --skip-refresh
echo ""
echo ">> Linting helm ..."
helm lint --namespace "$chart_name"
echo ""
echo ">> Rendering templates ..."
case "$chart_name" in
"stack")
echo ""
echo ">> Special Rendering for stack into argocd namespace ..."
TEMPLATE=$(helm template $chart_name ./ --namespace argocd --include-crds --dry-run)
;;
"cilium" | "coredns" | "metrics-server" |"prometheus-operator-crds")
echo ""
echo ">> Special Rendering for $chart_name into kube-system namespace ..."
TEMPLATE=$(helm template $chart_name ./ --namespace kube-system --include-crds --dry-run)
;;
*)
echo ""
echo ">> Standard Rendering for $chart_name ..."
TEMPLATE=$(helm template "$chart_name" ./ --namespace "$chart_name" --include-crds --dry-run)
;;
esac
echo ""
echo ">> Formating rendered template ..."
echo "$TEMPLATE" | yq '... comments=""' | yq 'select(. != null)' | yq -s '"'"$OUTPUT_FOLDER"'" + .kind + "-" + .metadata.name + ".yaml"'
# Strip comments again to ensure formatting correctness
for file in "$OUTPUT_FOLDER"/*; do
yq -i '... comments=""' $file
done
echo ""
echo ">> Manifests for $chart_name rendered to $OUTPUT_FOLDER"
ls $OUTPUT_FOLDER
echo ""
else
echo ""
echo ">> Directory $chart_path does not contain a Chart.yaml. Skipping ..."
echo ""
fi
done
echo "----"
- name: Check for Changes
id: check-changes
if: steps.check-dir-changes.outputs.changes-detected == 'true'
run: |
cd ${MANIFEST_DIR}
GIT_CHANGES=$(git status --porcelain)
if [ -n "$GIT_CHANGES" ]; then
echo ">> Changes detected"
git status --porcelain
echo "changes-detected=true" >> $GITEA_OUTPUT
else
echo ">> No changes detected, skipping PR creation"
fi
echo "----"
- name: Commit and Push Changes
id: commit-push
if: steps.check-changes.outputs.changes-detected == 'true'
run: |
cd ${MANIFEST_DIR}
echo ">> Commiting changes to ${BRANCH_NAME} ..."
git add .
git commit -m "chore: Update manifests after change"
REPO_URL="${{ secrets.REPO_URL }}/${{ gitea.repository }}"
echo ">> Pushing changes to $REPO_URL ..."
git push -u "https://oauth2:${{ secrets.BOT_TOKEN }}@$(echo $REPO_URL | sed -e 's|https://||')" ${BRANCH_NAME}
echo "----"
echo "HEAD_BRANCH=${BRANCH_NAME}" >> $GITEA_OUTPUT
echo "push=true" >> $GITEA_OUTPUT
- name: Check for Pull Request
id: check-for-pull-requst
if: steps.commit-push.outputs.push == 'true'
env:
GITEA_TOKEN: ${{ secrets.BOT_TOKEN }}
GITEA_URL: ${{ secrets.REPO_URL }}
HEAD_BRANCH: ${{ steps.commit-push.outputs.HEAD_BRANCH }}
run: |
cd ${MANIFEST_DIR}
API_ENDPOINT="${GITEA_URL}/api/v1/repos/${{ gitea.repository }}/pulls?base_branch=${BASE_BRANCH}&state=open&page=1"
echo ">> Checking if PR from branch ${HEAD_BRANCH} into ${BASE_BRANCH}"
echo ">> With Endpoint of:"
echo "$API_ENDPOINT"
HTTP_STATUS=$(
curl -X GET \
--silent \
--write-out '%{http_code}' \
--output response_body.json \
--dump-header response_headers.txt \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
"$API_ENDPOINT" 2> response_errors.txt
)
echo ">> HTTP Status Code: $HTTP_STATUS"
echo ">> Response Output ..."
echo "----"
cat response_body.json
echo "----"
cat response_headers.txt
echo "----"
cat response_errors.txt
echo "----"
if [ "$HTTP_STATUS" == "200" ] && [ "$(cat response_body.json | jq -r .[0].state)" == "open" ]; then
echo ">> Pull Request has been found open, will update"
PR_INDEX=$(cat response_body.json | jq -r .[0].number)
echo "pull-request-exists=${PR_INDEX}" >> $GITEA_OUTPUT
echo "pull-request-index=true" >> $GITEA_OUTPUT
elif [ "$HTTP_STATUS" == "200" ] && [ "$(cat response_body.json | jq -r .[0].state)" == "closed" ]; then
echo ">> Pull Request found, but was closed"
echo "pull-request-exists=false" >> $GITEA_OUTPUT
else
echo ">> Pull Request not found"
echo "pull-request-exists=false" >> $GITEA_OUTPUT
fi
echo "----"
- name: Create Pull Request
id: create-pull-request
if: steps.commit-push.outputs.push == 'true' && steps.check-for-pull-requst.outputs.pull-request-exists == 'false'
env:
GITEA_TOKEN: ${{ secrets.BOT_TOKEN }}
GITEA_URL: ${{ secrets.REPO_URL }}
HEAD_BRANCH: ${{ steps.commit-push.outputs.HEAD_BRANCH }}
run: |
cd ${MANIFEST_DIR}
API_ENDPOINT="${GITEA_URL}/api/v1/repos/${{ gitea.repository }}/pulls"
PAYLOAD=$( jq -n \
--arg head "${HEAD_BRANCH}" \
--arg base "${BASE_BRANCH}" \
--arg assignee "${ASSIGNEE}" \
--arg title "Automated Manifest Update" \
--arg body "This PR contains newly rendered Kubernetes manifests automatically generated by the CI workflow." \
'{head: $head, base: $base, assignee: $assignee, title: $title, body: $body}' )
echo ">> Creating PR from branch ${HEAD_BRANCH} into ${BASE_BRANCH}"
echo ">> With Endpoint of:"
echo "$API_ENDPOINT"
echo ">> With Payload of:"
echo "$PAYLOAD"
HTTP_STATUS=$(
curl -X POST \
--silent \
--write-out '%{http_code}' \
--output response_body.json \
--dump-header response_headers.txt \
--data "$PAYLOAD" \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
"$API_ENDPOINT" 2> response_errors.txt
)
echo ">> HTTP Status Code: $HTTP_STATUS"
echo ">> Response Output ..."
echo "----"
cat response_body.json
echo "----"
cat response_headers.txt
echo "----"
cat response_errors.txt
echo "----"
if [ "$HTTP_STATUS" == "201" ]; then
echo ">> Pull Request created successfully!"
PR_URL=$(cat response_body.json | jq -r .html_url)
echo "pull-request-url=${PR_URL}" >> $GITEA_OUTPUT
PR_ID=$(cat response_body.json | jq -r .id)
echo "pull-request-id=${PR_ID}" >> $GITEA_OUTPUT
echo "pull-request-operation=created" >> $GITEA_OUTPUT
elif [ "$HTTP_STATUS" == "422" ]; then
echo ">> Failed to create PR (HTTP 422: Unprocessable Entity), PR may already exist"
elif [ "$HTTP_STATUS" == "409" ]; then
echo ">> Failed to create PR (HTTP 409: Conflict), PR already exists"
else
echo ">> Failed to create PR, HTTP status code: $HTTP_STATUS"
exit 1
fi
echo "----"
- name: ntfy Created
uses: niniyas/ntfy-action@master
if: steps.create-pull-request.outputs.pull-request-operation == 'created'
with:
url: "${{ secrets.NTFY_URL }}"
topic: "${{ secrets.NTFY_TOPIC }}"
title: "Manifest Render PR Created - Infrastructure"
priority: 3
headers: '{"Authorization": "Bearer ${{ secrets.NTFY_CRED }}"}'
tags: action,successfully,completed
details: "Manifest rendering for Infrastructure has created a new Pull Request with ID: ${{ steps.create-pull-request.outputs.pull-request-id }}!"
icon: "https://cdn.jsdelivr.net/gh/selfhst/icons/png/gitea.png"
actions: '[{"action": "view", "label": "Open Gitea", "url": "${{ steps.create-pull-request.outputs.pull-request-url }}", "clear": true}]'
- name: ntfy Failed
uses: niniyas/ntfy-action@master
if: failure()
with:
url: "${{ secrets.NTFY_URL }}"
topic: "${{ secrets.NTFY_TOPIC }}"
title: "Manifest Render Failure - Infrastructure"
priority: 4
headers: '{"Authorization": "Bearer ${{ secrets.NTFY_CRED }}"}'
tags: action,failed
details: "Manifest rendering for Infrastructure has failed!"
icon: "https://cdn.jsdelivr.net/gh/selfhst/icons/png/gitea.png"
actions: '[{"action": "view", "label": "Open Gitea", "url": "https://gitea.alexlebens.dev/alexlebens/infrastructure/actions?workflow=render-manifests.yaml", "clear": true}]'
image: true

View File

@@ -1,624 +0,0 @@
name: render-manifests
on:
schedule:
- cron: '0 15 * * *'
workflow_dispatch:
pull_request:
branches:
- main
paths:
- 'clusters/cl01tl/helm/**'
types:
- closed
env:
CLUSTER: cl01tl
BASE_BRANCH: manifests
BRANCH_NAME_BASE: auto/update-manifests
ASSIGNEE: alexlebens
MAIN_DIR: /workspace/alexlebens/infrastructure/infrastructure
MANIFEST_DIR: /workspace/alexlebens/infrastructure/infrastructure-manifests
jobs:
render-manifests:
runs-on: ubuntu-js
if: >-
github.event_name == 'schedule' ||
github.event_name == 'workflow_dispatch' ||
(github.event_name == 'pull_request' && github.event.pull_request.merged == true)
steps:
- name: Checkout Main
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
path: infrastructure
fetch-depth: 0
- name: Checkout Manifests
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
ref: manifests
path: infrastructure-manifests
- name: Set Up Helm
uses: azure/setup-helm@dda3372f752e03dde6b3237bc9431cdc2f7a02a2 # v5
with:
token: ${{ secrets.GITEA_TOKEN }}
version: v3.17.2 # Pending https://github.com/helm/helm/pull/30743
cache: true
- name: Configure Kubeconfig
uses: azure/k8s-set-context@ae59a723ba9abe7a9655538854a025448dbab4aa # v4
with:
method: kubeconfig
kubeconfig: ${{ secrets.KUBECONFIG }}
- name: Cache Helm Dependencies
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5
with:
path: |
~/.cache/helm
~/.config/helm
key: helm-cache-${{ runner.os }}-${{ hashFiles('infrastructure/clusters/cl01tl/helm/**/Chart.yaml', 'infrastructure/clusters/cl01tl/helm/**/Chart.lock') }}
restore-keys: |
helm-cache-${{ runner.os }}-
- name: Determine Workflow Mode
id: mode
run: |
IS_AUTOMERGE="false"
RENDER_ALL="false"
DIFF_TARGET=""
if [[ "${{ github.event_name }}" == "schedule" || "${{ github.event_name }}" == "workflow_dispatch" ]]; then
echo ">> Mode: Dispatch/Schedule (Render All)"
RENDER_ALL="true"
elif [[ "${{ github.event_name }}" == "pull_request" ]]; then
if [[ "${{ contains(github.event.pull_request.labels.*.name, 'automerge') }}" == "true" ]]; then
echo ">> Mode: PR Merged (Automerge)"
IS_AUTOMERGE="true"
else
echo ">> Mode: PR Merged (Standard)"
fi
DIFF_TARGET="HEAD^..HEAD"
fi
echo ""
echo "----"
echo "is-automerge=${IS_AUTOMERGE}" >> "$GITHUB_OUTPUT"
echo "render-all=${RENDER_ALL}" >> "$GITHUB_OUTPUT"
echo "diff-target=${DIFF_TARGET}" >> "$GITHUB_OUTPUT"
- name: Prepare Manifest Branch
id: prepare-manifest-branch
env:
PR_NUMBER: ${{ github.event.pull_request.number }}
IS_AUTOMERGE: ${{ steps.mode.outputs.is-automerge }}
run: |
cd "${MANIFEST_DIR}"
echo ">> Configure git to use gitea-bot as user ..."
git config user.name "gitea-bot"
git config user.email "gitea-bot@alexlebens.net"
if [[ "$IS_AUTOMERGE" == "true" ]]; then
BRANCH_NAME="${BRANCH_NAME_BASE}-automerge-${PR_NUMBER}"
echo ""
echo ">> Creating branch ${BRANCH_NAME} ..."
git checkout -B "$BRANCH_NAME"
else
echo ""
echo ">> Checking if PR branch exists ..."
BRANCH_NAME="${BRANCH_NAME_BASE}"
if git ls-remote --exit-code --heads origin "${BRANCH_NAME}" > /dev/null 2>&1; then
echo ""
echo ">> Branch '${BRANCH_NAME}' exists, pulling changes ..."
git fetch origin "${BRANCH_NAME}"
git checkout "${BRANCH_NAME}"
git pull --rebase
else
echo ""
echo ">> Branch '${BRANCH_NAME}' does not exist, creating ..."
git checkout -b "${BRANCH_NAME}"
fi
fi
echo ""
echo "----"
echo "branch-name=${BRANCH_NAME}" >> "$GITHUB_OUTPUT"
- name: Check Which Directories Have Changes
id: check-dir-changes
env:
RENDER_ALL: ${{ steps.mode.outputs.render-all }}
DIFF_TARGET: ${{ steps.mode.outputs.diff-target }}
run: |
cd "${MAIN_DIR}"
if [[ "$RENDER_ALL" == "true" ]]; then
echo ">> Triggered on dispatch, will check all paths ..."
RENDER_DIR=$(find "clusters/${CLUSTER}/helm" -mindepth 1 -maxdepth 1 -type d -exec basename {} \; | sort -u)
else
echo ">> Checking for changes from ${DIFF_TARGET} ..."
RENDER_DIR=$(git diff --name-only "${DIFF_TARGET}" | grep -E "^clusters/${CLUSTER}/helm/" | awk -F '/' '{print $4}' | sort -u || true)
fi
if [ -n "${RENDER_DIR}" ]; then
echo ""
echo ">> Directories to Render:"
echo ""
echo "${RENDER_DIR}"
echo ""
echo "----"
echo "changes-detected=true" >> "$GITHUB_OUTPUT"
echo "render-dir<<EOF" >> "$GITHUB_OUTPUT"
echo "${RENDER_DIR}" >> "$GITHUB_OUTPUT"
echo "EOF" >> "$GITHUB_OUTPUT"
else
echo ""
echo ">> No chart changes detected"
echo ""
echo "----"
echo "changes-detected=false" >> "$GITHUB_OUTPUT"
fi
- name: Add Repositories
if: steps.check-dir-changes.outputs.changes-detected == 'true'
env:
RENDER_DIR: ${{ steps.check-dir-changes.outputs.render-dir }}
run: |
cd "${MAIN_DIR}"
echo ">> Adding repositories for chart dependencies ..."
echo ""
for DIR in ${RENDER_DIR}; do
helm dependency list --max-col-width 120 "${MAIN_DIR}/clusters/${CLUSTER}/helm/${DIR}" 2> /dev/null \
| tail -n +2 \
| awk 'NF > 0 { print $1, $3 }' \
| while read -r REPO_NAME REPO_URL; do
if [[ "${REPO_URL}" == oci://* ]]; then
echo ">> Ignoring OCI repo: ${REPO_URL}"
elif [[ -n "${REPO_NAME}" && -n "${REPO_URL}" ]]; then
helm repo add "${REPO_NAME}" "${REPO_URL}"
fi
done || true
done
if helm repo list > /dev/null 2>&1; then
echo ""
echo ">> Update repository cache ..."
helm repo update
fi
echo ""
echo "----"
- name: Remove Changed Manifest Files
if: steps.check-dir-changes.outputs.changes-detected == 'true'
env:
RENDER_DIR: ${{ steps.check-dir-changes.outputs.render-dir }}
run: |
cd "${MANIFEST_DIR}"
echo ">> Remove manifest files and rebuild from source ..."
echo ""
for DIR in ${RENDER_DIR}; do
CHART_PATH="${MANIFEST_DIR}/clusters/${CLUSTER}/manifests/${DIR}"
echo "${CHART_PATH}"
rm -rf "${CHART_PATH}"/*
done
echo ""
echo "----"
- name: Render Helm Manifests
id: render-manifests
if: steps.check-dir-changes.outputs.changes-detected == 'true'
env:
RENDER_DIR: ${{ steps.check-dir-changes.outputs.render-dir }}
run: |
cd "${MAIN_DIR}"
echo ">> Rendering Manifests ..."
render_chart() {
local DIR="$1"
local CHART_PATH="${MAIN_DIR}/clusters/${CLUSTER}/helm/${DIR}"
local CHART_NAME=$(basename "${CHART_PATH}")
echo ""
echo ">> Rendering chart: ${CHART_NAME}"
if [ -f "${CHART_PATH}/Chart.yaml" ]; then
local OUTPUT_FOLDER="${MANIFEST_DIR}/clusters/${CLUSTER}/manifests/${CHART_NAME}/"
mkdir -p "${OUTPUT_FOLDER}"
cd "${CHART_PATH}"
helm dependency update --skip-refresh > /dev/null
helm lint --namespace "${CHART_NAME}" --quiet
local NAMESPACE="${CHART_NAME}"
case "${CHART_NAME}" in
"stack")
NAMESPACE="argocd"
echo ">> Special Rendering into 'argocd' namespace ..."
;;
"cilium" | "coredns" | "metrics-server" | "prometheus-operator-crds")
NAMESPACE="kube-system"
echo ">> Special Rendering for ${CHART_NAME} into 'kube-system' namespace ..."
;;
*)
echo ">> Standard Rendering ..."
esac
echo ">> Formating rendered template ..."
local TEMPLATE
TEMPLATE=$(helm template "${CHART_NAME}" ./ --namespace "${NAMESPACE}" --include-crds --dry-run=server --api-versions "gateway.networking.k8s.io/v1/HTTPRoute")
# Format and split rendered template
echo "${TEMPLATE}" | yq '... comments=""' | yq 'select(. != null)' | yq -s '"'"${OUTPUT_FOLDER}"'" + .kind + "-" + .metadata.name + ".yaml"'
# Strip comments again to ensure formatting correctness
for file in "$OUTPUT_FOLDER"/*; do
yq -i '... comments=""' $file
done
echo ">> Manifests for ${CHART_NAME} rendered successfully to $OUTPUT_FOLDER:"
echo ""
ls $OUTPUT_FOLDER
echo ""
else
echo ""
echo ">> Directory ${CHART_PATH} does not contain a Chart.yaml. Skipping ..."
fi
}
export -f render_chart
export MAIN_DIR CLUSTER MANIFEST_DIR
# Run rendering in parallel
for DIR in ${RENDER_DIR}; do
echo "${DIR}"
done | xargs -P 4 -I {} bash -c 'OUT=$(render_chart "$@" 2>&1); printf "%s\n" "$OUT"' _ {}
echo ""
echo "----"
- name: Check for Changes
id: check-changes
if: steps.check-dir-changes.outputs.changes-detected == 'true'
run: |
cd "${MANIFEST_DIR}"
GIT_CHANGES=$(git status --porcelain)
if [ -n "${GIT_CHANGES}" ]; then
echo ">> Changes detected"
git status --porcelain
CHANGED_CHARTS=$(echo "$GIT_CHANGES" | grep -oE "clusters/${CLUSTER}/manifests/[^/]+" | awk -F '/' '{print $4}' | sort -u | paste -sd ',' -)
echo ""
echo "----"
echo "changes-detected=true" >> "$GITHUB_OUTPUT"
echo "changed-charts-csv=${CHANGED_CHARTS}" >> "$GITHUB_OUTPUT"
else
echo ">> No changes detected, skipping PR creation"
echo ""
echo "----"
fi
- name: Commit and Push Changes
id: commit-push
if: steps.check-changes.outputs.changes-detected == 'true'
env:
BRANCH_NAME: ${{ steps.prepare-manifest-branch.outputs.branch-name }}
IS_AUTOMERGE: ${{ steps.mode.outputs.is-automerge }}
run: |
cd "${MANIFEST_DIR}"
MSG="chore: Update manifests after change"
if [[ "$IS_AUTOMERGE" == "true" ]]; then
MSG="chore: Update manifests after automerge"
fi
echo ">> Commiting changes to ${BRANCH_NAME} ..."
git add .
git commit -m "${MSG}"
REPO_URL="${{ secrets.REPO_URL }}/${{ gitea.repository }}"
echo ""
echo ">> Pushing changes to ${REPO_URL} ..."
git push -u "https://oauth2:${{ secrets.BOT_TOKEN }}@${REPO_URL#*://}" "${BRANCH_NAME}"
echo ""
echo "----"
echo "push=true" >> "$GITHUB_OUTPUT"
echo "head-branch=${BRANCH_NAME}" >> "$GITHUB_OUTPUT"
- name: Check for Pull Request
id: check-for-pull-request
if: steps.commit-push.outputs.push == 'true' && steps.mode.outputs.is-automerge == 'false'
env:
GITEA_TOKEN: ${{ secrets.BOT_TOKEN }}
GITEA_URL: ${{ secrets.REPO_URL }}
HEAD_BRANCH: ${{ steps.commit-push.outputs.head-branch }}
run: |
cd "${MANIFEST_DIR}"
API_ENDPOINT="${GITEA_URL}/api/v1/repos/${{ gitea.repository }}/pulls?base_branch=${BASE_BRANCH}&state=open&page=1"
echo ">> Checking if PR from branch ${HEAD_BRANCH} into ${BASE_BRANCH}"
echo ">> With Endpoint of:"
echo "$API_ENDPOINT"
HTTP_STATUS=$(curl -X GET -s -w '%{http_code}' -o response_body.json -H "Authorization: token ${GITEA_TOKEN}" -H "Content-Type: application/json" "$API_ENDPOINT")
if [ "$HTTP_STATUS" == "200" ] && [ "$(cat response_body.json | jq -r .[0].state)" == "open" ]; then
echo ""
echo ">> Pull Request has been found open, will update"
echo ""
echo "----"
echo "pull-request-exists=$(cat response_body.json | jq -r .[0].number)" >> "$GITHUB_OUTPUT"
else
echo ""
echo ">> Pull Request not found"
echo ""
echo "----"
echo "pull-request-exists=false" >> "$GITHUB_OUTPUT"
fi
- name: Create Pull Request
id: create-pull-request
if: steps.commit-push.outputs.push == 'true' && (steps.mode.outputs.is-automerge == 'true' || steps.check-for-pull-request.outputs.pull-request-exists == 'false')
env:
IS_AUTOMERGE: ${{ steps.mode.outputs.is-automerge }}
GITEA_TOKEN: ${{ secrets.BOT_TOKEN }}
GITEA_URL: ${{ secrets.REPO_URL }}
HEAD_BRANCH: ${{ steps.commit-push.outputs.head-branch }}
CHARTS: ${{ steps.check-changes.outputs.changed-charts-csv }}
EVENT_NAME: ${{ github.event_name }}
ACTOR: ${{ github.actor }}
SHA: ${{ github.sha }}
REF: ${{ github.ref_name }}
run: |
cd "${MANIFEST_DIR}"
API_ENDPOINT="${GITEA_URL}/api/v1/repos/${{ gitea.repository }}/pulls"
BODY=$(printf "This PR contains newly rendered Kubernetes manifests automatically generated by the CI workflow.\n\n### Details\n- **Trigger**: \`%s\` by \`@%s\`\n- **Commit**: \`%s\` (on \`%s\`)\n- **Charts Updated**: \`%s\`" "${EVENT_NAME}" "${ACTOR}" "${SHA:0:7}" "${REF}" "${CHARTS}")
if [[ "$IS_AUTOMERGE" == "true" ]]; then
TITLE="Automated Manifest Update - Automerge"
BODY=$(printf "%s\n\n_This PR is expected to be automerged._" "${BODY}")
else
TITLE="Automated Manifest Update"
fi
PAYLOAD=$(jq -n --arg head "${HEAD_BRANCH}" --arg base "${BASE_BRANCH}" --arg assignee "${ASSIGNEE}" --arg title "${TITLE}" --arg body "${BODY}" '{head: $head, base: $base, assignee: $assignee, title: $title, body: $body}')
HTTP_STATUS=$(curl -X POST -s -w '%{http_code}' -o response_body.json --data "$PAYLOAD" -H "Authorization: token ${GITEA_TOKEN}" -H "Content-Type: application/json" "$API_ENDPOINT")
if [ "$HTTP_STATUS" == "201" ]; then
echo ">> Pull Request created successfully!"
echo ""
echo "----"
echo "pull-request-id=$(jq -r .id response_body.json)" >> "$GITHUB_OUTPUT"
echo "pull-request-number=$(jq -r .number response_body.json)" >> "$GITHUB_OUTPUT"
echo "pull-request-operation=created" >> "$GITHUB_OUTPUT"
elif [[ "$HTTP_STATUS" == "422" || "$HTTP_STATUS" == "409" ]]; then
echo ""
echo ">> Failed to create PR (Already exists)"
echo ""
echo "----"
else
echo ""
echo ">> Failed to create PR, HTTP status code: $HTTP_STATUS"
echo ""
echo "----"
exit 1
fi
- name: Update Pull Request
id: update-pull-request
if: steps.commit-push.outputs.push == 'true' && steps.check-for-pull-request.outputs.pull-request-exists != 'false' && steps.mode.outputs.is-automerge == 'false'
env:
GITEA_TOKEN: ${{ secrets.BOT_TOKEN }}
GITEA_URL: ${{ secrets.REPO_URL }}
PR_NUMBER: ${{ steps.check-for-pull-request.outputs.pull-request-exists }}
CHARTS: ${{ steps.check-changes.outputs.changed-charts-csv }}
EVENT_NAME: ${{ github.event_name }}
ACTOR: ${{ github.actor }}
SHA: ${{ github.sha }}
REF: ${{ github.ref_name }}
run: |
cd "${MANIFEST_DIR}"
API_ENDPOINT="${GITEA_URL}/api/v1/repos/${{ gitea.repository }}/pulls/${PR_NUMBER}"
EXISTING_BODY=$(jq -r '.[0].body' response_body.json)
NEW_DETAILS=$(printf "### Update Details (%s)\n- **Trigger**: \`%s\` by \`@%s\`\n- **Commit**: \`%s\` (on \`%s\`)\n- **Charts Updated**: \`%s\`" "$(date -u +'%Y-%m-%d %H:%M UTC')" "${EVENT_NAME}" "${ACTOR}" "${SHA:0:7}" "${REF}" "${CHARTS}")
UPDATED_BODY=$(printf "%s\n\n%s" "${EXISTING_BODY}" "${NEW_DETAILS}")
PAYLOAD=$(jq -n --arg body "${UPDATED_BODY}" '{body: $body}')
HTTP_STATUS=$(curl -X PATCH -s -w '%{http_code}' -o update_response.json --data "$PAYLOAD" -H "Authorization: token ${GITEA_TOKEN}" -H "Content-Type: application/json" "$API_ENDPOINT")
if [ "$HTTP_STATUS" == "201" ] || [ "$HTTP_STATUS" == "200" ]; then
echo ">> Pull Request updated successfully!"
echo ""
echo "----"
echo "pull-request-operation=updated" >> "$GITHUB_OUTPUT"
else
echo ">> Failed to update PR, HTTP status code: $HTTP_STATUS"; exit 1
echo ""
echo "----"
fi
- name: Merge Changes
id: merge-changes
if: steps.commit-push.outputs.push == 'true' && steps.mode.outputs.is-automerge == 'true'
env:
GITEA_TOKEN: ${{ secrets.BOT_TOKEN }}
GITEA_URL: ${{ secrets.REPO_URL }}
PR_NUMBER: ${{ steps.create-pull-request.outputs.pull-request-number }}
run: |
cd "${MANIFEST_DIR}"
API_ENDPOINT="${GITEA_URL}/api/v1/repos/${{ gitea.repository }}/pulls/${PR_NUMBER}/merge"
PAYLOAD=$(jq -n --arg Do "merge" '{Do: $Do}')
HTTP_STATUS=$(curl -X POST -s -w '%{http_code}' -o response_body.json --data "$PAYLOAD" -H "Authorization: token ${GITEA_TOKEN}" -H "Content-Type: application/json" "$API_ENDPOINT")
if [ "$HTTP_STATUS" == "200" ]; then
echo ">> Pull Request merged successfully!"
echo ""
echo "----"
echo "pull-request-operation=merged" >> "$GITHUB_OUTPUT"
else
echo ">> Failed to merge PR, HTTP status code: $HTTP_STATUS"; exit 1
echo ""
echo "----"
fi
- name: Cleanup Branch
if: failure() && steps.mode.outputs.is-automerge == 'true'
env:
BRANCH_NAME: ${{ steps.prepare-manifest-branch.outputs.branch-name }}
run: |
cd "${MANIFEST_DIR}"
echo ">> Removing branch: ${BRANCH_NAME}"
git push origin --delete "${BRANCH_NAME}" || true
echo ""
echo "----"
- name: ntfy Created
uses: niniyas/ntfy-action@96acac57fdc91d4c4f50b78486c1ed6f03f9f61c # master
if: steps.create-pull-request.outputs.pull-request-operation == 'created' && steps.mode.outputs.is-automerge == 'false'
with:
url: "${{ secrets.NTFY_URL }}"
topic: "${{ secrets.NTFY_TOPIC }}"
title: "Manifest Render - Open PR"
priority: 3
headers: '{"Authorization": "Bearer ${{ secrets.NTFY_CRED }}"}'
tags: action,successfully,completed
details: "Created renderd manifests for cluster '${{ env.CLUSTER }}' with charts: ${{ steps.check-changes.outputs.changed-charts-csv }}"
icon: "https://cdn.jsdelivr.net/gh/selfhst/icons/png/gitea.png"
actions: '[{"action": "view", "label": "View PR", "url": "${{ vars.USER_URL }}/${{ github.repository }}/pulls/${{ steps.create-pull-request.outputs.pull-request-number }}", "clear": true}]'
- name: ntfy Updated
uses: niniyas/ntfy-action@96acac57fdc91d4c4f50b78486c1ed6f03f9f61c # master
if: steps.commit-push.outputs.push == 'true' && steps.check-for-pull-request.outputs.pull-request-exists != 'false' && steps.mode.outputs.is-automerge == 'false'
with:
url: "${{ secrets.NTFY_URL }}"
topic: "${{ secrets.NTFY_TOPIC }}"
title: "Manifest Render - PR Updated"
priority: 3
headers: '{"Authorization": "Bearer ${{ secrets.NTFY_CRED }}"}'
tags: action,successfully,completed
details: "Updated rendered manifests PR for cluster '${{ env.CLUSTER }}' with charts: ${{ steps.check-changes.outputs.changed-charts-csv }}"
icon: "https://cdn.jsdelivr.net/gh/selfhst/icons/png/gitea.png"
actions: '[{"action": "view", "label": "View PR", "url": "${{ vars.USER_URL }}/${{ github.repository }}/pulls/${{ steps.create-pull-request.outputs.pull-request-number }}", "clear": true}]'
- name: ntfy Merged
uses: niniyas/ntfy-action@96acac57fdc91d4c4f50b78486c1ed6f03f9f61c # master
if: steps.merge-changes.outputs.pull-request-operation == 'merged'
with:
url: "${{ secrets.NTFY_URL }}"
topic: "${{ secrets.NTFY_TOPIC }}"
title: "Manifest Render - Automerged"
priority: 3
headers: '{"Authorization": "Bearer ${{ secrets.NTFY_CRED }}"}'
tags: action,successfully,completed
details: "Automerged manifest rendering for cluster '${{ env.CLUSTER }}' with charts: ${{ steps.check-changes.outputs.changed-charts-csv }}"
icon: "https://cdn.jsdelivr.net/gh/selfhst/icons/png/gitea.png"
actions: '[{"action": "view", "label": "View PR", "url": "${{ vars.USER_URL }}/${{ github.repository }}/pulls/${{ steps.create-pull-request.outputs.pull-request-number }}", "clear": true}]'
- name: ntfy Failed
uses: niniyas/ntfy-action@96acac57fdc91d4c4f50b78486c1ed6f03f9f61c # master
if: failure()
with:
url: "${{ secrets.NTFY_URL }}"
topic: "${{ secrets.NTFY_TOPIC }}"
title: "Manifest Render Failure"
priority: 4
headers: '{"Authorization": "Bearer ${{ secrets.NTFY_CRED }}"}'
tags: action,failed
details: "Manifest rendering for Infrastructure has failed!"
icon: "https://cdn.jsdelivr.net/gh/selfhst/icons/png/gitea.png"
actions: '[{"action": "view", "label": "View Logs", "url": "${{ vars.USER_URL }}/${{ github.repository }}/actions/runs/${{ github.run_id }}", "clear": true}]'

View File

@@ -13,10 +13,10 @@ on:
jobs:
renovate:
runs-on: ubuntu-latest
container: ghcr.io/renovatebot/renovate:43.84.2@sha256:92285747b3aac062a4f567762c272a12dce037843a20177a02c95b7c420e20cb
container: ghcr.io/renovatebot/renovate:42
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
uses: actions/checkout@v6
- name: Renovate
run: renovate
@@ -25,7 +25,7 @@ jobs:
RENOVATE_ENDPOINT: ${{ vars.INSTANCE_URL }}
RENOVATE_REPOSITORIES: alexlebens/infrastructure
RENOVATE_GIT_AUTHOR: Renovate Bot <renovate-bot@alexlebens.net>
LOG_LEVEL: debug
LOG_LEVEL: info
RENOVATE_TOKEN: ${{ secrets.RENOVATE_TOKEN }}
RENOVATE_GIT_PRIVATE_KEY: ${{ secrets.RENOVATE_GIT_PRIVATE_KEY }}
RENOVATE_GITHUB_COM_TOKEN: ${{ secrets.RENOVATE_GITHUB_COM_TOKEN }}

1
.gitignore vendored
View File

@@ -1,4 +1,3 @@
/**/archive/
/**/charts/
/**/manifests/
/**/tmpcharts*/

View File

@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v6.0.0
rev: v2.3.0
hooks:
- id: end-of-file-fixer
- id: trailing-whitespace
@@ -9,9 +9,7 @@ repos:
exclude: '^.*\/templates\/.*$'
args:
- --multi
- id: check-merge-conflict
- id: check-json
- repo: https://github.com/IamTheFij/docker-pre-commit
rev: v3.0.1
rev: v2.0.0
hooks:
- id: docker-compose-check

View File

@@ -2,12 +2,6 @@
GitOps definied infrastrucutre for the alexlebens.net domain.
## Stack-cl01tl
https://argocd.alexlebens.net/api/badge?name=stack-cl01tl&revision=true&showAppName=true
App-of-Apps Application for cl01tl
## License
This project is licensed under the terms of the Apache 2.0 License license.

View File

@@ -1,9 +1,9 @@
dependencies:
- name: app-template
repository: https://bjw-s-labs.github.io/helm-charts/
version: 4.6.2
version: 4.5.0
- name: volsync-target
repository: oci://harbor.alexlebens.net/helm-charts
version: 0.8.0
digest: sha256:ff81b3d8fc831e4b8048f646fffcf597aa7410e52ecf27690eab8104047dbe6f
generated: "2026-03-06T01:04:41.514235218Z"
version: 0.3.0
digest: sha256:3763d6c5c0b45219235229aa1d72bfa426abd29aa8d92c1b1ca958b6afb3bfc8
generated: "2025-12-15T17:43:51.908308-06:00"

View File

@@ -5,23 +5,21 @@ description: Actual
keywords:
- actual
- budget
home: https://docs.alexlebens.dev/applications/actual/
home: https://wiki.alexlebens.dev/s/86192f45-94b7-45de-872c-6ef3fec7df5e
sources:
- https://github.com/actualbudget/actual
- https://github.com/actualbudget/actual/pkgs/container/actual
- https://github.com/bjw-s-labs/helm-charts/tree/main/charts/other/app-template
- https://gitea.alexlebens.dev/alexlebens/helm-charts/src/branch/main/charts/volsync-target
maintainers:
- name: alexlebens
dependencies:
- name: app-template
alias: actual
repository: https://bjw-s-labs.github.io/helm-charts/
version: 4.6.2
version: 4.5.0
- name: volsync-target
alias: volsync-target-data
version: 0.8.0
version: 0.3.0
repository: oci://harbor.alexlebens.net/helm-charts
icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/actual-budget.png
# renovate: datasource=github-releases depName=actualbudget/actual
appVersion: 26.3.0
appVersion: 25.12.0

View File

@@ -0,0 +1,28 @@
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: http-route-actual
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: http-route-actual
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/part-of: {{ .Release.Name }}
spec:
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: traefik-gateway
namespace: traefik
hostnames:
- actual.alexlebens.net
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- group: ''
kind: Service
name: actual
port: 80
weight: 100

View File

@@ -4,18 +4,20 @@ actual:
type: deployment
replicas: 1
strategy: Recreate
revisionHistoryLimit: 3
containers:
main:
image:
repository: ghcr.io/actualbudget/actual
tag: 26.3.0@sha256:eb8bc26f53025e07e464594c12d77c52c4b95840c8dadd9b95c4f0c4660f8ad2
tag: 25.12.0
pullPolicy: IfNotPresent
env:
- name: ACTUAL_PORT
value: 5006
- name: TZ
value: US/Central
resources:
requests:
cpu: 25m
memory: 64Mi
cpu: 10m
memory: 128Mi
probes:
liveness:
enabled: true
@@ -40,30 +42,13 @@ actual:
port: 80
targetPort: 5006
protocol: HTTP
route:
main:
kind: HTTPRoute
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: traefik-gateway
namespace: traefik
hostnames:
- actual.alexlebens.net
rules:
- backendRefs:
- name: actual
port: 80
matches:
- path:
type: PathPrefix
value: /
persistence:
data:
forceRename: actual-data
storageClass: ceph-block
accessMode: ReadWriteOnce
size: 2Gi
retain: true
advancedMounts:
main:
main:
@@ -71,12 +56,3 @@ actual:
readOnly: false
volsync-target-data:
pvcTarget: actual-data
local:
enabled: true
schedule: 0 8 * * *
remote:
enabled: true
schedule: 0 9 * * *
external:
enabled: true
schedule: 0 10 * * *

View File

@@ -1,12 +1,12 @@
dependencies:
- name: argo-workflows
repository: https://argoproj.github.io/argo-helm
version: 1.0.5
version: 0.46.2
- name: argo-events
repository: https://argoproj.github.io/argo-helm
version: 2.4.21
version: 2.4.19
- name: postgres-cluster
repository: oci://harbor.alexlebens.net/helm-charts
version: 7.10.0
digest: sha256:d0d7ebf1c0013d001aa2f17d04a6d3f3d7a1fa7d5c62792eef856b87c24eb26e
generated: "2026-03-20T20:48:30.830922259Z"
version: 7.1.3
digest: sha256:fb51f9312fd003df7f9beced8e3583eb66c74a57820effab510bd80ce3a91558
generated: "2025-12-17T16:08:51.370582257Z"

View File

@@ -7,26 +7,25 @@ keywords:
- argo-events
- workflows
- events
home: https://docs.alexlebens.dev/applications/argo-workflows/
home: https://wiki.alexlebens.dev/s/a268508f-d81d-4b4b-8bd5-9058edaea635
sources:
- https://github.com/argoproj/argo-workflows
- https://github.com/argoproj/argo-events
- https://github.com/argoproj/argo-helm/tree/main/charts/argo-workflows
- https://github.com/argoproj/argo-helm/tree/main/charts/argo-events
- https://github.com/cloudnative-pg/cloudnative-pg
- https://github.com/argoproj/argo-helm/tree/main/charts
- https://gitea.alexlebens.dev/alexlebens/helm-charts/src/branch/main/charts/postgres-cluster
maintainers:
- name: alexlebens
dependencies:
- name: argo-workflows
version: 1.0.5
version: 0.46.2
repository: https://argoproj.github.io/argo-helm
- name: argo-events
version: 2.4.21
version: 2.4.19
repository: https://argoproj.github.io/argo-helm
- name: postgres-cluster
alias: postgres-18-cluster
version: 7.10.0
version: 7.1.3
repository: oci://harbor.alexlebens.net/helm-charts
icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/argo-cd.png
# renovate: datasource=github-releases depName=argoproj/argo-workflows
appVersion: v4.0.3
appVersion: v3.7.6

View File

@@ -14,9 +14,82 @@ spec:
data:
- secretKey: secret
remoteRef:
conversionStrategy: Default
decodingStrategy: None
key: /authentik/oidc/argo-workflows
metadataPolicy: None
property: secret
- secretKey: client
remoteRef:
conversionStrategy: Default
decodingStrategy: None
key: /authentik/oidc/argo-workflows
metadataPolicy: None
property: client
---
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: argo-workflows-postgresql-18-cluster-backup-secret
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: argo-workflows-postgresql-18-cluster-backup-secret
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/part-of: {{ .Release.Name }}
spec:
secretStoreRef:
kind: ClusterSecretStore
name: vault
data:
- secretKey: ACCESS_KEY_ID
remoteRef:
conversionStrategy: Default
decodingStrategy: None
key: /digital-ocean/home-infra/postgres-backups
metadataPolicy: None
property: access
- secretKey: ACCESS_SECRET_KEY
remoteRef:
conversionStrategy: Default
decodingStrategy: None
key: /digital-ocean/home-infra/postgres-backups
metadataPolicy: None
property: secret
---
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: argo-workflows-postgresql-18-cluster-backup-secret-garage
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: argo-workflows-postgresql-18-cluster-backup-secret-garage
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/part-of: {{ .Release.Name }}
spec:
secretStoreRef:
kind: ClusterSecretStore
name: vault
data:
- secretKey: ACCESS_KEY_ID
remoteRef:
conversionStrategy: Default
decodingStrategy: None
key: /garage/home-infra/postgres-backups
metadataPolicy: None
property: ACCESS_KEY_ID
- secretKey: ACCESS_SECRET_KEY
remoteRef:
conversionStrategy: Default
decodingStrategy: None
key: /garage/home-infra/postgres-backups
metadataPolicy: None
property: ACCESS_SECRET_KEY
- secretKey: ACCESS_REGION
remoteRef:
conversionStrategy: Default
decodingStrategy: None
key: /garage/home-infra/postgres-backups
metadataPolicy: None
property: ACCESS_REGION

View File

@@ -0,0 +1,28 @@
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: http-route-argo-workflows
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: http-route-argo-workflows
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/part-of: {{ .Release.Name }}
spec:
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: traefik-gateway
namespace: traefik
hostnames:
- argo-workflows.alexlebens.net
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- group: ''
kind: Service
name: argo-workflows-server
port: 2746
weight: 100

View File

@@ -1,16 +1,13 @@
argo-workflows:
crds:
install: true
keep: true
full: true
upgradeJob:
image:
repository: registry.k8s.io/kubectl
tag: v1.35.3
controller:
metricsConfig:
enabled: true
persistence:
connectionPool:
maxIdleConns: 100
maxOpenConns: 0
nodeStatusOffLoad: true
archive: true
postgresql:
host: argo-workflows-postgresql-18-cluster-rw
port: 5432
@@ -25,34 +22,24 @@ argo-workflows:
ssl: false
sslMode: disable
workflowWorkers: 2
workflowTTLWorkers: 2
podCleanupWorkers: 2
cronWorkflowWorkers: 2
workflowTTLWorkers: 1
podCleanupWorkers: 1
cronWorkflowWorkers: 1
resources:
requests:
cpu: 10m
memory: 32Mi
memory: 128Mi
serviceMonitor:
enabled: true
name: workflow-controller
workflowNamespaces:
- argocd
- argo-workflows
server:
authModes:
- sso
httproute:
enabled: true
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: traefik-gateway
namespace: traefik
hostnames:
- argo-workflows.alexlebens.net
rules:
- matches:
- path:
type: PathPrefix
value: /
ingress:
enabled: false
sso:
enabled: true
issuer: https://authentik.alexlebens.net/application/o/argo-workflows/
@@ -69,15 +56,15 @@ argo-workflows:
- openid
- email
- profile
useStaticCredentials: true
artifactRepository:
archiveLogs: false
argo-events:
crds:
install: true
keep: true
controller:
resources:
requests:
cpu: 10m
memory: 32Mi
memory: 128Mi
metrics:
enabled: true
serviceMonitor:
@@ -87,23 +74,58 @@ argo-events:
resources:
requests:
cpu: 10m
memory: 32Mi
memory: 128Mi
postgres-18-cluster:
mode: recovery
cluster:
storage:
storageClass: local-path
walStorage:
storageClass: local-path
recovery:
method: objectStore
objectStore:
destinationPath: s3://postgres-backups/cl01tl/argo-workflows/argo-workflows-postgresql-18-cluster
endpointURL: http://garage-main.garage:3900
index: 1
endpointCredentials: argo-workflows-postgresql-18-cluster-backup-secret-garage
backup:
objectStore:
- name: garage-local
destinationPath: s3://postgres-backups/cl01tl/argo-workflows/argo-workflows-postgresql-18-cluster
index: 1
destinationBucket: postgres-backups
externalSecretCredentialPath: /garage/home-infra/postgres-backups
endpointURL: http://garage-main.garage:3900
endpointCredentials: argo-workflows-postgresql-18-cluster-backup-secret-garage
endpointCredentialsIncludeRegion: true
retentionPolicy: "3d"
isWALArchiver: true
# - name: external
# destinationPath: s3://postgres-backups-ce540ddf106d186bbddca68a/cl01tl/argo-workflows/argo-workflows-postgresql-18-cluster
# index: 1
# retentionPolicy: "30d"
# isWALArchiver: false
# - name: garage-remote
# destinationPath: s3://postgres-backups/cl01tl/argo-workflows/argo-workflows-postgresql-18-cluster
# index: 1
# endpointURL: https://garage-ps10rp.boreal-beaufort.ts.net:3900
# endpointCredentials: argo-workflows-postgresql-18-cluster-backup-secret-garage
# endpointCredentialsIncludeRegion: true
# retentionPolicy: "30d"
# data:
# compression: bzip2
scheduledBackups:
- name: live-backup
suspend: false
immediate: true
schedule: "0 0 14 * * *"
schedule: "0 0 0 * * *"
backupName: garage-local
# - name: daily-backup
# suspend: false
# immediate: true
# schedule: "0 0 0 * * *"
# backupName: external
# - name: weekly-backup
# suspend: true
# immediate: true
# schedule: "0 0 4 * * SAT"
# backupName: garage-remote

View File

@@ -1,6 +1,6 @@
dependencies:
- name: argo-cd
repository: https://argoproj.github.io/argo-helm
version: 9.4.15
digest: sha256:a0eed2e174bb6b13d04653c755a359025b050d479a92180039a1990dd8ee7caa
generated: "2026-03-20T01:09:07.547016465Z"
version: 9.1.8
digest: sha256:4d2089dba47c25af1126a5397f001bb114f6c464b20493c382c4c7b315e42c24
generated: "2025-12-17T01:21:10.460753309Z"

View File

@@ -4,8 +4,10 @@ version: 1.0.0
description: Argo CD
keywords:
- argo-cd
- delivery
- deployment
home: https://docs.alexlebens.dev/applications/argo-cd/
- gitops
home: https://wiki.alexlebens.dev/s/8a75cf26-b9df-437e-9cc5-2ef47e871a5f
sources:
- https://github.com/argoproj/argo-cd
- https://github.com/argoproj/argo-helm/tree/main/charts/argo-cd
@@ -13,8 +15,7 @@ maintainers:
- name: alexlebens
dependencies:
- name: argo-cd
version: 9.4.15
version: 9.1.8
repository: https://argoproj.github.io/argo-helm
icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/argo-cd.png
# renovate: datasource=github-releases depName=argoproj/argo-cd
appVersion: v3.3.4
appVersion: v3.2.1

View File

@@ -14,11 +14,17 @@ spec:
data:
- secretKey: secret
remoteRef:
conversionStrategy: Default
decodingStrategy: None
key: /authentik/oidc/argocd
metadataPolicy: None
property: secret
- secretKey: client
remoteRef:
conversionStrategy: Default
decodingStrategy: None
key: /authentik/oidc/argocd
metadataPolicy: None
property: client
---
@@ -38,33 +44,45 @@ spec:
data:
- secretKey: ntfy-token
remoteRef:
conversionStrategy: Default
decodingStrategy: None
key: /ntfy/user/cl01tl
metadataPolicy: None
property: token
---
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: argocd-gitea-repo-infrastructure-secret
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: argocd-gitea-repo-infrastructure-secret
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/part-of: {{ .Release.Name }}
spec:
secretStoreRef:
kind: ClusterSecretStore
name: vault
data:
- secretKey: type
remoteRef:
key: /cl01tl/argocd/credentials/repo/infrastructure
property: type
- secretKey: url
remoteRef:
key: /cl01tl/argocd/credentials/repo/infrastructure
property: url
- secretKey: sshPrivateKey
remoteRef:
key: /cl01tl/argocd/credentials/repo/infrastructure
property: sshPrivateKey
# ---
# apiVersion: external-secrets.io/v1
# kind: ExternalSecret
# metadata:
# name: argocd-gitea-repo-infrastructure-secret
# namespace: {{ .Release.Namespace }}
# labels:
# app.kubernetes.io/name: argocd-gitea-repo-infrastructure-secret
# app.kubernetes.io/instance: {{ .Release.Name }}
# app.kubernetes.io/part-of: {{ .Release.Name }}
# spec:
# secretStoreRef:
# kind: ClusterSecretStore
# name: vault
# data:
# - secretKey: type
# remoteRef:
# conversionStrategy: Default
# decodingStrategy: None
# key: /cl01tl/argocd/credentials/repo/infrastructure
# metadataPolicy: None
# property: type
# - secretKey: url
# remoteRef:
# conversionStrategy: Default
# decodingStrategy: None
# key: /cl01tl/argocd/credentials/repo/infrastructure
# metadataPolicy: None
# property: url
# - secretKey: sshPrivateKey
# remoteRef:
# conversionStrategy: Default
# decodingStrategy: None
# key: /cl01tl/argocd/credentials/repo/infrastructure
# metadataPolicy: None
# property: sshPrivateKey

View File

@@ -0,0 +1,28 @@
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: http-route-argocd
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: http-route-argocd
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/part-of: {{ .Release.Name }}
spec:
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: traefik-gateway
namespace: traefik
hostnames:
- argocd.alexlebens.net
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- group: ''
kind: Service
name: argocd-server
port: 80
weight: 100

View File

@@ -1,11 +1,11 @@
argo-cd:
crds:
install: true
keep: true
configs:
cm:
admin.enabled: true
accounts.homepage: apiKey
timeout.reconciliation: 100s
timeout.reconciliation.jitter: 60s
url: https://argocd.alexlebens.net
statusbadge.url: https://argocd.alexlebens.net/
statusbadge.enabled: true
@@ -29,56 +29,26 @@ argo-cd:
rbac:
policy.csv: |
g, ArgoCD Admins, role:admin
g, homepage, role:readonly
cmp:
create: true
plugins:
cdk8s:
init:
command: [cdk8s]
args: [import]
generate:
command: [cdk8s, synth]
args: [--stdout]
discover:
fileName: "*.go"
controller:
replicas: 1
resources:
requests:
cpu: 15m
memory: 1Gi
readinessProbe:
failureThreshold: 3
initialDelaySeconds: 60
periodSeconds: 30
successThreshold: 1
timeoutSeconds: 5
metrics:
enabled: true
serviceMonitor:
enabled: true
rules:
enabled: true
spec:
- alert: ArgoAppMissing
expr: |
absent(argocd_app_info) == 1
for: 15m
labels:
severity: critical
annotations:
summary: "[Argo CD] No reported applications"
description: >
Argo CD has not reported any applications data for the past 15 minutes which
means that it must be down or not functioning properly. This needs to be
resolved for this cloud to continue to maintain state.
- alert: ArgoAppNotSynced
expr: |
argocd_app_info{sync_status!="Synced"} == 1
for: 12h
labels:
severity: warning
annotations:
summary: "[{{`{{$labels.name}}`}}] Application not synchronized"
description: >
The application [{{`{{$labels.name}}`}} has not been synchronized for over
12 hours which means that the state of this cloud has drifted away from the
state inside Git.
dex:
enabled: true
resources:
requests:
cpu: 10m
memory: 64Mi
metrics:
enabled: true
serviceMonitor:
@@ -89,120 +59,70 @@ argo-cd:
enabled: true
redis-ha:
enabled: true
image:
repository: redis
tag: 8.6.1-alpine@sha256:315270d166080f537bbdf1b489b603aaaa213cb55a544acfa51feb7481abb1c0
persistentVolume:
enabled: true
redis:
resources:
requests:
cpu: 1000m
memory: 64Mi
haproxy:
enabled: true
image:
repository: haproxy
tag: 3.3.6-alpine@sha256:744be2dca649a44d490a4c565d36968d19482dd387f1bdd44c168f4322bc6b1e
resources:
requests:
cpu: 10m
memory: 128Mi
metrics:
enabled: true
serviceMonitor:
enabled: true
exporter:
enabled: true
image: ghcr.io/oliver006/redis_exporter
tag: v1.82.0@sha256:6a97d4dd743b533e1f950c677b87d880e44df363c61af3f406fc9e53ed65ee03
serviceMonitor:
enabled: true
prometheusRule:
enabled: true
interval: 30s
rules:
- alert: RedisPodDown
expr: |
redis_up{job="{{ include "redis-ha.fullname" . }}"} == 0
for: 5m
labels:
severity: critical
annotations:
description: Redis pod {{ "{{ $labels.pod }}" }} is down
summary: Redis pod {{ "{{ $labels.pod }}" }} is down
auth: false
redisSecretInit:
enabled: false
server:
replicas: 2
resources:
requests:
cpu: 10m
memory: 64Mi
extensions:
enabled: true
extensionList:
- name: extension-trivy
env:
- name: EXTENSION_URL
value: https://github.com/mziyabo/argocd-trivy-extension/releases/download/v0.2.0/extension-trivy.tar
- name: EXTENSION_CHECKSUM_URL
value: https://github.com/mziyabo/argocd-trivy-extension/releases/download/v0.2.0/extension-trivy_checksums.txt
metrics:
enabled: true
serviceMonitor:
enabled: true
httproute:
enabled: true
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: traefik-gateway
namespace: traefik
hostnames:
- argocd.alexlebens.net
ingress:
enabled: false
repoServer:
replicas: 2
resources:
requests:
cpu: 10m
memory: 64Mi
readinessProbe:
enabled: true
failureThreshold: 3
initialDelaySeconds: 60
periodSeconds: 30
successThreshold: 1
timeoutSeconds: 5
livenessProbe:
enabled: true
failureThreshold: 3
initialDelaySeconds: 60
periodSeconds: 30
successThreshold: 1
timeoutSeconds: 5
extraContainers:
- name: cmp-cdk8s
command:
- /var/run/argocd/argocd-cmp-server
image: ghcr.io/akuity/cdk8s-cmp-typescript:1.0
securityContext:
runAsNonRoot: true
runAsUser: 999
volumeMounts:
- mountPath: /var/run/argocd
name: var-files
- mountPath: /home/argocd/cmp-server/plugins
name: plugins
- mountPath: /home/argocd/cmp-server/config/plugin.yaml
subPath: cdk8s.yaml
name: argocd-cmp-cm
- mountPath: /tmp
name: cmp-tmp
volumes:
- name: argocd-cmp-cm
configMap:
name: argocd-cmp-cm
- name: cmp-tmp
emptyDir: {}
metrics:
enabled: true
serviceMonitor:
enabled: true
applicationSet:
replicas: 2
resources:
requests:
cpu: 10m
memory: 64Mi
metrics:
enabled: true
serviceMonitor:
enabled: true
readinessProbe:
enabled: true
failureThreshold: 3
initialDelaySeconds: 60
periodSeconds: 30
successThreshold: 1
timeoutSeconds: 5
livenessProbe:
enabled: true
failureThreshold: 3
initialDelaySeconds: 60
periodSeconds: 30
successThreshold: 1
timeoutSeconds: 5
readinessProbe:
enabled: true
notifications:
argocdUrl: https://argocd.alexlebens.net
enabled: true
context:
argocdUrl: https://argocd.alexlebens.net
secret:
create: false
name: argocd-notifications-secret
@@ -216,10 +136,6 @@ argo-cd:
headers:
- name: Authorization
value: Bearer $ntfy-token
resources:
requests:
cpu: 10m
memory: 64Mi
livenessProbe:
enabled: true
readinessProbe:

View File

@@ -1,12 +1,12 @@
dependencies:
- name: app-template
repository: https://bjw-s-labs.github.io/helm-charts/
version: 4.6.2
version: 4.5.0
- name: volsync-target
repository: oci://harbor.alexlebens.net/helm-charts
version: 0.8.0
version: 0.3.0
- name: volsync-target
repository: oci://harbor.alexlebens.net/helm-charts
version: 0.8.0
digest: sha256:7ee4cfdf7f908401c39b3cda0cf8783b25dcb9cf93e7c911609bab9e303ec5bf
generated: "2026-03-06T01:05:03.534042627Z"
version: 0.3.0
digest: sha256:88e0d8008795451a64f3a2e4fa4fc120d48cef4badb4305e8e60afbb494352c5
generated: "2025-12-15T18:19:02.989735-06:00"

View File

@@ -7,29 +7,25 @@ keywords:
- books
- podcasts
- audiobooks
home: https://docs.alexlebens.dev/applications/audiobookshelf/
home: https://wiki.alexlebens.dev/s/d4d6719f-cd1c-4b6e-b78e-2d2d7a5097d7
sources:
- https://github.com/advplyr/audiobookshelf
- https://github.com/caronc/apprise
- https://github.com/advplyr/audiobookshelf/pkgs/container/audiobookshelf
- https://github.com/caronc/apprise-api/pkgs/container/apprise
- https://github.com/bjw-s-labs/helm-charts/tree/main/charts/other/app-template
- https://gitea.alexlebens.dev/alexlebens/helm-charts/src/branch/main/charts/volsync-target
maintainers:
- name: alexlebens
dependencies:
- name: app-template
alias: audiobookshelf
repository: https://bjw-s-labs.github.io/helm-charts/
version: 4.6.2
version: 4.5.0
- name: volsync-target
alias: volsync-target-config
version: 0.8.0
version: 0.3.0
repository: oci://harbor.alexlebens.net/helm-charts
- name: volsync-target
alias: volsync-target-metadata
version: 0.8.0
version: 0.3.0
repository: oci://harbor.alexlebens.net/helm-charts
icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/audiobookshelf.png
# renovate: datasource=github-releases depName=advplyr/audiobookshelf
appVersion: 2.33.1
appVersion: 2.31.0

View File

@@ -14,5 +14,8 @@ spec:
data:
- secretKey: ntfy-url
remoteRef:
conversionStrategy: Default
decodingStrategy: None
key: /cl01tl/audiobookshelf/apprise
metadataPolicy: None
property: ntfy-url

View File

@@ -0,0 +1,28 @@
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: http-route-audiobookshelf
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: http-route-audiobookshelf
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/part-of: {{ .Release.Name }}
spec:
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: traefik-gateway
namespace: traefik
hostnames:
- audiobookshelf.alexlebens.net
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- group: ''
kind: Service
name: audiobookshelf
port: 80
weight: 100

View File

@@ -1,52 +1,14 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: audiobookshelf-books-nfs-storage
name: audiobookshelf-nfs-storage
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: audiobookshelf-books-nfs-storage
app.kubernetes.io/name: audiobookshelf-nfs-storage
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/part-of: {{ .Release.Name }}
spec:
volumeName: audiobookshelf-books-nfs-storage
storageClassName: nfs-client
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: audiobookshelf-audiobooks-nfs-storage
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: audiobookshelf-audiobooks-nfs-storage
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/part-of: {{ .Release.Name }}
spec:
volumeName: audiobookshelf-audiobooks-nfs-storage
storageClassName: nfs-client
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: audiobookshelf-podcasts-nfs-storage
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: audiobookshelf-podcasts-nfs-storage
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/part-of: {{ .Release.Name }}
spec:
volumeName: audiobookshelf-podcasts-nfs-storage
volumeName: audiobookshelf-nfs-storage
storageClassName: nfs-client
accessModes:
- ReadWriteMany

View File

@@ -1,10 +1,10 @@
apiVersion: v1
kind: PersistentVolume
metadata:
name: audiobookshelf-books-nfs-storage
name: audiobookshelf-nfs-storage
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: audiobookshelf-books-nfs-storage
app.kubernetes.io/name: audiobookshelf-nfs-storage
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/part-of: {{ .Release.Name }}
spec:
@@ -15,57 +15,7 @@ spec:
accessModes:
- ReadWriteMany
nfs:
path: /volume2/Storage/Books
server: synologybond.alexlebens.net
mountOptions:
- vers=4
- minorversion=1
- noac
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: audiobookshelf-audiobooks-nfs-storage
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: audiobookshelf-audiobooks-nfs-storage
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/part-of: {{ .Release.Name }}
spec:
persistentVolumeReclaimPolicy: Retain
storageClassName: nfs-client
capacity:
storage: 1Gi
accessModes:
- ReadWriteMany
nfs:
path: /volume2/Storage/Audiobooks
server: synologybond.alexlebens.net
mountOptions:
- vers=4
- minorversion=1
- noac
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: audiobookshelf-podcasts-nfs-storage
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: audiobookshelf-podcasts-nfs-storage
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/part-of: {{ .Release.Name }}
spec:
persistentVolumeReclaimPolicy: Retain
storageClassName: nfs-client
capacity:
storage: 1Gi
accessModes:
- ReadWriteMany
nfs:
path: /volume2/Storage/Podcasts
path: /volume2/Storage
server: synologybond.alexlebens.net
mountOptions:
- vers=4

View File

@@ -0,0 +1,19 @@
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: audiobookshelf-apprise
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: audiobookshelf-apprise
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/part-of: {{ .Release.Name }}
spec:
endpoints:
- port: apprise
interval: 30s
scrapeTimeout: 15s
path: /metrics
selector:
matchLabels:
app.kubernetes.io/name: audiobookshelf
app.kubernetes.io/instance: {{ .Release.Name }}

View File

@@ -4,29 +4,28 @@ audiobookshelf:
type: deployment
replicas: 1
strategy: Recreate
pod:
securityContext:
fsGroup: 1000
fsGroupChangePolicy: OnRootMismatch
revisionHistoryLimit: 3
containers:
main:
image:
repository: ghcr.io/advplyr/audiobookshelf
tag: 2.33.1@sha256:a4a5841bba093d81e5f4ad1eaedb4da3fda6dbb2528c552349da50ad1f7ae708
tag: 2.31.0
pullPolicy: IfNotPresent
env:
- name: TZ
value: America/Chicago
value: US/Central
resources:
requests:
cpu: 10m
memory: 200Mi
memory: 128Mi
apprise-api:
image:
repository: ghcr.io/caronc/apprise
tag: v1.3.2@sha256:1aafc2118b6eae5d70d17831d9a8a52adee7104fd6f2bb018e6421664699c903
repository: caronc/apprise
tag: 1.3.0
pullPolicy: IfNotPresent
env:
- name: TZ
value: America/Chicago
value: US/Central
- name: PGID
value: "1000"
- name: PUID
@@ -42,6 +41,10 @@ audiobookshelf:
secretKeyRef:
name: audiobookshelf-apprise-config
key: ntfy-url
resources:
requests:
cpu: 10m
memory: 128Mi
service:
main:
controller: main
@@ -54,43 +57,13 @@ audiobookshelf:
port: 8000
targetPort: 8000
protocol: HTTP
serviceMonitor:
main:
selector:
matchLabels:
app.kubernetes.io/name: audiobookshelf
app.kubernetes.io/instance: audiobookshelf
serviceName: '{{ include "bjw-s.common.lib.chart.names.fullname" $ }}'
endpoints:
- port: apprise
scheme: http
path: /metrics
interval: 30s
scrapeTimeout: 15s
route:
main:
kind: HTTPRoute
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: traefik-gateway
namespace: traefik
hostnames:
- audiobookshelf.alexlebens.net
rules:
- backendRefs:
- name: audiobookshelf
port: 80
matches:
- path:
type: PathPrefix
value: /
persistence:
config:
forceRename: audiobookshelf-config
storageClass: ceph-block
accessMode: ReadWriteOnce
size: 2Gi
retain: true
advancedMounts:
main:
main:
@@ -101,51 +74,20 @@ audiobookshelf:
storageClass: ceph-block
accessMode: ReadWriteOnce
size: 10Gi
retain: true
advancedMounts:
main:
main:
- path: /metadata
readOnly: false
books:
existingClaim: audiobookshelf-books-nfs-storage
advancedMounts:
main:
main:
- path: /mnt/store/Books
readOnly: false
audiobooks:
existingClaim: audiobookshelf-audiobooks-nfs-storage
existingClaim: audiobookshelf-nfs-storage
advancedMounts:
main:
main:
- path: /mnt/store/Audiobooks
readOnly: false
podcasts:
existingClaim: audiobookshelf-podcasts-nfs-storage
advancedMounts:
main:
main:
- path: /mnt/store/Podcasts
- path: /mnt/store/
readOnly: false
volsync-target-config:
pvcTarget: audiobookshelf-config
local:
enabled: true
schedule: 2 8 * * *
remote:
enabled: true
schedule: 2 9 * * *
external:
enabled: true
schedule: 2 10 * * *
volsync-target-metadata:
pvcTarget: audiobookshelf-metadata
local:
enabled: true
schedule: 4 8 * * *
remote:
enabled: true
schedule: 4 9 * * *
external:
enabled: true
schedule: 4 10 * * *

View File

@@ -1,15 +1,15 @@
dependencies:
- name: authentik
repository: https://charts.goauthentik.io/
version: 2026.2.1
version: 2025.10.3
- name: cloudflared
repository: oci://harbor.alexlebens.net/helm-charts
version: 2.4.0
version: 1.23.2
- name: postgres-cluster
repository: oci://harbor.alexlebens.net/helm-charts
version: 7.10.0
- name: valkey
version: 7.1.3
- name: redis-replication
repository: oci://harbor.alexlebens.net/helm-charts
version: 0.4.0
digest: sha256:8c353c5dad4c3d04d518c1445497f0d1cb64261a4201ae17a2c0874454b807a7
generated: "2026-03-15T20:04:35.99407071Z"
version: 0.5.0
digest: sha256:529f2ddaef6ef3584461ae31e4e3ffcc1146f19ece74ef054a7ddbc7eb36a0d8
generated: "2025-12-17T16:09:03.696627571Z"

View File

@@ -6,31 +6,33 @@ keywords:
- authentik
- sso
- oidc
- ldap
- idp
- authentication
home: https://docs.alexlebens.dev/applications/authentik/
home: https://wiki.alexlebens.dev/s/45ca5171-581f-41d2-b6fb-2b0915029a2d
sources:
- https://github.com/goauthentik/authentik
- https://github.com/cloudflare/cloudflared
- https://github.com/cloudnative-pg/cloudnative-pg
- https://github.com/goauthentik/helm
- https://gitea.alexlebens.dev/alexlebens/helm-charts/src/branch/main/charts/cloudflared
- https://gitea.alexlebens.dev/alexlebens/helm-charts/src/branch/main/charts/postgres-cluster
- https://gitea.alexlebens.dev/alexlebens/helm-charts/src/branch/main/charts/valkey
maintainers:
- name: alexlebens
dependencies:
- name: authentik
version: 2026.2.1
version: 2025.10.3
repository: https://charts.goauthentik.io/
- name: cloudflared
alias: cloudflared
repository: oci://harbor.alexlebens.net/helm-charts
version: 2.4.0
version: 1.23.2
- name: postgres-cluster
alias: postgres-18-cluster
version: 7.10.0
version: 7.1.3
repository: oci://harbor.alexlebens.net/helm-charts
- name: valkey
alias: valkey
version: 0.4.0
- name: redis-replication
version: 0.5.0
repository: oci://harbor.alexlebens.net/helm-charts
icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/authentik.png
# renovate: datasource=github-releases depName=goauthentik/authentik
appVersion: 2025.10.2

View File

@@ -14,5 +14,98 @@ spec:
data:
- secretKey: key
remoteRef:
conversionStrategy: Default
decodingStrategy: None
key: /cl01tl/authentik/key
metadataPolicy: None
property: key
---
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: authentik-cloudflared-secret
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: authentik-cloudflared-secret
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/part-of: {{ .Release.Name }}
spec:
secretStoreRef:
kind: ClusterSecretStore
name: vault
data:
- secretKey: cf-tunnel-token
remoteRef:
conversionStrategy: Default
decodingStrategy: None
key: /cloudflare/tunnels/authentik
metadataPolicy: None
property: token
---
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: authentik-postgresql-18-cluster-backup-secret
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: authentik-postgresql-18-cluster-backup-secret
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/part-of: {{ .Release.Name }}
spec:
secretStoreRef:
kind: ClusterSecretStore
name: vault
data:
- secretKey: ACCESS_KEY_ID
remoteRef:
conversionStrategy: Default
decodingStrategy: None
key: /digital-ocean/home-infra/postgres-backups
metadataPolicy: None
property: access
- secretKey: ACCESS_SECRET_KEY
remoteRef:
conversionStrategy: Default
decodingStrategy: None
key: /digital-ocean/home-infra/postgres-backups
metadataPolicy: None
property: secret
---
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: authentik-postgresql-18-cluster-backup-secret-garage
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: authentik-postgresql-18-cluster-backup-secret-garage
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/part-of: {{ .Release.Name }}
spec:
secretStoreRef:
kind: ClusterSecretStore
name: vault
data:
- secretKey: ACCESS_KEY_ID
remoteRef:
conversionStrategy: Default
decodingStrategy: None
key: /garage/home-infra/postgres-backups
metadataPolicy: None
property: ACCESS_KEY_ID
- secretKey: ACCESS_SECRET_KEY
remoteRef:
conversionStrategy: Default
decodingStrategy: None
key: /garage/home-infra/postgres-backups
metadataPolicy: None
property: ACCESS_SECRET_KEY
- secretKey: ACCESS_REGION
remoteRef:
conversionStrategy: Default
decodingStrategy: None
key: /garage/home-infra/postgres-backups
metadataPolicy: None
property: ACCESS_REGION

View File

@@ -0,0 +1,28 @@
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: http-route-authentik
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: http-route-authentik
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/part-of: {{ .Release.Name }}
spec:
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: traefik-gateway
namespace: traefik
hostnames:
- authentik.alexlebens.net
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- group: ''
kind: Service
name: authentik-server
port: 80
weight: 100

View File

@@ -1,39 +0,0 @@
apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
name: allow-outpost-cross-namespace-access
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: allow-outpost-cross-namespace-access
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/part-of: {{ .Release.Name }}
spec:
from:
- group: gateway.networking.k8s.io
kind: HTTPRoute
namespace: lidarr
- group: gateway.networking.k8s.io
kind: HTTPRoute
namespace: radarr
- group: gateway.networking.k8s.io
kind: HTTPRoute
namespace: radarr-4k
- group: gateway.networking.k8s.io
kind: HTTPRoute
namespace: radarr-anime
- group: gateway.networking.k8s.io
kind: HTTPRoute
namespace: radarr-standup
- group: gateway.networking.k8s.io
kind: HTTPRoute
namespace: sonarr
- group: gateway.networking.k8s.io
kind: HTTPRoute
namespace: sonarr-4k
- group: gateway.networking.k8s.io
kind: HTTPRoute
namespace: sonarr-anime
to:
- group: ""
kind: Service
name: ak-outpost-traefik-proxy-auth

View File

@@ -28,69 +28,87 @@ authentik:
key: password
authentik:
redis:
host: authentik-valkey
host: redis-replication-authentik-master
server:
replicas: 2
resources:
requests:
cpu: 100m
memory: 700Mi
livenessProbe:
failureThreshold: 3
initialDelaySeconds: 15
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 5
readinessProbe:
failureThreshold: 3
initialDelaySeconds: 15
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 5
name: server
replicas: 1
metrics:
enabled: true
serviceMonitor:
enabled: true
route:
main:
enabled: true
hostnames:
- authentik.alexlebens.net
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: traefik-gateway
namespace: traefik
ingress:
enabled: false
worker:
name: worker
replicas: 2
resources:
requests:
cpu: 100m
memory: 512Mi
metrics:
enabled: true
serviceMonitor:
enabled: true
replicas: 1
prometheus:
rules:
enabled: true
postgresql:
enabled: false
redis:
enabled: false
cloudflared:
existingSecretName: authentik-cloudflared-secret
postgres-18-cluster:
mode: recovery
cluster:
storage:
storageClass: local-path
walStorage:
storageClass: local-path
recovery:
method: objectStore
objectStore:
index: 2
destinationPath: s3://postgres-backups/cl01tl/authentik/authentik-postgresql-18-cluster
endpointURL: http://garage-main.garage:3900
index: 1
endpointCredentials: authentik-postgresql-18-cluster-backup-secret-garage
backup:
objectStore:
- name: garage-local
index: 2
destinationBucket: postgres-backups
externalSecretCredentialPath: /garage/home-infra/postgres-backups
destinationPath: s3://postgres-backups/cl01tl/authentik/authentik-postgresql-18-cluster
index: 1
endpointURL: http://garage-main.garage:3900
endpointCredentials: authentik-postgresql-18-cluster-backup-secret-garage
endpointCredentialsIncludeRegion: true
retentionPolicy: "3d"
isWALArchiver: true
# - name: external
# destinationPath: s3://postgres-backups-ce540ddf106d186bbddca68a/cl01tl/authentik/authentik-postgresql-18-cluster
# index: 1
# retentionPolicy: "30d"
# isWALArchiver: false
# - name: garage-remote
# destinationPath: s3://postgres-backups/cl01tl/authentik/authentik-postgresql-18-cluster
# index: 1
# endpointURL: https://garage-ps10rp.boreal-beaufort.ts.net:3900
# endpointCredentials: authentik-postgresql-18-cluster-backup-secret-garage
# retentionPolicy: "30d"
# data:
# compression: bzip2
# jobs: 2
scheduledBackups:
- name: live-backup
suspend: false
immediate: true
schedule: "0 5 14 * * *"
schedule: "0 0 0 * * *"
backupName: garage-local
# - name: daily-backup
# suspend: false
# immediate: true
# schedule: "0 0 0 * * *"
# backupName: external
# - name: weekly-backup
# suspend: false
# immediate: true
# schedule: "0 0 4 * * SAT"
# backupName: garage-remote
redis-replication:
existingSecret:
enabled: false
redisReplication:
clusterSize: 3
redisSentinel:
enabled: true
clusterSize: 3

View File

@@ -1,12 +1,12 @@
dependencies:
- name: app-template
repository: https://bjw-s-labs.github.io/helm-charts/
version: 4.6.2
version: 4.5.0
- name: volsync-target
repository: oci://harbor.alexlebens.net/helm-charts
version: 0.8.0
version: 0.3.0
- name: volsync-target
repository: oci://harbor.alexlebens.net/helm-charts
version: 0.8.0
digest: sha256:f203538010828e77336f3cf39451a1072c90aeb8ece7c173a3476c49883b46d1
generated: "2026-03-06T01:05:24.935421139Z"
version: 0.3.0
digest: sha256:13c950ad5cd6accd192e6768557c0df74af2cd767d2372dc38c1cdb7e1563399
generated: "2025-12-15T18:33:59.961957-06:00"

View File

@@ -5,27 +5,25 @@ description: backrest
keywords:
- backrest
- backup
home: https://docs.alexlebens.dev/applications/backrest/
home: https://wiki.alexlebens.dev/
sources:
- https://github.com/garethgeorge/backrest
- https://github.com/garethgeorge/backrest/pkgs/container/backrest
- https://hub.docker.com/r/garethgeorge/backrest
- https://github.com/bjw-s-labs/helm-charts/tree/main/charts/other/app-template
- https://gitea.alexlebens.dev/alexlebens/helm-charts/src/branch/main/charts/volsync-target
maintainers:
- name: alexlebens
dependencies:
- name: app-template
alias: backrest
repository: https://bjw-s-labs.github.io/helm-charts/
version: 4.6.2
version: 4.5.0
- name: volsync-target
alias: volsync-target-config
version: 0.8.0
version: 0.3.0
repository: oci://harbor.alexlebens.net/helm-charts
- name: volsync-target
alias: volsync-target-data
version: 0.8.0
version: 0.3.0
repository: oci://harbor.alexlebens.net/helm-charts
icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/backrest.png
# renovate: datasource=github-releases depName=garethgeorge/backrest
appVersion: v1.12.1
appVersion: v1.10.1

View File

@@ -0,0 +1,28 @@
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: http-route-backrest
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: http-route-backrest
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/part-of: {{ .Release.Name }}
spec:
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: traefik-gateway
namespace: traefik
hostnames:
- backrest.alexlebens.net
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- group: ''
kind: Service
name: backrest
port: 80
weight: 100

View File

@@ -0,0 +1,14 @@
apiVersion: v1
kind: Service
metadata:
name: garage-ps10rp
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: garage-ps10rp
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/part-of: {{ .Release.Name }}
annotations:
tailscale.com/tailnet-fqdn: garage-ps10rp.boreal-beaufort.ts.net
spec:
externalName: placeholder
type: ExternalName

View File

@@ -7,8 +7,9 @@ backrest:
containers:
main:
image:
repository: ghcr.io/garethgeorge/backrest
tag: v1.12.1@sha256:f4d34bd6fa985d13bdb6c01c5d8727e07708899afa9567d800808357d77b9fb0
repository: garethgeorge/backrest
tag: v1.10.1
pullPolicy: IfNotPresent
env:
- name: TZ
value: America/Chicago
@@ -23,7 +24,7 @@ backrest:
resources:
requests:
cpu: 10m
memory: 80Mi
memory: 256Mi
service:
main:
controller: main
@@ -32,43 +33,13 @@ backrest:
port: 80
targetPort: 9898
protocol: TCP
serviceMonitor:
main:
selector:
matchLabels:
app.kubernetes.io/name: backrest
app.kubernetes.io/instance: backrest
serviceName: '{{ include "bjw-s.common.lib.chart.names.fullname" $ }}'
endpoints:
- port: http
scheme: http
path: /metrics
interval: 300s
scrapeTimeout: 15s
route:
main:
kind: HTTPRoute
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: traefik-gateway
namespace: traefik
hostnames:
- backrest.alexlebens.net
rules:
- backendRefs:
- name: backrest
port: 80
matches:
- path:
type: PathPrefix
value: /
persistence:
data:
forceRename: backrest-data
storageClass: ceph-block
accessMode: ReadWriteOnce
size: 10Gi
retain: true
advancedMounts:
main:
main:
@@ -79,6 +50,7 @@ backrest:
storageClass: ceph-block
accessMode: ReadWriteOnce
size: 1Gi
retain: true
advancedMounts:
main:
main:
@@ -114,23 +86,5 @@ backrest:
readOnly: true
volsync-target-data:
pvcTarget: backrest-data
local:
enabled: true
schedule: 6 8 * * *
remote:
enabled: true
schedule: 6 9 * * *
external:
enabled: true
schedule: 6 10 * * *
volsync-target-config:
pvcTarget: backrest-config
local:
enabled: true
schedule: 8 8 * * *
remote:
enabled: true
schedule: 8 9 * * *
external:
enabled: true
schedule: 8 10 * * *

View File

@@ -1,9 +1,9 @@
dependencies:
- name: app-template
repository: https://bjw-s-labs.github.io/helm-charts/
version: 4.6.2
version: 4.5.0
- name: volsync-target
repository: oci://harbor.alexlebens.net/helm-charts
version: 0.8.0
digest: sha256:ce88e4cd451613c9dbc25d285700970789ff678452ef277f3c8465dbf6157f1f
generated: "2026-03-06T01:05:44.405374459Z"
version: 0.5.0
digest: sha256:cb702f316026bdb487ace1abec56cc3c505376cf14a45528e3e593e4cc7effab
generated: "2025-12-15T19:04:05.574701-06:00"

View File

@@ -4,25 +4,24 @@ version: 1.0.0
description: Bazarr
keywords:
- bazarr
- servarr
- subtitles
home: https://docs.alexlebens.dev/applications/bazarr/
home: https://wiki.alexlebens.dev/s/92784d53-1d43-42fd-b509-f42c73454226
sources:
- https://github.com/morpheus65535/bazarr
- https://github.com/linuxserver/docker-bazarr
- https://github.com/linuxserver/docker-bazarr/pkgs/container/bazarr
- https://github.com/bjw-s-labs/helm-charts/tree/main/charts/other/app-template
- https://gitea.alexlebens.dev/alexlebens/helm-charts/src/branch/main/charts/volsync-target
maintainers:
- name: alexlebens
dependencies:
- name: app-template
alias: bazarr
repository: https://bjw-s-labs.github.io/helm-charts/
version: 4.6.2
version: 4.5.0
- name: volsync-target
alias: volsync-target-config
version: 0.8.0
version: 0.5.0
repository: oci://harbor.alexlebens.net/helm-charts
icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/bazarr.png
# renovate: datasource=github-releases depName=morpheus65535/bazarr
appVersion: 1.5.6
appVersion: 1.5.3

View File

@@ -0,0 +1,28 @@
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: http-route-bazarr
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: http-route-bazarr
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/part-of: {{ .Release.Name }}
spec:
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: traefik-gateway
namespace: traefik
hostnames:
- bazarr.alexlebens.net
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- group: ''
kind: Service
name: bazarr
port: 80
weight: 100

View File

@@ -4,6 +4,7 @@ bazarr:
type: deployment
replicas: 1
strategy: Recreate
revisionHistoryLimit: 3
pod:
securityContext:
runAsUser: 1000
@@ -14,10 +15,11 @@ bazarr:
main:
image:
repository: ghcr.io/linuxserver/bazarr
tag: 1.5.6@sha256:05f9d5b24884f37120453dc1a008a47be244eebec32099ae1bd29032e75b67aa
tag: 1.5.3@sha256:648f694532a3a53d8cf78bc888919ef538659bad41af4c680b0427ad1047d171
pullPolicy: IfNotPresent
env:
- name: TZ
value: America/Chicago
value: US/Central
- name: PUID
value: 1000
- name: PGID
@@ -34,30 +36,13 @@ bazarr:
port: 80
targetPort: 6767
protocol: HTTP
route:
main:
kind: HTTPRoute
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: traefik-gateway
namespace: traefik
hostnames:
- bazarr.alexlebens.net
rules:
- backendRefs:
- name: bazarr
port: 80
matches:
- path:
type: PathPrefix
value: /
persistence:
config:
forceRename: bazarr-config
storageClass: ceph-block
accessMode: ReadWriteOnce
size: 5Gi
retain: true
advancedMounts:
main:
main:
@@ -77,12 +62,3 @@ volsync-target-config:
runAsGroup: 1000
fsGroup: 1000
fsGroupChangePolicy: OnRootMismatch
local:
enabled: true
schedule: 10 8 * * *
remote:
enabled: true
schedule: 10 9 * * *
external:
enabled: true
schedule: 10 10 * * *

View File

@@ -1,9 +1,9 @@
dependencies:
- name: app-template
repository: https://bjw-s-labs.github.io/helm-charts/
version: 4.6.2
- name: valkey
version: 4.5.0
- name: redis-replication
repository: oci://harbor.alexlebens.net/helm-charts
version: 0.4.0
digest: sha256:a5b0099261d772b24a302a106d106cfa82ac07fa14564141e00cf107d708e859
generated: "2026-03-09T23:06:16.853255429Z"
version: 0.5.0
digest: sha256:a7840240d52d7c66aa2e542132e32907dd0c48d3051eb15190a209215cbd4dce
generated: "2025-12-15T20:06:31.995318697Z"

View File

@@ -5,23 +5,20 @@ description: Blocky
keywords:
- blocky
- dns
home: https://docs.alexlebens.dev/applications/blocky/
home: https://wiki.alexlebens.dev/s/cf70113d-20bc-48ad-afb8-1e22ed3fd62a
sources:
- https://github.com/0xERR0R/blocky
- https://github.com/0xERR0R/blocky/pkgs/container/blocky
- https://hub.docker.com/r/spx01/blocky
- https://github.com/bjw-s-labs/helm-charts/tree/main/charts/other/app-template
- https://gitea.alexlebens.dev/alexlebens/helm-charts/src/branch/main/charts/valkey
maintainers:
- name: alexlebens
dependencies:
- name: app-template
alias: blocky
repository: https://bjw-s-labs.github.io/helm-charts/
version: 4.6.2
- name: valkey
alias: valkey
version: 0.4.0
version: 4.5.0
- name: redis-replication
version: 0.5.0
repository: oci://harbor.alexlebens.net/helm-charts
icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/blocky.png
# renovate: datasource=github-releases depName=0xerr0r/blocky
appVersion: v0.29.0
appVersion: v0.28.2

View File

@@ -0,0 +1,19 @@
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: blocky
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: blocky
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/part-of: {{ .Release.Name }}
spec:
selector:
matchLabels:
app.kubernetes.io/name: blocky
app.kubernetes.io/instance: {{ .Release.Name }}
endpoints:
- port: metrics
interval: 30s
scrapeTimeout: 10s
path: /metrics

View File

@@ -4,18 +4,20 @@ blocky:
type: deployment
replicas: 3
strategy: RollingUpdate
revisionHistoryLimit: 3
containers:
main:
image:
repository: ghcr.io/0xerr0r/blocky
tag: v0.29.0@sha256:a6d99f323d3036a99a3767a52ad612f4d8f3f31167492bfc14d4ea57b24cdfd0
tag: v0.28.2@sha256:5f84a54e4ee950c4ab21db905b7497476ece2f4e1a376d23ab8c4855cabddcba
pullPolicy: IfNotPresent
env:
- name: TZ
value: America/Chicago
value: US/Central
resources:
requests:
cpu: 10m
memory: 90Mi
memory: 128Mi
configMaps:
config:
enabled: true
@@ -94,11 +96,12 @@ blocky:
cl01tl-endpoint IN A 10.232.1.22
cl01tl-endpoint IN A 10.232.1.23
cl01tl-gateway IN A 10.232.1.200
traefik-cl01tl IN A 10.232.1.21
blocky IN A 10.232.1.22
plex-lb IN A 10.232.1.23
;; Application Names
actual IN CNAME traefik-cl01tl
alertmanager IN CNAME traefik-cl01tl
@@ -108,42 +111,38 @@ blocky:
authentik IN CNAME traefik-cl01tl
backrest IN CNAME traefik-cl01tl
bazarr IN CNAME traefik-cl01tl
booklore IN CNAME traefik-cl01tl
ceph IN CNAME traefik-cl01tl
code-server IN CNAME traefik-cl01tl
dawarich IN CNAME traefik-cl01tl
directus IN CNAME traefik-cl01tl
excalidraw IN CNAME traefik-cl01tl
feishin IN CNAME traefik-cl01tl
foldergram IN CNAME traefik-cl01tl
ephemera IN CNAME traefik-cl01tl
garage-s3 IN CNAME traefik-cl01tl
garage-webui IN CNAME traefik-cl01tl
gatus IN CNAME traefik-cl01tl
gitea IN CNAME traefik-cl01tl
grafana IN CNAME traefik-cl01tl
grimmory IN CNAME traefik-cl01tl
harbor IN CNAME traefik-cl01tl
headlamp IN CNAME traefik-cl01tl
home IN CNAME traefik-cl01tl
home-assistant IN CNAME traefik-cl01tl
home-assistant-code-server IN CNAME traefik-cl01tl
houndarr IN CNAME traefik-cl01tl
hubble IN CNAME traefik-cl01tl
hubble IN CNAME cl01tl-gateway
huntarr IN CNAME traefik-cl01tl
immich IN CNAME traefik-cl01tl
jellyfin IN CNAME traefik-cl01tl
jellyfin-vue IN CNAME traefik-cl01tl
jellystat IN CNAME traefik-cl01tl
kiwix IN CNAME traefik-cl01tl
komodo IN CNAME traefik-cl01tl
languagetool IN CNAME traefik-cl01tl
lidarr IN CNAME traefik-cl01tl
lidatube IN CNAME traefik-cl01tl
listenarr IN CNAME traefik-cl01tl
mail IN CNAME traefik-cl01tl
medialyze IN CNAME traefik-cl01tl
movie-roulette IN CNAME traefik-cl01tl
music-grabber IN CNAME traefik-cl01tl
navidrome IN CNAME traefik-cl01tl
n8n IN CNAME traefik-cl01tl
ntfy IN CNAME traefik-cl01tl
objects IN CNAME traefik-cl01tl
ollama IN CNAME traefik-cl01tl
omni-tools IN CNAME traefik-cl01tl
overseerr IN CNAME traefik-cl01tl
photoview IN CNAME traefik-cl01tl
plex IN CNAME traefik-cl01tl
postiz IN CNAME traefik-cl01tl
@@ -157,18 +156,17 @@ blocky:
radarr-standup IN CNAME traefik-cl01tl
searxng IN CNAME traefik-cl01tl
seerr IN CNAME traefik-cl01tl
shelfmark IN CNAME traefik-cl01tl
slskd IN CNAME traefik-cl01tl
sonarr IN CNAME traefik-cl01tl
sonarr-4k IN CNAME traefik-cl01tl
sonarr-anime IN CNAME traefik-cl01tl
stalwart IN CNAME traefik-cl01tl
tautulli IN CNAME traefik-cl01tl
tdarr IN CNAME traefik-cl01tl
tubearchivist IN CNAME traefik-cl01tl
vault IN CNAME traefik-cl01tl
whodb IN CNAME traefik-cl01tl
yamtrack IN CNAME traefik-cl01tl
yubal IN CNAME traefik-cl01tl
blocking:
denylists:
@@ -184,53 +182,35 @@ blocky:
- https://v.firebog.net/hosts/Prigent-Ads.txt
mal:
- https://v.firebog.net/hosts/Prigent-Crypto.txt
- https://osint.digitalside.it/Threat-Intel/lists/latestdomains.txt
pro:
- https://raw.githubusercontent.com/hagezi/dns-blocklists/main/wildcard/pro.plus.txt
oisd:
- https://big.oisd.nl/domainswild
allowlists:
sus:
- |
*.alexlebens.net
*.alexlebens.dev
*.boreal-beaufort.ts.net
*.discord.com
cdn.trackjs.com
ads:
- |
*.alexlebens.net
*.alexlebens.dev
*.boreal-beaufort.ts.net
*.discord.com
cdn.trackjs.com
priv:
- |
*.alexlebens.net
*.alexlebens.dev
*.boreal-beaufort.ts.net
*.discord.com
cdn.trackjs.com
mal:
- |
*.alexlebens.net
*.alexlebens.dev
*.boreal-beaufort.ts.net
*.discord.com
cdn.trackjs.com
pro:
- |
*.alexlebens.net
*.alexlebens.dev
*.boreal-beaufort.ts.net
*.discord.com
cdn.trackjs.com
oisd:
- |
*.alexlebens.net
*.alexlebens.dev
*.boreal-beaufort.ts.net
*.discord.com
cdn.trackjs.com
clientGroupsBlock:
default:
- sus
@@ -238,7 +218,6 @@ blocky:
- priv
- mal
- pro
- oisd
blockType: zeroIp
blockTTL: 1m
loading:
@@ -262,7 +241,7 @@ blocky:
cacheTimeNegative: 30m
redis:
address: blocky-valkey.blocky:6379
address: redis-replication-blocky-master.blocky:6379
required: true
prometheus:
@@ -310,19 +289,6 @@ blocky:
port: 4000
targetPort: 4000
protocol: TCP
serviceMonitor:
main:
selector:
matchLabels:
app.kubernetes.io/name: blocky
app.kubernetes.io/instance: blocky
serviceName: '{{ include "bjw-s.common.lib.chart.names.fullname" $ }}'
endpoints:
- port: metrics
scheme: http
path: /metrics
interval: 30s
scrapeTimeout: 10s
persistence:
config:
enabled: true
@@ -335,3 +301,10 @@ blocky:
readOnly: true
mountPropagation: None
subPath: config.yml
redis-replication:
existingSecret:
enabled: false
redisReplication:
clusterSize: 3
redisSentinel:
enabled: false

View File

@@ -0,0 +1,15 @@
dependencies:
- name: app-template
repository: https://bjw-s-labs.github.io/helm-charts/
version: 4.5.0
- name: mariadb-cluster
repository: https://helm.mariadb.com/mariadb-operator
version: 25.10.2
- name: volsync-target
repository: oci://harbor.alexlebens.net/helm-charts
version: 0.5.0
- name: volsync-target
repository: oci://harbor.alexlebens.net/helm-charts
version: 0.5.0
digest: sha256:6981b2c060c19bac6517578bd9b5b11a300a4deb431110bf90da317237a4a252
generated: "2025-12-15T19:15:49.886575-06:00"

View File

@@ -0,0 +1,32 @@
apiVersion: v2
name: booklore
version: 1.0.0
description: booklore
keywords:
- booklore
- books
home: https://wiki.alexlebens.dev/
sources:
- https://github.com/booklore-app/BookLore
- https://github.com/booklore-app/booklore/pkgs/container/booklore
- https://github.com/bjw-s-labs/helm-charts/tree/main/charts/other/app-template
maintainers:
- name: alexlebens
dependencies:
- name: app-template
alias: booklore
repository: https://bjw-s-labs.github.io/helm-charts/
version: 4.5.0
- name: mariadb-cluster
version: 25.10.2
repository: https://helm.mariadb.com/mariadb-operator
- name: volsync-target
alias: volsync-target-config
version: 0.5.0
repository: oci://harbor.alexlebens.net/helm-charts
- name: volsync-target
alias: volsync-target-data
version: 0.5.0
repository: oci://harbor.alexlebens.net/helm-charts
icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/booklore.png
appVersion: v1.13.2

View File

@@ -1,10 +1,10 @@
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: grimmory-database-secret
name: booklore-database-secret
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: grimmory-database-secret
app.kubernetes.io/name: booklore-database-secret
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/part-of: {{ .Release.Name }}
spec:
@@ -14,17 +14,20 @@ spec:
data:
- secretKey: password
remoteRef:
key: /cl01tl/grimmory/database
conversionStrategy: Default
decodingStrategy: None
key: /cl01tl/booklore/database
metadataPolicy: None
property: password
---
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: grimmory-data-replication-secret
name: booklore-data-replication-secret
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: grimmory-data-replication-secret
app.kubernetes.io/name: booklore-data-replication-secret
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/part-of: {{ .Release.Name }}
spec:
@@ -34,17 +37,20 @@ spec:
data:
- secretKey: psk.txt
remoteRef:
key: /cl01tl/grimmory/replication
conversionStrategy: Default
decodingStrategy: None
key: /cl01tl/booklore/replication
metadataPolicy: None
property: psk.txt
---
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: grimmory-mariadb-cluster-backup-secret-external
name: booklore-mariadb-cluster-backup-secret-external
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: grimmory-mariadb-cluster-backup-secret-external
app.kubernetes.io/name: booklore-mariadb-cluster-backup-secret-external
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/part-of: {{ .Release.Name }}
spec:
@@ -54,21 +60,27 @@ spec:
data:
- secretKey: access
remoteRef:
conversionStrategy: Default
decodingStrategy: None
key: /digital-ocean/home-infra/mariadb-backups
metadataPolicy: None
property: access
- secretKey: secret
remoteRef:
conversionStrategy: Default
decodingStrategy: None
key: /digital-ocean/home-infra/mariadb-backups
metadataPolicy: None
property: secret
---
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: grimmory-mariadb-cluster-backup-secret-garage
name: booklore-mariadb-cluster-backup-secret-garage
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: grimmory-mariadb-cluster-backup-secret-garage
app.kubernetes.io/name: booklore-mariadb-cluster-backup-secret-garage
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/part-of: {{ .Release.Name }}
spec:
@@ -78,9 +90,15 @@ spec:
data:
- secretKey: access
remoteRef:
conversionStrategy: Default
decodingStrategy: None
key: /garage/home-infra/mariadb-backups
metadataPolicy: None
property: access
- secretKey: secret
remoteRef:
conversionStrategy: Default
decodingStrategy: None
key: /garage/home-infra/mariadb-backups
metadataPolicy: None
property: secret

View File

@@ -0,0 +1,28 @@
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: http-route-booklore
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: http-route-booklore
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/part-of: {{ .Release.Name }}
spec:
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: traefik-gateway
namespace: traefik
hostnames:
- booklore.alexlebens.net
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- group: ''
kind: Service
name: booklore
port: 80
weight: 100

View File

@@ -1,11 +1,11 @@
apiVersion: v1
kind: Namespace
metadata:
name: grimmory
name: booklore
annotations:
volsync.backube/privileged-movers: "true"
labels:
app.kubernetes.io/name: grimmory
app.kubernetes.io/name: booklore
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/part-of: {{ .Release.Name }}
pod-security.kubernetes.io/audit: privileged

View File

@@ -1,14 +1,14 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: grimmory-books-nfs-storage
name: booklore-books-nfs-storage
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: grimmory-books-nfs-storage
app.kubernetes.io/name: booklore-books-nfs-storage
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/part-of: {{ .Release.Name }}
spec:
volumeName: grimmory-books-nfs-storage
volumeName: booklore-books-nfs-storage
storageClassName: nfs-client
accessModes:
- ReadWriteMany
@@ -20,14 +20,14 @@ spec:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: grimmory-books-import-nfs-storage
name: booklore-books-import-nfs-storage
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: grimmory-books-import-nfs-storage
app.kubernetes.io/name: booklore-books-import-nfs-storage
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/part-of: {{ .Release.Name }}
spec:
volumeName: grimmory-books-import-nfs-storage
volumeName: booklore-books-import-nfs-storage
storageClassName: nfs-client
accessModes:
- ReadWriteMany

View File

@@ -1,10 +1,10 @@
apiVersion: v1
kind: PersistentVolume
metadata:
name: grimmory-books-nfs-storage
name: booklore-books-nfs-storage
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: grimmory-books-nfs-storage
app.kubernetes.io/name: booklore-books-nfs-storage
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/part-of: {{ .Release.Name }}
spec:
@@ -26,10 +26,10 @@ spec:
apiVersion: v1
kind: PersistentVolume
metadata:
name: grimmory-books-import-nfs-storage
name: booklore-books-import-nfs-storage
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: grimmory-books-import-nfs-storage
app.kubernetes.io/name: booklore-books-import-nfs-storage
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/part-of: {{ .Release.Name }}
spec:

View File

@@ -0,0 +1,15 @@
apiVersion: volsync.backube/v1alpha1
kind: ReplicationDestination
metadata:
name: booklore-data-replication-destination
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: booklore-data-replication-destination
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/part-of: {{ .Release.Name }}
spec:
rsyncTLS:
copyMethod: Direct
accessModes: ["ReadWriteMany"]
destinationPVC: booklore-books-nfs-storage
keySecret: booklore-data-replication-secret

View File

@@ -0,0 +1,17 @@
apiVersion: volsync.backube/v1alpha1
kind: ReplicationSource
metadata:
name: booklore-data-replication-source
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: booklore-data-replication-source
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/part-of: {{ .Release.Name }}
spec:
sourcePVC: booklore-data
trigger:
schedule: "0 0 * * *"
rsyncTLS:
keySecret: booklore-data-replication-secret
address: volsync-rsync-tls-dst-booklore-data-replication-destination
copyMethod: Snapshot

View File

@@ -0,0 +1,14 @@
apiVersion: v1
kind: Service
metadata:
name: garage-ps10rp
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: garage-ps10rp
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/part-of: {{ .Release.Name }}
annotations:
tailscale.com/tailnet-fqdn: garage-ps10rp.boreal-beaufort.ts.net
spec:
externalName: placeholder
type: ExternalName

View File

@@ -1,42 +1,36 @@
grimmory:
booklore:
controllers:
main:
type: deployment
replicas: 1
strategy: Recreate
pod:
securityContext:
fsGroup: 1000
fsGroupChangePolicy: OnRootMismatch
revisionHistoryLimit: 3
containers:
main:
image:
repository: ghcr.io/grimmory-tools/grimmory
tag: v2.3.0@sha256:9014247f591074529894f81115ca40f899db697e89f72c2fe91ec530e3f19597
repository: ghcr.io/booklore-app/booklore
tag: v1.13.2
pullPolicy: IfNotPresent
env:
- name: TZ
value: America/Chicago
- name: USER_ID
value: 1000
- name: GROUP_ID
value: 1000
- name: DATABASE_URL
value: jdbc:mariadb://grimmory-mariadb-cluster-primary.grimmory:3306/booklore
value: jdbc:mariadb://booklore-mariadb-cluster-primary.booklore:3306/booklore
- name: DATABASE_USERNAME
value: grimmory
value: booklore
- name: DATABASE_PASSWORD
valueFrom:
secretKeyRef:
name: grimmory-database-secret
name: booklore-database-secret
key: password
- name: GRIMMORY_PORT
- name: BOOKLORE_PORT
value: 6060
- name: SWAGGER_ENABLED
value: false
resources:
requests:
cpu: 10m
memory: 1Gi
cpu: 50m
memory: 128Mi
service:
main:
controller: main
@@ -45,35 +39,29 @@ grimmory:
port: 80
targetPort: 6060
protocol: HTTP
route:
main:
kind: HTTPRoute
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: traefik-gateway
namespace: traefik
hostnames:
- grimmory.alexlebens.net
rules:
- backendRefs:
- name: grimmory
port: 80
matches:
- path:
type: PathPrefix
value: /
persistence:
config:
forceRename: grimmory-config
forceRename: booklore-config
storageClass: ceph-block
accessMode: ReadWriteOnce
size: 5Gi
retain: true
advancedMounts:
main:
main:
- path: /app/data
readOnly: false
data:
forceRename: booklore-data
storageClass: ceph-block
accessMode: ReadWriteOnce
size: 10Gi
retain: true
advancedMounts:
main:
main:
- path: /data
readOnly: false
books-import:
type: emptyDir
advancedMounts:
@@ -81,15 +69,8 @@ grimmory:
main:
- path: /bookdrop
readOnly: false
data:
existingClaim: grimmory-books-nfs-storage
advancedMounts:
main:
main:
- path: /data
readOnly: false
ingest:
existingClaim: grimmory-books-import-nfs-storage
existingClaim: booklore-books-import-nfs-storage
advancedMounts:
main:
main:
@@ -99,28 +80,13 @@ mariadb-cluster:
mariadb:
rootPasswordSecretKeyRef:
generate: false
name: grimmory-database-secret
name: booklore-database-secret
key: password
storage:
size: 5Gi
replicas: 3
galera:
enabled: true
bootstrapFrom:
s3:
bucket: mariadb-backups-b230a2f5aecf080a4b372c08
prefix: cl01tl/grimmory
endpoint: nyc3.digitaloceanspaces.com
region: us-east-1
accessKeyIdSecretKeyRef:
name: grimmory-mariadb-cluster-backup-secret-external
key: access
secretAccessKeySecretKeyRef:
name: grimmory-mariadb-cluster-backup-secret-external
key: secret
tls:
enabled: true
backupContentType: Physical
databases:
- name: booklore
characterSet: utf8
@@ -128,22 +94,21 @@ mariadb-cluster:
cleanupPolicy: Delete
requeueInterval: 10h
users:
- name: grimmory
- name: booklore
passwordSecretKeyRef:
name: grimmory-database-secret
name: booklore-database-secret
key: password
host: '%'
maxUserConnections: 100
cleanupPolicy: Delete
requeueInterval: 10h
retryInterval: 30s
grants:
- name: grimmory
- name: booklore
privileges:
- "ALL PRIVILEGES"
database: "booklore"
table: "*"
username: grimmory
username: booklore
grantOption: true
host: '%'
cleanupPolicy: Delete
@@ -161,14 +126,14 @@ mariadb-cluster:
storage:
s3:
bucket: mariadb-backups-b230a2f5aecf080a4b372c08
prefix: cl01tl/grimmory
prefix: cl01tl/booklore
endpoint: nyc3.digitaloceanspaces.com
region: us-east-1
accessKeyIdSecretKeyRef:
name: grimmory-mariadb-cluster-backup-secret-external
name: booklore-mariadb-cluster-backup-secret-external
key: access
secretAccessKeySecretKeyRef:
name: grimmory-mariadb-cluster-backup-secret-external
name: booklore-mariadb-cluster-backup-secret-external
key: secret
tls:
enabled: true
@@ -183,14 +148,14 @@ mariadb-cluster:
storage:
s3:
bucket: mariadb-backups
prefix: cl01tl/grimmory
prefix: cl01tl/booklore
endpoint: garage-ps10rp.boreal-beaufort.ts.net:3900
region: us-east-1
accessKeyIdSecretKeyRef:
name: grimmory-mariadb-cluster-backup-secret-garage
name: booklore-mariadb-cluster-backup-secret-garage
key: access
secretAccessKeySecretKeyRef:
name: grimmory-mariadb-cluster-backup-secret-garage
name: booklore-mariadb-cluster-backup-secret-garage
key: secret
tls:
enabled: true
@@ -205,26 +170,25 @@ mariadb-cluster:
storage:
s3:
bucket: mariadb-backups
prefix: cl01tl/grimmory
prefix: cl01tl/booklore
endpoint: garage-main.garage:3900
region: us-east-1
accessKeyIdSecretKeyRef:
name: grimmory-mariadb-cluster-backup-secret-garage
name: booklore-mariadb-cluster-backup-secret-garage
key: access
secretAccessKeySecretKeyRef:
name: grimmory-mariadb-cluster-backup-secret-garage
name: booklore-mariadb-cluster-backup-secret-garage
key: secret
volsync-target-config:
pvcTarget: grimmory-config
moverSecurityContext:
fsGroup: 1000
fsGroupChangePolicy: OnRootMismatch
pvcTarget: booklore-config
volsync-target-data:
pvcTarget: booklore-data
local:
enabled: true
schedule: 12 8 * * *
restic:
cacheCapacity: 10Gi
remote:
enabled: true
schedule: 12 9 * * *
restic:
cacheCapacity: 10Gi
external:
enabled: true
schedule: 12 10 * * *
restic:
cacheCapacity: 10Gi

View File

@@ -1,6 +1,6 @@
dependencies:
- name: cert-manager
repository: https://charts.jetstack.io
version: v1.20.0
digest: sha256:1543bd17649cb32982de3cce017fcbed1b44c41d50b76c6471b266f33e261c29
generated: "2026-03-10T16:06:49.332999536Z"
version: v1.19.2
digest: sha256:b02bda9b9f2fc886af11d017a27a5761513defee603f9e3aa1d7add2749b925c
generated: "2025-12-10T15:01:57.196895547Z"

View File

@@ -14,8 +14,7 @@ maintainers:
- name: alexlebens
dependencies:
- name: cert-manager
version: v1.20.0
version: v1.19.2
repository: https://charts.jetstack.io
icon: https://raw.githubusercontent.com/walkxcode/dashboard-icons/main/png/cert-manager.png
# renovate: datasource=github-releases depName=cert-manager/cert-manager
appVersion: v1.20.0
appVersion: v1.19.2

View File

@@ -1,6 +1,6 @@
dependencies:
- name: cilium
repository: https://helm.cilium.io/
version: 1.19.2
digest: sha256:11f8eef4733b70c2b9a91ce39fe3c1ea1ad3fa3c46750efb015e03ff6ea3655b
generated: "2026-03-24T03:46:51.217460551Z"
version: 1.18.5
digest: sha256:b997853961dca1ed43d32b58b17e6e592581eb555db0b1457b168251cf3aaa45
generated: "2025-12-17T16:05:05.870297681Z"

View File

@@ -15,8 +15,7 @@ maintainers:
- name: alexlebens
dependencies:
- name: cilium
version: 1.19.2
version: 1.18.5
repository: https://helm.cilium.io/
icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/cilium.png
# renovate: datasource=github-releases depName=cilium/cilium
appVersion: 1.19.1
appVersion: 1.18.4

View File

@@ -1,4 +1,4 @@
# apiVersion: cilium.io/v2
# apiVersion: cilium.io/v2alpha1
# kind: CiliumBGPAdvertisement
# metadata:
# name: cilium-bgp-advertisements

View File

@@ -1,4 +1,4 @@
# apiVersion: cilium.io/v2
# apiVersion: cilium.io/v2alpha1
# kind: CiliumBGPClusterConfig
# metadata:
# name: cilium-bgp

View File

@@ -1,4 +1,4 @@
# apiVersion: cilium.io/v2
# apiVersion: cilium.io/v2alpha1
# kind: CiliumBGPPeerConfig
# metadata:
# name: cilium-peer

View File

@@ -1,4 +1,4 @@
apiVersion: cilium.io/v2
apiVersion: "cilium.io/v2alpha1"
kind: CiliumLoadBalancerIPPool
metadata:
name: default-ip-pool
@@ -11,9 +11,11 @@ spec:
blocks:
- start: "10.232.1.21"
stop: "10.232.1.23"
- start: "10.232.2.21"
stop: "10.232.2.23"
---
apiVersion: cilium.io/v2
apiVersion: "cilium.io/v2alpha1"
kind: CiliumLoadBalancerIPPool
metadata:
name: bgp-ip-pool

View File

@@ -1,24 +1,28 @@
# apiVersion: gateway.networking.k8s.io/v1
# kind: Gateway
# metadata:
# name: cilium-tls-gateway
# name: tls-gateway
# namespace: {{ .Release.Namespace }}
# labels:
# app.kubernetes.io/name: cilium-tls-gateway
# app.kubernetes.io/name: tls-gateway
# app.kubernetes.io/instance: {{ .Release.Name }}
# app.kubernetes.io/part-of: {{ .Release.Name }}
# annotations:
# cert-manager.io/cluster-issuer: letsencrypt-issuer
# spec:
# addresses:
# - type: IPAddress
# value: 10.232.1.23
# gatewayClassName: cilium
# listeners:
# - allowedRoutes:
# namespaces:
# from: All
# hostname: '*.alexlebens.net'
# name: http
# port: 80
# protocol: HTTP
# - allowedRoutes:
# namespaces:
# from: All
# hostname: '*.alexlebens.net'
# name: https
# port: 443
# protocol: HTTPS
@@ -29,17 +33,3 @@
# name: https-gateway-cert
# namespace: kube-system
# mode: Terminate
# - allowedRoutes:
# namespaces:
# from: All
# hostname: 'alexlebens.net'
# name: https-domain
# port: 443
# protocol: HTTPS
# tls:
# certificateRefs:
# - group: ''
# kind: Secret
# name: https-gateway-cert
# namespace: kube-system
# mode: Terminate

View File

@@ -1,10 +1,10 @@
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: hubble
name: http-route-hubble
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: hubble
app.kubernetes.io/name: http-route-hubble
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/part-of: {{ .Release.Name }}
spec:

View File

@@ -35,9 +35,8 @@ cilium:
enabled: true
routerIDAllocation:
mode: "default"
bpf:
hostLegacyRouting: true
devices: end0 enp6s0
enableK8sEndpointSlice: true
ciliumEndpointSlice:
enabled: true
ingressController:
@@ -46,8 +45,6 @@ cilium:
enabled: true
enableAlpn: true
enableAppProtocol: true
gatewayClass:
create: auto
externalIPs:
enabled: true
socketLB:
@@ -63,7 +60,7 @@ cilium:
method: cronJob
relay:
enabled: true
prometheus:
metrics:
serviceMonitor:
enabled: true
ui:

View File

@@ -1,9 +1,9 @@
dependencies:
- name: cloudnative-pg
repository: https://cloudnative-pg.io/charts/
version: 0.27.1
version: 0.27.0
- name: plugin-barman-cloud
repository: https://cloudnative-pg.io/charts/
version: 0.5.0
digest: sha256:e7089ffd089cae87529e28f0e71302b9fc4a869b389cbb6628f1c559644a3a10
generated: "2026-02-05T19:36:19.473447121Z"
version: 0.3.1
digest: sha256:14aa30b7bf75571b03bda19af68cd50c1e7908b883351b196a260609a5b85551
generated: "2025-12-10T19:25:17.952954019Z"

View File

@@ -16,11 +16,10 @@ maintainers:
- name: alexlebens
dependencies:
- name: cloudnative-pg
version: 0.27.1
version: 0.27.0
repository: https://cloudnative-pg.io/charts/
- name: plugin-barman-cloud
version: 0.5.0
version: 0.3.1
repository: https://cloudnative-pg.io/charts/
icon: https://avatars.githubusercontent.com/u/100373852?s=200&v=4
# renovate: datasource=github-releases depName=cloudnative-pg/cloudnative-pg
appVersion: 1.28.1
appVersion: 1.28.0

View File

@@ -7,10 +7,10 @@ plugin-barman-cloud:
image:
registry: ghcr.io
repository: cloudnative-pg/plugin-barman-cloud
tag: v0.11.0
tag: v0.9.0
sidecarImage:
registry: ghcr.io
repository: cloudnative-pg/plugin-barman-cloud-sidecar
tag: v0.11.0
tag: v0.9.0
crds:
create: true

View File

@@ -1,12 +1,12 @@
dependencies:
- name: app-template
repository: https://bjw-s-labs.github.io/helm-charts/
version: 4.6.2
version: 4.5.0
- name: cloudflared
repository: oci://harbor.alexlebens.net/helm-charts
version: 2.4.0
version: 1.23.2
- name: volsync-target
repository: oci://harbor.alexlebens.net/helm-charts
version: 0.8.0
digest: sha256:dee0f52096efc543f4db3a5dc2732fd37ae9b7950b264e399a6e74c2f3e7cee6
generated: "2026-03-09T22:04:00.58415637Z"
version: 0.5.0
digest: sha256:bd1cbd66ccb360978a342ee218bfb01006a486fb85c5714acd593b9e1389b151
generated: "2025-12-15T21:50:58.968382-06:00"

View File

@@ -19,14 +19,14 @@ dependencies:
- name: app-template
alias: code-server
repository: https://bjw-s-labs.github.io/helm-charts/
version: 4.6.2
version: 4.5.0
- name: cloudflared
alias: cloudflared
repository: oci://harbor.alexlebens.net/helm-charts
version: 2.4.0
version: 1.23.2
- name: volsync-target
alias: volsync-target-config
version: 0.8.0
version: 0.5.0
repository: oci://harbor.alexlebens.net/helm-charts
icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/visual-studio-code.png
# renovate: datasource=github-releases depName=linuxserver/docker-code-server
appVersion: 4.108.1
appVersion: 4.106.3

View File

@@ -26,3 +26,26 @@ spec:
key: /cl01tl/code-server/auth
metadataPolicy: None
property: SUDO_PASSWORD
---
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: code-server-cloudflared-secret
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: code-server-cloudflared-secret
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/part-of: {{ .Release.Name }}
spec:
secretStoreRef:
kind: ClusterSecretStore
name: vault
data:
- secretKey: cf-tunnel-token
remoteRef:
conversionStrategy: Default
decodingStrategy: None
key: /cloudflare/tunnels/codeserver
metadataPolicy: None
property: token

View File

@@ -0,0 +1,28 @@
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: http-route-code-server
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: http-route-code-server
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/part-of: {{ .Release.Name }}
spec:
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: traefik-gateway
namespace: traefik
hostnames:
- code-server.alexlebens.net
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- group: ''
kind: Service
name: code-server
port: 8443
weight: 100

View File

@@ -9,7 +9,7 @@ code-server:
main:
image:
repository: ghcr.io/linuxserver/code-server
tag: 4.112.0@sha256:4bb5b8ad22268001687c047f0f04933799fb03df1eb0e1e266ba15ed2d9f4e8b
tag: 4.106.3@sha256:83793e4460090d6c46f4842ff6ab8aa26ad8a567885112bbe754b45c61935055
pullPolicy: IfNotPresent
env:
- name: TZ
@@ -35,27 +35,6 @@ code-server:
port: 8443
targetPort: 8443
protocol: HTTP
route:
main:
kind: HTTPRoute
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: traefik-gateway
namespace: traefik
hostnames:
- code-server.alexlebens.net
rules:
- backendRefs:
- group: ''
kind: Service
name: code-server
port: 8443
weight: 100
matches:
- path:
type: PathPrefix
value: /
persistence:
config:
forceRename: code-server-config
@@ -68,6 +47,8 @@ code-server:
main:
- path: /config
readOnly: false
cloudflared:
existingSecretName: code-server-cloudflared-secret
volsync-target-config:
pvcTarget: code-server-config
moverSecurityContext:
@@ -75,12 +56,3 @@ volsync-target-config:
runAsGroup: 1000
fsGroup: 1000
fsGroupChangePolicy: OnRootMismatch
local:
enabled: true
schedule: 16 8 * * *
remote:
enabled: true
schedule: 16 9 * * *
external:
enabled: true
schedule: 16 10 * * *

View File

@@ -1,6 +1,6 @@
dependencies:
- name: coredns
repository: https://coredns.github.io/helm
version: 1.45.2
digest: sha256:36ed42e4273536b6548426b4e0f51b0816d9e8fe52333bce4c61acd8ade607e8
generated: "2026-01-24T08:01:31.043488615Z"
version: 1.45.0
digest: sha256:cfcb22a7d0bce4d6000800706597ae43faec74255f1deb5cc3279b2d0a81f6c6
generated: "2025-12-02T17:17:52.206039-06:00"

View File

@@ -7,7 +7,7 @@ keywords:
- dns
- network
- kubernetes
home: https://wiki.alexlebens.dev/s/
home: https://wiki.alexlebens.dev/s/43947ec6-a034-449f-8c76-982ac493b072
sources:
- https://github.com/coredns/coredns
- https://github.com/coredns/helm
@@ -15,8 +15,7 @@ maintainers:
- name: alexlebens
dependencies:
- name: coredns
version: 1.45.2
version: 1.45.0
repository: https://coredns.github.io/helm
icon: https://raw.githubusercontent.com/walkxcode/dashboard-icons/main/png/coredns.png
# renovate: datasource=github-releases depName=coredns/coredns
appVersion: v1.14.2
appVersion: v1.13.2

View File

@@ -1,7 +1,7 @@
coredns:
image:
repository: registry.k8s.io/coredns/coredns
tag: v1.14.2
tag: v1.13.1
replicaCount: 3
resources:
requests:

View File

@@ -1,29 +0,0 @@
apiVersion: v2
name: dawarich
version: 1.0.0
description: Dawarich
keywords:
- dawarich
- location
home: https://wiki.alexlebens.dev/s/
sources:
- https://github.com/Freika/dawarich
- https://github.com/bjw-s-labs/helm-charts/tree/main/charts/other/app-template
maintainers:
- name: alexlebens
dependencies:
- name: app-template
alias: dawarich
repository: https://bjw-s-labs.github.io/helm-charts/
version: 4.6.2
- name: postgres-cluster
alias: postgres-18-cluster
version: 7.10.0
repository: oci://harbor.alexlebens.net/helm-charts
- name: valkey
alias: valkey
version: 0.4.0
repository: oci://harbor.alexlebens.net/helm-charts
icon: https://cdn.jsdelivr.net/gh/selfhst/icons@main/png/dawarich.png
# renovate: datasource=github-releases depName=Freika/dawarich
appVersion: 1.4.0

View File

@@ -1,51 +0,0 @@
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: dawarich-key-secret
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: dawarich-key-secret
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/part-of: {{ .Release.Name }}
spec:
secretStoreRef:
kind: ClusterSecretStore
name: vault
data:
- secretKey: key
remoteRef:
conversionStrategy: Default
decodingStrategy: None
key: /cl01tl/dawarich/key
metadataPolicy: None
property: key
---
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: dawarich-oidc-secret
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: dawarich-oidc-secret
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/part-of: {{ .Release.Name }}
spec:
secretStoreRef:
kind: ClusterSecretStore
name: vault
data:
- secretKey: client
remoteRef:
conversionStrategy: Default
decodingStrategy: None
key: /authentik/oidc/dawarich
metadataPolicy: None
property: client
- secretKey: secret
remoteRef:
conversionStrategy: Default
decodingStrategy: None
key: /authentik/oidc/dawarich
metadataPolicy: None
property: secret

View File

@@ -1,344 +0,0 @@
dawarich:
controllers:
main:
type: deployment
replicas: 1
strategy: Recreate
revisionHistoryLimit: 3
containers:
main:
image:
repository: freikin/dawarich
tag: 1.4.0
pullPolicy: IfNotPresent
command: ["web-entrypoint.sh"]
args: ["bin/rails", "server", "-p", "3000", "-b", "::"]
env:
- name: RAILS_ENV
value: production
- name: REDIS_URL
value: redis://dawarich-valkey.dawarich:6379
- name: DATABASE_HOST
valueFrom:
secretKeyRef:
name: dawarich-postgresql-18-cluster-app
key: host
- name: DATABASE_PORT
valueFrom:
secretKeyRef:
name: dawarich-postgresql-18-cluster-app
key: port
- name: DATABASE_USERNAME
valueFrom:
secretKeyRef:
name: dawarich-postgresql-18-cluster-app
key: user
- name: DATABASE_PASSWORD
valueFrom:
secretKeyRef:
name: dawarich-postgresql-18-cluster-app
key: password
- name: DATABASE_NAME
valueFrom:
secretKeyRef:
name: dawarich-postgresql-18-cluster-app
key: dbname
- name: APPLICATION_HOSTS
value: dawarich.alexlebens.net,dawarich.dawarich,localhost,::1,127.0.0.1
- name: TIME_ZONE
value: America/Chicago
- name: APPLICATION_PROTOCOL
value: http
- name: OIDC_ISSUER
value: https://authentik.alexlebens.net/application/o/darwich/
- name: OIDC_REDIRECT_URI
value: https://dawarich.alexlebens.net/users/auth/openid_connect/callback
- name: OIDC_CLIENT_ID
valueFrom:
secretKeyRef:
name: dawarich-oidc-secret
key: client
- name: OIDC_CLIENT_SECRET
valueFrom:
secretKeyRef:
name: dawarich-oidc-secret
key: secret
- name: OIDC_PROVIDER_NAME
value: Authentik
- name: OIDC_AUTO_REGISTER
value: true
- name: PROMETHEUS_EXPORTER_ENABLED
value: true
- name: PROMETHEUS_EXPORTER_HOST
value: 0.0.0.0
- name: PROMETHEUS_EXPORTER_PORT
value: 9394
- name: SECRET_KEY_BASE
valueFrom:
secretKeyRef:
name: dawarich-key-secret
key: key
- name: RAILS_LOG_TO_STDOUT
value: true
- name: SELF_HOSTED
value: true
- name: STORE_GEODATA
value: true
probes:
liveness:
enabled: false
custom: true
spec:
exec:
command:
- /bin/sh
- -c
- wget -qO - http://127.0.0.1:3000/api/v1/health | grep -Eq '\"status\"\\s*:\\s*\"ok\"'
failureThreshold: 5
initialDelaySeconds: 60
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 10
resources:
requests:
cpu: 10m
memory: 128Mi
sidekiq:
image:
repository: freikin/dawarich
tag: 1.4.0
pullPolicy: IfNotPresent
command: ["sidekiq-entrypoint.sh"]
args: ["sidekiq"]
env:
- name: RAILS_ENV
value: production
- name: REDIS_URL
value: redis://dawarich-valkey.dawarich:6379
- name: DATABASE_HOST
valueFrom:
secretKeyRef:
name: dawarich-postgresql-18-cluster-app
key: host
- name: DATABASE_PORT
valueFrom:
secretKeyRef:
name: dawarich-postgresql-18-cluster-app
key: port
- name: DATABASE_USERNAME
valueFrom:
secretKeyRef:
name: dawarich-postgresql-18-cluster-app
key: user
- name: DATABASE_PASSWORD
valueFrom:
secretKeyRef:
name: dawarich-postgresql-18-cluster-app
key: password
- name: DATABASE_NAME
valueFrom:
secretKeyRef:
name: dawarich-postgresql-18-cluster-app
key: dbname
- name: APPLICATION_HOSTS
value: dawarich.alexlebens.net,dawarich.dawarich,localhost,::1,127.0.0.1
- name: TIME_ZONE
value: America/Chicago
- name: APPLICATION_PROTOCOL
value: http
- name: DISTANCE_UNIT
value: mi
- name: OIDC_ISSUER
value: https://authentik.alexlebens.net/application/o/darwich/
- name: OIDC_REDIRECT_URI
value: https://dawarich.alexlebens.net/users/auth/openid_connect/callback
- name: OIDC_CLIENT_ID
valueFrom:
secretKeyRef:
name: dawarich-oidc-secret
key: client
- name: OIDC_CLIENT_SECRET
valueFrom:
secretKeyRef:
name: dawarich-oidc-secret
key: secret
- name: OIDC_PROVIDER_NAME
value: Authentik
- name: OIDC_AUTO_REGISTER
value: true
- name: PROMETHEUS_EXPORTER_ENABLED
value: true
- name: PROMETHEUS_EXPORTER_HOST
value: 0.0.0.0
- name: PROMETHEUS_EXPORTER_PORT
value: 9394
- name: SECRET_KEY_BASE
valueFrom:
secretKeyRef:
name: dawarich-key-secret
key: key
- name: RAILS_LOG_TO_STDOUT
value: true
- name: SELF_HOSTED
value: true
- name: STORE_GEODATA
value: true
probes:
liveness:
enabled: false
custom: true
spec:
exec:
command:
- /bin/sh
- -c
- pgrep -f sidekiq
failureThreshold: 5
initialDelaySeconds: 60
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 10
resources:
requests:
cpu: 10m
memory: 128Mi
service:
main:
controller: main
ports:
http:
port: 80
targetPort: 3000
protocol: TCP
metrics:
port: 9394
targetPort: 9394
protocol: TCP
serviceMonitor:
main:
selector:
matchLabels:
app.kubernetes.io/name: dawarich
app.kubernetes.io/instance: dawarich
serviceName: '{{ include "bjw-s.common.lib.chart.names.fullname" $ }}'
endpoints:
- port: metrics
interval: 30s
scrapeTimeout: 15s
path: /metrics
route:
main:
kind: HTTPRoute
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: traefik-gateway
namespace: traefik
hostnames:
- dawarich.alexlebens.net
rules:
- backendRefs:
- group: ""
kind: Service
name: dawarich
port: 80
weight: 100
matches:
- path:
type: PathPrefix
value: /
persistence:
storage:
forceRename: dawarich-storage
storageClass: ceph-block
accessMode: ReadWriteOnce
size: 5Gi
retain: true
advancedMounts:
main:
main:
- path: /var/app/storage
readOnly: false
sidekiq:
- path: /var/app/storage
readOnly: false
public:
forceRename: dawarich-public
storageClass: ceph-block
accessMode: ReadWriteOnce
size: 5Gi
retain: true
advancedMounts:
main:
main:
- path: /var/app/public
readOnly: false
sidekiq:
- path: /var/app/public
readOnly: false
watched:
forceRename: dawarich-watched
storageClass: ceph-block
accessMode: ReadWriteOnce
size: 1Gi
retain: true
advancedMounts:
main:
main:
- path: /var/app/tmp/imports/watched
readOnly: false
sidekiq:
- path: /var/app/tmp/imports/watched
readOnly: false
postgres-18-cluster:
mode: recovery
cluster:
image:
repository: ghcr.io/cloudnative-pg/postgis
tag: 18-3-system-trixie
initdb:
postInitTemplateSQL:
- CREATE EXTENSION postgis;
- CREATE EXTENSION postgis_topology;
- CREATE EXTENSION fuzzystrmatch;
- CREATE EXTENSION postgis_tiger_geocoder;
recovery:
method: objectStore
objectStore:
index: 1
backup:
objectStore:
- name: garage-local
index: 1
destinationBucket: postgres-backups
externalSecretCredentialPath: /garage/home-infra/postgres-backups
isWALArchiver: true
# - name: garage-remote
# index: 1
# destinationBucket: postgres-backups
# externalSecretCredentialPath: /garage/home-infra/postgres-backups
# retentionPolicy: "90d"
# data:
# compression: bzip2
# - name: external
# index: 1
# endpointURL: https://nyc3.digitaloceanspaces.com
# destinationBucket: postgres-backups-ce540ddf106d186bbddca68a
# externalSecretCredentialPath: /garage/home-infra/postgres-backups
# isWALArchiver: false
scheduledBackups:
- name: live-backup
suspend: false
immediate: true
schedule: "0 10 14 * * *"
backupName: garage-local
# - name: weekly-backup
# suspend: true
# immediate: true
# schedule: "0 0 4 * * SAT"
# backupName: garage-remote
# - name: daily-backup
# suspend: true
# immediate: true
# schedule: "0 0 0 * * *"
# backupName: external

View File

@@ -1,6 +1,6 @@
dependencies:
- name: democratic-csi
repository: https://democratic-csi.github.io/charts/
version: 0.15.1
digest: sha256:e07d76a67023fb523e7d49730330995d0028faba9a4c7c3a6b87c5828921b3c3
generated: "2026-01-08T20:33:17.610556446Z"
version: 0.15.0
digest: sha256:6fe3d8ad7b990b07ed80a31c75a0a49db8da497c46a956c632615a2093d29d58
generated: "2025-12-01T20:25:24.972076-06:00"

View File

@@ -15,7 +15,6 @@ maintainers:
dependencies:
- name: democratic-csi
repository: https://democratic-csi.github.io/charts/
version: 0.15.1
version: 0.15.0
icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/kubernetes.png
# renovate: datasource=github-releases depName=democratic-csi/democratic-csi
appVersion: v1.9.4

View File

@@ -1,6 +1,6 @@
dependencies:
- name: descheduler
repository: https://kubernetes-sigs.github.io/descheduler/
version: 0.35.1
digest: sha256:ed7cc8068b83ac483fda3a781227b35e12a34abdca214b5490e7036c89db1a95
generated: "2026-03-09T21:21:45.788316167Z"
version: 0.34.0
digest: sha256:1020c1fc8c179744f308e9b79f010dcaf59a05019f7d007157974be97063e12b
generated: "2025-12-01T20:25:26.970808-06:00"

View File

@@ -14,8 +14,7 @@ maintainers:
- name: alexlebens
dependencies:
- name: descheduler
version: 0.35.1
version: 0.34.0
repository: https://kubernetes-sigs.github.io/descheduler/
icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/kubernetes.png
# renovate: datasource=github-releases depName=kubernetes-sigs/descheduler
appVersion: v0.35.1
appVersion: 0.34.0

View File

@@ -1,12 +1,15 @@
dependencies:
- name: app-template
repository: https://bjw-s-labs.github.io/helm-charts/
version: 4.6.2
version: 4.5.0
- name: cloudflared
repository: oci://harbor.alexlebens.net/helm-charts
version: 1.23.2
- name: postgres-cluster
repository: oci://harbor.alexlebens.net/helm-charts
version: 7.10.0
- name: valkey
version: 7.1.3
- name: redis-replication
repository: oci://harbor.alexlebens.net/helm-charts
version: 0.4.0
digest: sha256:dfcb5d35e03ecdc4206227d206d36509319f0dcdaed54363840d71337debb3f7
generated: "2026-03-15T20:05:03.156596646Z"
version: 0.5.0
digest: sha256:984cd51b50663cda85c4861949d2dc724de730a415344936a4fe39745aca31d3
generated: "2025-12-17T16:09:15.230017239Z"

View File

@@ -20,15 +20,17 @@ dependencies:
- name: app-template
alias: directus
repository: https://bjw-s-labs.github.io/helm-charts/
version: 4.6.2
version: 4.5.0
- name: cloudflared
alias: cloudflared-directus
repository: oci://harbor.alexlebens.net/helm-charts
version: 1.23.2
- name: postgres-cluster
alias: postgres-18-cluster
version: 7.10.0
version: 7.1.3
repository: oci://harbor.alexlebens.net/helm-charts
- name: valkey
alias: valkey
version: 0.4.0
- name: redis-replication
version: 0.5.0
repository: oci://harbor.alexlebens.net/helm-charts
icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/directus.png
# renovate: datasource=github-releases depName=directus/directus
appVersion: 11.16.1
appVersion: 11.14.0

View File

@@ -41,6 +41,59 @@ spec:
metadataPolicy: None
property: key
---
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: directus-metric-token
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: directus-metric-token
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/part-of: {{ .Release.Name }}
spec:
secretStoreRef:
kind: ClusterSecretStore
name: vault
data:
- secretKey: metric-token
remoteRef:
conversionStrategy: Default
decodingStrategy: None
key: /cl01tl/directus/metrics
metadataPolicy: None
property: metric-token
---
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: directus-redis-config
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: directus-redis-config
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/part-of: {{ .Release.Name }}
spec:
secretStoreRef:
kind: ClusterSecretStore
name: vault
data:
- secretKey: user
remoteRef:
conversionStrategy: Default
decodingStrategy: None
key: /cl01tl/directus/redis
metadataPolicy: None
property: user
- secretKey: password
remoteRef:
conversionStrategy: Default
decodingStrategy: None
key: /cl01tl/directus/redis
metadataPolicy: None
property: password
---
apiVersion: external-secrets.io/v1
kind: ExternalSecret
@@ -75,10 +128,10 @@ spec:
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: directus-metric-token
name: directus-cloudflared-secret
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: directus-metric-token
app.kubernetes.io/name: directus-cloudflared-secret
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/part-of: {{ .Release.Name }}
spec:
@@ -86,22 +139,22 @@ spec:
kind: ClusterSecretStore
name: vault
data:
- secretKey: metric-token
- secretKey: cf-tunnel-token
remoteRef:
conversionStrategy: Default
decodingStrategy: None
key: /cl01tl/directus/metrics
key: /cloudflare/tunnels/directus
metadataPolicy: None
property: metric-token
property: token
---
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: directus-bucket-garage
name: directus-postgresql-18-cluster-backup-secret
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: directus-bucket-garage
app.kubernetes.io/name: directus-postgresql-18-cluster-backup-secret
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/part-of: {{ .Release.Name }}
spec:
@@ -113,32 +166,25 @@ spec:
remoteRef:
conversionStrategy: Default
decodingStrategy: None
key: /garage/home-infra/directus-assets
key: /digital-ocean/home-infra/postgres-backups
metadataPolicy: None
property: ACCESS_KEY_ID
property: access
- secretKey: ACCESS_SECRET_KEY
remoteRef:
conversionStrategy: Default
decodingStrategy: None
key: /garage/home-infra/directus-assets
key: /digital-ocean/home-infra/postgres-backups
metadataPolicy: None
property: ACCESS_SECRET_KEY
- secretKey: ACCESS_REGION
remoteRef:
conversionStrategy: Default
decodingStrategy: None
key: /garage/home-infra/directus-assets
metadataPolicy: None
property: ACCESS_REGION
property: secret
---
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: directus-valkey-config
name: directus-postgresql-18-cluster-backup-secret-garage
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: directus-valkey-config
app.kubernetes.io/name: directus-postgresql-18-cluster-backup-secret-garage
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/part-of: {{ .Release.Name }}
spec:
@@ -146,24 +192,24 @@ spec:
kind: ClusterSecretStore
name: vault
data:
- secretKey: default
- secretKey: ACCESS_KEY_ID
remoteRef:
conversionStrategy: Default
decodingStrategy: None
key: /cl01tl/directus/valkey
key: /garage/home-infra/postgres-backups
metadataPolicy: None
property: password
- secretKey: user
property: ACCESS_KEY_ID
- secretKey: ACCESS_SECRET_KEY
remoteRef:
conversionStrategy: Default
decodingStrategy: None
key: /cl01tl/directus/valkey
key: /garage/home-infra/postgres-backups
metadataPolicy: None
property: user
- secretKey: password
property: ACCESS_SECRET_KEY
- secretKey: ACCESS_REGION
remoteRef:
conversionStrategy: Default
decodingStrategy: None
key: /cl01tl/directus/valkey
key: /garage/home-infra/postgres-backups
metadataPolicy: None
property: password
property: ACCESS_REGION

View File

@@ -0,0 +1,11 @@
apiVersion: objectbucket.io/v1alpha1
kind: ObjectBucketClaim
metadata:
name: ceph-bucket-directus
labels:
app.kubernetes.io/name: ceph-bucket-directus
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/part-of: {{ .Release.Name }}
spec:
generateBucketName: bucket-directus
storageClassName: ceph-bucket

View File

@@ -0,0 +1,22 @@
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: directus
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: directus
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/part-of: {{ .Release.Name }}
spec:
selector:
matchLabels:
app.kubernetes.io/name: directus
app.kubernetes.io/instance: {{ .Release.Name }}
endpoints:
- port: http
interval: 30s
scrapeTimeout: 15s
path: /metrics
bearerTokenSecret:
name: directus-metric-token
key: metric-token

View File

@@ -9,11 +9,11 @@ directus:
main:
image:
repository: directus/directus
tag: 11.16.1
tag: 11.14.0
pullPolicy: IfNotPresent
env:
- name: PUBLIC_URL
value: https://directus.alexlebens.net
value: https://directus.alexlebens.dev
- name: WEBSOCKETS_ENABLED
value: true
- name: ADMIN_EMAIL
@@ -72,16 +72,16 @@ directus:
- name: REDIS_ENABLED
value: true
- name: REDIS_HOST
value: directus-valkey
value: redis-replication-directus-master
- name: REDIS_USERNAME
valueFrom:
secretKeyRef:
name: directus-valkey-config
name: directus-redis-config
key: user
- name: REDIS_PASSWORD
valueFrom:
secretKeyRef:
name: directus-valkey-config
name: directus-redis-config
key: password
- name: STORAGE_LOCATIONS
value: s3
@@ -90,22 +90,22 @@ directus:
- name: STORAGE_S3_KEY
valueFrom:
secretKeyRef:
name: directus-bucket-garage
key: ACCESS_KEY_ID
name: ceph-bucket-directus
key: AWS_ACCESS_KEY_ID
- name: STORAGE_S3_SECRET
valueFrom:
secretKeyRef:
name: directus-bucket-garage
key: ACCESS_SECRET_KEY
- name: STORAGE_S3_REGION
valueFrom:
secretKeyRef:
name: directus-bucket-garage
key: ACCESS_REGION
name: ceph-bucket-directus
key: AWS_SECRET_ACCESS_KEY
- name: STORAGE_S3_BUCKET
value: directus-assets
valueFrom:
configMapKeyRef:
name: ceph-bucket-directus
key: BUCKET_NAME
- name: STORAGE_S3_REGION
value: us-east-1
- name: STORAGE_S3_ENDPOINT
value: http://garage-main.garage:3900
value: http://rook-ceph-rgw-ceph-objectstore.rook-ceph.svc:80
- name: STORAGE_S3_FORCE_PATH_STYLE
value: true
- name: AUTH_PROVIDERS
@@ -125,7 +125,7 @@ directus:
- name: AUTH_AUTHENTIK_SCOPE
value: openid profile email
- name: AUTH_AUTHENTIK_ISSUER_URL
value: https://authentik.alexlebens.net/application/o/directus/.well-known/openid-configuration
value: https://auth.alexlebens.dev/application/o/directus/.well-known/openid-configuration
- name: AUTH_AUTHENTIK_IDENTIFIER_KEY
value: email
- name: AUTH_AUTHENTIK_ALLOW_PUBLIC_REGISTRATION
@@ -153,91 +153,70 @@ directus:
port: 80
targetPort: 8055
protocol: TCP
serviceMonitor:
main:
selector:
matchLabels:
app.kubernetes.io/name: directus
app.kubernetes.io/instance: directus
serviceName: '{{ include "bjw-s.common.lib.chart.names.fullname" $ }}'
endpoints:
- port: http
interval: 30s
scrapeTimeout: 15s
path: /metrics
bearerTokenSecret:
name: directus-metric-token
key: metric-token
route:
main:
kind: HTTPRoute
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: traefik-gateway
namespace: traefik
hostnames:
- directus.alexlebens.net
rules:
- backendRefs:
- group: ''
kind: Service
name: directus
port: 80
weight: 100
matches:
- path:
type: PathPrefix
value: /
cloudflared-directus:
name: cloudflared-directus
existingSecretName: directus-cloudflared-secret
postgres-18-cluster:
mode: recovery
cluster:
storage:
storageClass: local-path
walStorage:
storageClass: local-path
recovery:
method: objectStore
objectStore:
destinationPath: s3://postgres-backups/cl01tl/directus/directus-postgresql-18-cluster
endpointURL: http://garage-main.garage:3900
index: 1
endpointCredentials: directus-postgresql-18-cluster-backup-secret-garage
backup:
objectStore:
- name: garage-local
destinationPath: s3://postgres-backups/cl01tl/directus/directus-postgresql-18-cluster
index: 1
destinationBucket: postgres-backups
externalSecretCredentialPath: /garage/home-infra/postgres-backups
endpointURL: http://garage-main.garage:3900
endpointCredentials: directus-postgresql-18-cluster-backup-secret-garage
endpointCredentialsIncludeRegion: true
retentionPolicy: "3d"
isWALArchiver: true
# - name: garage-remote
# - name: external
# destinationPath: s3://postgres-backups-ce540ddf106d186bbddca68a/cl01tl/directus/directus-postgresql-18-cluster
# index: 1
# destinationBucket: postgres-backups
# externalSecretCredentialPath: /garage/home-infra/postgres-backups
# retentionPolicy: "90d"
# retentionPolicy: "30d"
# isWALArchiver: false
# - name: garage-remote
# destinationPath: s3://postgres-backups/cl01tl/directus/directus-postgresql-18-cluster
# index: 1
# endpointURL: https://garage-ps10rp.boreal-beaufort.ts.net:3900
# endpointCredentials: directus-postgresql-18-cluster-backup-secret-garage
# retentionPolicy: "30d"
# data:
# compression: bzip2
# - name: external
# index: 1
# endpointURL: https://nyc3.digitaloceanspaces.com
# destinationBucket: postgres-backups-ce540ddf106d186bbddca68a
# externalSecretCredentialPath: /garage/home-infra/postgres-backups
# isWALArchiver: false
# jobs: 2
scheduledBackups:
- name: live-backup
suspend: false
immediate: true
schedule: "0 15 14 * * *"
schedule: "0 0 0 * * *"
backupName: garage-local
# - name: weekly-backup
# suspend: true
# immediate: true
# schedule: "0 0 4 * * SAT"
# backupName: garage-remote
# - name: daily-backup
# suspend: true
# suspend: false
# immediate: true
# schedule: "0 0 0 * * *"
# backupName: external
valkey:
valkey:
auth:
enabled: true
usersExistingSecret: directus-valkey-config
aclUsers:
default:
permissions: "~* &* +@all"
metrics:
enabled: false
# - name: weekly-backup
# suspend: false
# immediate: true
# schedule: "0 0 4 * * SAT"
# backupName: garage-remote
redis-replication:
existingSecret:
enabled: true
name: directus-redis-config
key: password
redisReplication:
clusterSize: 3
redisSentinel:
enabled: true
clusterSize: 3

View File

@@ -1,6 +1,6 @@
dependencies:
- name: eck-operator
repository: https://helm.elastic.co
version: 3.3.1
digest: sha256:8585f3ea3e4cafc4ff2969ea7e797017b7cfe4becb3385f0b080725908c02f09
generated: "2026-02-25T18:48:55.77034549Z"
version: 3.2.0
digest: sha256:b27ba092ddfa078f763e409dd5db1144a269eff0f45af04f180d844f13466a34
generated: "2025-12-01T20:25:30.722424-06:00"

View File

@@ -15,8 +15,7 @@ maintainers:
- name: alexlebens
dependencies:
- name: eck-operator
version: 3.3.1
version: 3.2.0
repository: https://helm.elastic.co
icon: https://helm.elastic.co/icons/eck.png
# renovate: datasource=github-releases depName=elastic/cloud-on-k8s
appVersion: v3.3.1
appVersion: v3.2.0

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