Compare commits
42
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fcd16f6128 | ||
|
|
2ac2a94bb4 | ||
|
|
3c7e358dd5 | ||
|
|
9be8fb6c69 | ||
|
|
7fdeacffb8 | ||
|
|
cef499de73 | ||
|
|
1b70a55300 | ||
|
|
3f2b4e9acf | ||
|
|
6057734a4f | ||
|
|
8eedf8b74b | ||
|
|
8c0e36a5c0 | ||
|
|
78cd15f12c | ||
|
|
18c633c242 | ||
|
|
4510394531 | ||
|
|
2545312db1 | ||
|
|
8ce0b809c0 | ||
|
|
506c04e15c | ||
|
|
bdcbb3d5af | ||
|
|
faac6febb8 | ||
|
|
695da1308c | ||
|
|
552b22cb66 | ||
|
|
3756e60c95 | ||
|
|
d0d217ddf4 | ||
|
|
24f84bab2f | ||
|
|
0b8a3c16a7 | ||
|
|
e9a68aae77 | ||
|
|
5359df5ed6 | ||
|
|
8aea0f0d13 | ||
|
|
65d4f2d482 | ||
|
|
2fe9b7632f | ||
|
|
e436d89eef | ||
|
|
8729cb5062 | ||
|
|
f1e4a1088d | ||
|
|
b357ef95d8 | ||
|
|
67422663b7 | ||
|
|
88705fec88 | ||
|
|
c098807aa4 | ||
|
|
e1eee2d3c7 | ||
|
|
ff83daed1e | ||
|
|
080ae343e6 | ||
|
|
8d3185f8ab | ||
|
|
ff40a71145 |
No files matched your search
Executable
+94
@@ -0,0 +1,94 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Local regressions only: kubectl is mocked and Docker is used for config parsing.
|
||||||
|
set -euo pipefail
|
||||||
|
repo="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||||
|
scratch="$(mktemp -d)"
|
||||||
|
trap 'rm -rf "$scratch"' EXIT
|
||||||
|
|
||||||
|
mkdir -p "$scratch/repo/app" "$scratch/repo/postgres" "$scratch/repo/netbird" "$scratch/repo/renovate"
|
||||||
|
git -C "$scratch/repo" init -q
|
||||||
|
for file in app/compose.yaml postgres/shared-compose.yaml netbird/client.compose.yaml renovate/renovate-compose.yaml; do
|
||||||
|
touch "$scratch/repo/$file"
|
||||||
|
done
|
||||||
|
git -C "$scratch/repo" add .
|
||||||
|
# shellcheck source=../workflows/compose-lint.sh
|
||||||
|
source "$repo/.gitea/workflows/compose-lint.sh"
|
||||||
|
actual="$(cd "$scratch/repo" && compose_files)"
|
||||||
|
expected=$'app/compose.yaml\nnetbird/client.compose.yaml\npostgres/shared-compose.yaml\nrenovate/renovate-compose.yaml'
|
||||||
|
[ "$actual" = "$expected" ] || { echo 'Compose discovery missed a file' >&2; exit 1; }
|
||||||
|
|
||||||
|
cat >"$scratch/compose.yaml" <<'YAML'
|
||||||
|
services:
|
||||||
|
example:
|
||||||
|
image: busybox:1.37.0
|
||||||
|
environment:
|
||||||
|
REQUIRED: ${HOMELAB_TEST_REQUIRED:?required for this regression}
|
||||||
|
YAML
|
||||||
|
unset HOMELAB_TEST_REQUIRED
|
||||||
|
if validate_compose_file "$scratch/compose.yaml" >"$scratch/config.log" 2>&1; then
|
||||||
|
echo 'Full Compose validation accepted a missing variable' >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
grep -q 'required for this regression' "$scratch/config.log"
|
||||||
|
HOMELAB_TEST_REQUIRED=present validate_compose_file "$scratch/compose.yaml"
|
||||||
|
|
||||||
|
cat >"$scratch/resources.json" <<'JSON'
|
||||||
|
{"kind":"List","items":[
|
||||||
|
{"kind":"Deployment","metadata":{"namespace":"app"},"spec":{"template":{"spec":{
|
||||||
|
"containers":[{"envFrom":[{"secretRef":{"name":"credentials"}},{"secretRef":{"name":"optional","optional":true}}],"env":[{"valueFrom":{"secretKeyRef":{"name":"credentials","key":"password"}}}]}],
|
||||||
|
"initContainers":[{"envFrom":[{"secretRef":{"name":"init"}}]}],
|
||||||
|
"imagePullSecrets":[{"name":"registry"}],
|
||||||
|
"volumes":[{"secret":{"secretName":"mounted"}},{"projected":{"sources":[{"secret":{"name":"projected"}},{"secret":{"name":"optional-projected","optional":true}}]}}]
|
||||||
|
}}}},
|
||||||
|
{"kind":"CronJob","metadata":{},"spec":{"jobTemplate":{"spec":{"template":{"spec":{"containers":[{"envFrom":[{"secretRef":{"name":"cron"}}]}]}}}}}},
|
||||||
|
{"kind":"IngressRoute","metadata":{"namespace":"app"},"spec":{"tls":{"secretName":"controller-issued-tls"}}}
|
||||||
|
]}
|
||||||
|
JSON
|
||||||
|
actual="$(jq -r -f "$repo/.gitea/workflows/secret-references.jq" "$scratch/resources.json" | sort)"
|
||||||
|
expected=$'app credentials\napp init\napp mounted\napp projected\napp registry\ndefault cron'
|
||||||
|
[ "$actual" = "$expected" ] || { echo "Unexpected Secret references: $actual" >&2; exit 1; }
|
||||||
|
|
||||||
|
REPO="$repo"
|
||||||
|
# shellcheck source=../workflows/deploy-lib.sh
|
||||||
|
source "$repo/.gitea/workflows/deploy-lib.sh"
|
||||||
|
K8S_MANIFESTS=("$scratch/resources.json")
|
||||||
|
KUSTOMIZE_APPS=()
|
||||||
|
# No live cluster access. Reject credentials in app even if they exist elsewhere.
|
||||||
|
kubectl() {
|
||||||
|
case "$1" in
|
||||||
|
create) cat "$scratch/resources.json" ;;
|
||||||
|
get)
|
||||||
|
if [ "$3" = credentials ] && [ "$5" = app ]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
*) echo "Unexpected kubectl invocation: $*" >&2; return 1 ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
if check_referenced_secrets >"$scratch/secrets.log"; then
|
||||||
|
echo 'Namespace-scoped Secret check accepted a missing Secret' >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
grep -q 'MISSING OR UNREADABLE: app/credentials' "$scratch/secrets.log"
|
||||||
|
# API/rendering errors must not produce an empty reference list and pass.
|
||||||
|
kubectl() { return 1; }
|
||||||
|
if ! skip_uninstalled_vmagent_crd "$REPO/prometheus-stack/k8s/vmagent.yaml"; then
|
||||||
|
echo 'VMAgent preflight did not skip an uninstalled CRD' >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
kubectl() { return 0; }
|
||||||
|
if skip_uninstalled_vmagent_crd "$REPO/prometheus-stack/k8s/vmagent.yaml"; then
|
||||||
|
echo 'VMAgent preflight skipped an installed CRD' >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if skip_uninstalled_vmagent_crd "$REPO/prometheus-stack/k8s/victoria.yaml"; then
|
||||||
|
echo 'VMAgent preflight skipped an unrelated manifest' >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
kubectl() { return 1; }
|
||||||
|
if check_referenced_secrets >"$scratch/secrets.log"; then
|
||||||
|
echo 'Secret check accepted a failed manifest render' >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
printf '%s\n' 'Deploy validation regressions passed.'
|
||||||
@@ -3,7 +3,7 @@ name: ci
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- "**"
|
- main
|
||||||
pull_request:
|
pull_request:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
@@ -88,7 +88,7 @@ jobs:
|
|||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
tools_dir="$(bash .gitea/workflows/install-ci-tools.sh shellcheck)"
|
tools_dir="$(bash .gitea/workflows/install-ci-tools.sh shellcheck jq)"
|
||||||
export PATH="$tools_dir:$PATH"
|
export PATH="$tools_dir:$PATH"
|
||||||
mapfile -t scripts < <(
|
mapfile -t scripts < <(
|
||||||
git ls-files '*.sh' ':(glob)**/*.bash'
|
git ls-files '*.sh' ':(glob)**/*.bash'
|
||||||
@@ -98,6 +98,7 @@ jobs:
|
|||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
shellcheck --external-sources --source-path=SCRIPTDIR --severity=style "${scripts[@]}"
|
shellcheck --external-sources --source-path=SCRIPTDIR --severity=style "${scripts[@]}"
|
||||||
|
bash .gitea/tests/deploy-validation.sh
|
||||||
|
|
||||||
lint-prettier:
|
lint-prettier:
|
||||||
runs-on: [self-hosted, linux, arch, homelab]
|
runs-on: [self-hosted, linux, arch, homelab]
|
||||||
@@ -141,6 +142,7 @@ jobs:
|
|||||||
export PATH="$tools_dir:$PATH"
|
export PATH="$tools_dir:$PATH"
|
||||||
ruff check .
|
ruff check .
|
||||||
ruff format --check .
|
ruff format --check .
|
||||||
|
python3 -m unittest discover -s tests -v
|
||||||
|
|
||||||
lint-yaml:
|
lint-yaml:
|
||||||
runs-on: [self-hosted, linux, arch, homelab]
|
runs-on: [self-hosted, linux, arch, homelab]
|
||||||
@@ -292,6 +294,11 @@ jobs:
|
|||||||
echo "server-side dry-run: ${#manifests[@]} manifests, ${#kustomize_apps[@]} kustomize apps"
|
echo "server-side dry-run: ${#manifests[@]} manifests, ${#kustomize_apps[@]} kustomize apps"
|
||||||
failed=0
|
failed=0
|
||||||
for m in ${manifests[@]+"${manifests[@]}"}; do
|
for m in ${manifests[@]+"${manifests[@]}"}; do
|
||||||
|
if [[ "$m" == "prometheus-stack/k8s/vmagent.yaml" ]] \
|
||||||
|
&& ! kubectl get crd vmagents.operator.victoriametrics.com >/dev/null 2>&1; then
|
||||||
|
echo "skip server-side dry-run until the VictoriaMetrics Operator CRD is installed: $m"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
if ! out="$(kubectl apply --dry-run=server -f "$m" 2>&1)"; then
|
if ! out="$(kubectl apply --dry-run=server -f "$m" 2>&1)"; then
|
||||||
failed=1
|
failed=1
|
||||||
echo "::error file=${m}::$(printf '%s' "$out" | head -1)"
|
echo "::error file=${m}::$(printf '%s' "$out" | head -1)"
|
||||||
@@ -331,11 +338,20 @@ jobs:
|
|||||||
- name: Detect changed docker-built services
|
- name: Detect changed docker-built services
|
||||||
id: services
|
id: services
|
||||||
shell: bash
|
shell: bash
|
||||||
|
env:
|
||||||
|
PUSH_BEFORE: ${{ github.event.before }}
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
base="${{ github.event.before }}"
|
base="${PUSH_BEFORE:-}"
|
||||||
if [ -z "$base" ] || [ "$base" = "0000000000000000000000000000000000000000" ]; then
|
empty_tree="$(git hash-object -t tree /dev/null)"
|
||||||
base="$(git rev-list --max-parents=0 HEAD)"
|
if [[ "$base" =~ ^0{40}$ ]]; then
|
||||||
|
base="$empty_tree"
|
||||||
|
elif [[ ! "$base" =~ ^[0-9a-fA-F]{40}$ ]] || ! git cat-file -e "${base}^{commit}" 2>/dev/null; then
|
||||||
|
# Some Gitea push payloads expose `before` as multiple root commits
|
||||||
|
# joined by newlines. It is not a usable diff base; use this push's
|
||||||
|
# first parent so image changes in the current commit are still built.
|
||||||
|
base="$(git rev-parse "${GITHUB_SHA}^" 2>/dev/null || printf '%s' "$empty_tree")"
|
||||||
|
echo "::warning::invalid push-before value; comparing against ${base}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# A failed diff used to leave changed_files empty, which reads exactly
|
# A failed diff used to leave changed_files empty, which reads exactly
|
||||||
|
|||||||
@@ -21,8 +21,7 @@
|
|||||||
# All committed Compose files, including the ones deploy never starts.
|
# All committed Compose files, including the ones deploy never starts.
|
||||||
compose_files() {
|
compose_files() {
|
||||||
git ls-files \
|
git ls-files \
|
||||||
'*/compose.yaml' '*/compose.yml' 'compose.yaml' 'compose.yml' \
|
'*compose.yaml' '*compose.yml'
|
||||||
'*/docker-compose.yaml' '*/docker-compose.yml'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Prints the flags that turn `docker compose config` into the general check.
|
# Prints the flags that turn `docker compose config` into the general check.
|
||||||
|
|||||||
@@ -31,6 +31,16 @@ warn() {
|
|||||||
echo "WARNING: $*" >&2
|
echo "WARNING: $*" >&2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Prune needs the complete desired set in one invocation. Per-file pruning
|
||||||
|
# treats resources from the other files as absent and can delete them.
|
||||||
|
check_prune_mode() {
|
||||||
|
if [ "$APPLY_PRUNE" = "true" ]; then
|
||||||
|
echo "ERROR: APPLY_PRUNE=true is unsupported by the per-file deploy loop." >&2
|
||||||
|
echo "Disable it; remove obsolete resources explicitly after review." >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
collect_k8s() {
|
collect_k8s() {
|
||||||
git -C "$REPO" ls-files -- "$1" \
|
git -C "$REPO" ls-files -- "$1" \
|
||||||
| grep -E '\.ya?ml$' \
|
| grep -E '\.ya?ml$' \
|
||||||
@@ -536,6 +546,7 @@ rollback_workloads() {
|
|||||||
# have to be declared as custom.regex managers in renovate/renovate.json.
|
# have to be declared as custom.regex managers in renovate/renovate.json.
|
||||||
HELM_RELEASES=(
|
HELM_RELEASES=(
|
||||||
"prometheus-stack|prometheus-community/kube-prometheus-stack|prometheus|86.2.3|prometheus-stack/k8s/grafana-values.yaml|prometheus-stack/k8s/active"
|
"prometheus-stack|prometheus-community/kube-prometheus-stack|prometheus|86.2.3|prometheus-stack/k8s/grafana-values.yaml|prometheus-stack/k8s/active"
|
||||||
|
"victoria-operator|victoriametrics/victoria-metrics-operator|prometheus|0.68.1|prometheus-stack/k8s/victoria-operator-values.yaml|prometheus-stack/k8s/active"
|
||||||
"loki|grafana/loki|prometheus|7.3.0|loki/k8s/loki-values.yaml|loki/k8s/active"
|
"loki|grafana/loki|prometheus|7.3.0|loki/k8s/loki-values.yaml|loki/k8s/active"
|
||||||
"alloy|grafana/alloy|prometheus|1.12.1|loki/k8s/alloy-values.yaml|loki/k8s/active"
|
"alloy|grafana/alloy|prometheus|1.12.1|loki/k8s/alloy-values.yaml|loki/k8s/active"
|
||||||
"reloader|stakater/reloader|reloader|2.2.17|reloader/k8s/reloader-values.yaml|reloader/k8s/active"
|
"reloader|stakater/reloader|reloader|2.2.17|reloader/k8s/reloader-values.yaml|reloader/k8s/active"
|
||||||
@@ -547,6 +558,7 @@ helm_repo_for() {
|
|||||||
prometheus-community/*) echo "prometheus-community https://prometheus-community.github.io/helm-charts" ;;
|
prometheus-community/*) echo "prometheus-community https://prometheus-community.github.io/helm-charts" ;;
|
||||||
grafana/*) echo "grafana https://grafana.github.io/helm-charts" ;;
|
grafana/*) echo "grafana https://grafana.github.io/helm-charts" ;;
|
||||||
stakater/*) echo "stakater https://stakater.github.io/stakater-charts" ;;
|
stakater/*) echo "stakater https://stakater.github.io/stakater-charts" ;;
|
||||||
|
victoriametrics/*) echo "victoriametrics https://victoriametrics.github.io/helm-charts" ;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -686,30 +698,74 @@ stage_preflight() {
|
|||||||
git -C "$REPO" reset --hard "$target"
|
git -C "$REPO" reset --hard "$target"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Required pod Secrets, scoped to the resource namespace. TLS route Secrets are
|
||||||
|
# created by cert-manager and are not prerequisites for applying a Certificate.
|
||||||
|
check_referenced_secrets() {
|
||||||
|
local m k objects refs extracted ns name
|
||||||
|
local missing=()
|
||||||
|
refs=""
|
||||||
|
for m in ${K8S_MANIFESTS[@]+"${K8S_MANIFESTS[@]}"}; do
|
||||||
|
if skip_uninstalled_vmagent_crd "$m"; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
objects="$(kubectl create --dry-run=client --validate=false -f "$m" -o json)" || return 1
|
||||||
|
extracted="$(printf '%s' "$objects" | jq -r -f "$REPO/.gitea/workflows/secret-references.jq")" || return 1
|
||||||
|
refs+="$extracted"$'\n'
|
||||||
|
done
|
||||||
|
for k in ${KUSTOMIZE_APPS[@]+"${KUSTOMIZE_APPS[@]}"}; do
|
||||||
|
objects="$(kubectl kustomize "$k" | kubectl create --dry-run=client --validate=false -f - -o json)" || return 1
|
||||||
|
extracted="$(printf '%s' "$objects" | jq -r -f "$REPO/.gitea/workflows/secret-references.jq")" || return 1
|
||||||
|
refs+="$extracted"$'\n'
|
||||||
|
done
|
||||||
|
while read -r ns name; do
|
||||||
|
[ -n "${name:-}" ] || continue
|
||||||
|
if kubectl get secret "$name" -n "$ns" -o name >/dev/null 2>&1; then
|
||||||
|
echo " ok: $ns/$name"
|
||||||
|
else
|
||||||
|
echo " MISSING OR UNREADABLE: $ns/$name"
|
||||||
|
missing+=("$ns/$name")
|
||||||
|
fi
|
||||||
|
done < <(printf '%s' "$refs" | sort -u)
|
||||||
|
if [ "${#missing[@]}" -gt 0 ]; then
|
||||||
|
echo "ERROR: required pod Secrets are missing or unreadable:"
|
||||||
|
printf ' - %s\n' "${missing[@]}"
|
||||||
|
echo "Create them in the listed namespaces from the service's secret example."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# The VMAgent CRD is installed by the VictoriaMetrics Operator Helm release in
|
||||||
|
# stage_apply_k8s, after this preflight stage. Skip only its dry-run until then.
|
||||||
|
skip_uninstalled_vmagent_crd() {
|
||||||
|
local manifest="$1"
|
||||||
|
if [[ "$manifest" == "$REPO/prometheus-stack/k8s/vmagent.yaml" ]] \
|
||||||
|
&& ! kubectl get crd vmagents.operator.victoriametrics.com >/dev/null 2>&1; then
|
||||||
|
echo " skip: VMAgent CRD is installed by Helm during apply: ${manifest#"$REPO"/}"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
stage_validate() {
|
stage_validate() {
|
||||||
|
check_prune_mode || return 1
|
||||||
cd "$REPO"
|
cd "$REPO"
|
||||||
select_manifests
|
select_manifests
|
||||||
local m k cf
|
local m k cf
|
||||||
# Compose .env files and secret files are gitignored by design, so the
|
# The deploy host has the local .env and secret files. Resolve them here so
|
||||||
# workstation never has real values for the inactive stacks. This stage only
|
# missing configuration fails before either apply job changes workloads.
|
||||||
# runs the full check on active stacks; the general structure check for every
|
# CI keeps the structure-only check for inactive stacks.
|
||||||
# committed Compose file (active or not) lives in the ci workflow, which has no
|
|
||||||
# .env at all.
|
|
||||||
#
|
|
||||||
# Active stacks are still validated with interpolation and env-file resolution
|
|
||||||
# off, so required-variable guards (:?) and missing local files do not fail the
|
|
||||||
# deploy. Normalization and consistency checks stay enabled.
|
|
||||||
# shellcheck source=compose-lint.sh
|
# shellcheck source=compose-lint.sh
|
||||||
source "$REPO/.gitea/workflows/compose-lint.sh"
|
source "$REPO/.gitea/workflows/compose-lint.sh"
|
||||||
local compose_validate_flags=()
|
|
||||||
mapfile -t compose_validate_flags < <(compose_safe_flags)
|
|
||||||
log "Validate compose stacks"
|
log "Validate compose stacks"
|
||||||
for cf in ${COMPOSE_STACKS[@]+"${COMPOSE_STACKS[@]}"}; do
|
for cf in ${COMPOSE_STACKS[@]+"${COMPOSE_STACKS[@]}"}; do
|
||||||
echo " config: $cf"
|
echo " config: $cf"
|
||||||
validate_compose_file "$cf" ${compose_validate_flags[@]+"${compose_validate_flags[@]}"}
|
validate_compose_file "$cf"
|
||||||
done
|
done
|
||||||
log "Validate k8s manifests (kubectl dry-run=client)"
|
log "Validate k8s manifests (kubectl dry-run=client)"
|
||||||
for m in ${K8S_MANIFESTS[@]+"${K8S_MANIFESTS[@]}"}; do
|
for m in ${K8S_MANIFESTS[@]+"${K8S_MANIFESTS[@]}"}; do
|
||||||
|
if skip_uninstalled_vmagent_crd "$m"; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
kubectl apply --dry-run=client -f "$m" >/dev/null
|
kubectl apply --dry-run=client -f "$m" >/dev/null
|
||||||
done
|
done
|
||||||
for k in ${KUSTOMIZE_APPS[@]+"${KUSTOMIZE_APPS[@]}"}; do
|
for k in ${KUSTOMIZE_APPS[@]+"${KUSTOMIZE_APPS[@]}"}; do
|
||||||
@@ -717,6 +773,9 @@ stage_validate() {
|
|||||||
done
|
done
|
||||||
log "Validate k8s manifests (kubectl dry-run=server)"
|
log "Validate k8s manifests (kubectl dry-run=server)"
|
||||||
for m in ${K8S_MANIFESTS[@]+"${K8S_MANIFESTS[@]}"}; do
|
for m in ${K8S_MANIFESTS[@]+"${K8S_MANIFESTS[@]}"}; do
|
||||||
|
if skip_uninstalled_vmagent_crd "$m"; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
kubectl apply --dry-run=server -f "$m" >/dev/null
|
kubectl apply --dry-run=server -f "$m" >/dev/null
|
||||||
done
|
done
|
||||||
for k in ${KUSTOMIZE_APPS[@]+"${KUSTOMIZE_APPS[@]}"}; do
|
for k in ${KUSTOMIZE_APPS[@]+"${KUSTOMIZE_APPS[@]}"}; do
|
||||||
@@ -724,48 +783,20 @@ stage_validate() {
|
|||||||
done
|
done
|
||||||
log "Checking referenced Secrets exist"
|
log "Checking referenced Secrets exist"
|
||||||
echo " (deploy never applies *secret*.yaml; create missing ones manually)"
|
echo " (deploy never applies *secret*.yaml; create missing ones manually)"
|
||||||
local ref_secrets=() missing_secrets=() all_secrets s
|
check_referenced_secrets
|
||||||
if [ "${#K8S_MANIFESTS[@]}" -gt 0 ]; then
|
|
||||||
while IFS= read -r s; do
|
|
||||||
[ -n "$s" ] && ref_secrets+=("$s")
|
|
||||||
done < <(
|
|
||||||
{
|
|
||||||
grep -h -A1 -E 'secretRef:|secretKeyRef:' "${K8S_MANIFESTS[@]}" 2>/dev/null || true
|
|
||||||
grep -h -E 'secretName:' "${K8S_MANIFESTS[@]}" 2>/dev/null || true
|
|
||||||
} | grep -E 'name:' | sed -E 's/.*name:[[:space:]]*//' | tr -d '"'"'"' "'"'" | sed -E 's/[[:space:]]*#.*//' | awk 'NF' | sort -u || true
|
|
||||||
)
|
|
||||||
fi
|
|
||||||
all_secrets="$(kubectl get secrets -A --no-headers -o custom-columns=:metadata.name 2>/dev/null || true)"
|
|
||||||
for s in ${ref_secrets[@]+"${ref_secrets[@]}"}; do
|
|
||||||
if printf '%s\n' "$all_secrets" | grep -qx "$s"; then
|
|
||||||
echo " ok: $s"
|
|
||||||
else
|
|
||||||
echo " MISSING: $s"
|
|
||||||
missing_secrets+=("$s")
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
if [ "${#missing_secrets[@]}" -gt 0 ]; then
|
|
||||||
echo "ERROR: ${#missing_secrets[@]} referenced Secret(s) not found in the cluster:"
|
|
||||||
printf ' - %s\n' "${missing_secrets[@]}"
|
|
||||||
echo "Create them manually from the laptop, e.g.:"
|
|
||||||
echo " kubectl apply -f SERVICE/k8s/secrets.yaml # see SERVICE/k8s/secrets.yaml.example"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
stage_apply_k8s() {
|
stage_apply_k8s() {
|
||||||
|
check_prune_mode || return 1
|
||||||
cd "$REPO"
|
cd "$REPO"
|
||||||
select_manifests >/dev/null
|
select_manifests >/dev/null
|
||||||
local ns_files=() other_files=() m k prune_opts=()
|
local ns_files=() other_files=() m k
|
||||||
for m in ${K8S_MANIFESTS[@]+"${K8S_MANIFESTS[@]}"}; do
|
for m in ${K8S_MANIFESTS[@]+"${K8S_MANIFESTS[@]}"}; do
|
||||||
case "$m" in
|
case "$m" in
|
||||||
*/namespace.y?ml) ns_files+=("$m") ;;
|
*/namespace.y?ml) ns_files+=("$m") ;;
|
||||||
*) other_files+=("$m") ;;
|
*) other_files+=("$m") ;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
if [ "$APPLY_PRUNE" = "true" ]; then
|
|
||||||
prune_opts=(--prune -l app.kubernetes.io/managed-by=homelab-deploy)
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Record what is about to change, and publish it for the verify job, before
|
# Record what is about to change, and publish it for the verify job, before
|
||||||
# the first apply. Both are fatal on failure: see snapshot_dir.
|
# the first apply. Both are fatal on failure: see snapshot_dir.
|
||||||
@@ -790,7 +821,7 @@ stage_apply_k8s() {
|
|||||||
if [ "${#other_files[@]}" -gt 0 ]; then
|
if [ "${#other_files[@]}" -gt 0 ]; then
|
||||||
log "Applying resources (${#other_files[@]} files, our images pinned to digests)"
|
log "Applying resources (${#other_files[@]} files, our images pinned to digests)"
|
||||||
for m in "${other_files[@]}"; do
|
for m in "${other_files[@]}"; do
|
||||||
if ! render_pinned <"$m" | kubectl apply "${prune_opts[@]}" -f -; then
|
if ! render_pinned <"$m" | kubectl apply -f -; then
|
||||||
echo "ERROR: apply failed for ${m#"$REPO"/}" >&2
|
echo "ERROR: apply failed for ${m#"$REPO"/}" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ on:
|
|||||||
# workflow_dispatch so a red lint/validate run can never reach the cluster.
|
# workflow_dispatch so a red lint/validate run can never reach the cluster.
|
||||||
workflow_run:
|
workflow_run:
|
||||||
workflows: [ci]
|
workflows: [ci]
|
||||||
|
branches: [main]
|
||||||
types: [completed]
|
types: [completed]
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
@@ -137,9 +138,10 @@ jobs:
|
|||||||
# lets it start after a failed dependency; the needs on apply-compose are a
|
# lets it start after a failed dependency; the needs on apply-compose are a
|
||||||
# barrier, so verification begins only once both applies are done.
|
# barrier, so verification begins only once both applies are done.
|
||||||
verify-k8s:
|
verify-k8s:
|
||||||
needs: [apply-k8s, apply-compose]
|
needs: [preflight, apply-k8s, apply-compose]
|
||||||
if: >-
|
if: >-
|
||||||
always() &&
|
always() &&
|
||||||
|
needs.preflight.result == 'success' &&
|
||||||
needs.apply-k8s.result != 'skipped' &&
|
needs.apply-k8s.result != 'skipped' &&
|
||||||
needs.apply-compose.result != 'skipped'
|
needs.apply-compose.result != 'skipped'
|
||||||
runs-on: [self-hosted, linux, arch, homelab, prod]
|
runs-on: [self-hosted, linux, arch, homelab, prod]
|
||||||
@@ -182,8 +184,11 @@ jobs:
|
|||||||
# suppressing them on a rollback would hide the one run where the answer
|
# suppressing them on a rollback would hide the one run where the answer
|
||||||
# matters most.
|
# matters most.
|
||||||
smoke:
|
smoke:
|
||||||
needs: [verify-k8s]
|
needs: [preflight, verify-k8s]
|
||||||
if: always() && needs.verify-k8s.result != 'skipped'
|
if: >-
|
||||||
|
always() &&
|
||||||
|
needs.preflight.result == 'success' &&
|
||||||
|
needs.verify-k8s.result != 'skipped'
|
||||||
runs-on: [self-hosted, linux, arch, homelab, prod]
|
runs-on: [self-hosted, linux, arch, homelab, prod]
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
steps:
|
steps:
|
||||||
|
|||||||
@@ -120,6 +120,15 @@ install_shellcheck() {
|
|||||||
rm -rf "$tmp"
|
rm -rf "$tmp"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
install_jq() {
|
||||||
|
if at_version jq "${JQ_VERSION}"; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
fetch "https://github.com/jqlang/jq/releases/download/jq-${JQ_VERSION}/jq-linux-${goarch}" \
|
||||||
|
"$BIN_DIR/jq"
|
||||||
|
chmod 0755 "$BIN_DIR/jq"
|
||||||
|
}
|
||||||
|
|
||||||
install_uv() {
|
install_uv() {
|
||||||
if at_version uv "${UV_VERSION}"; then
|
if at_version uv "${UV_VERSION}"; then
|
||||||
return 0
|
return 0
|
||||||
@@ -236,6 +245,7 @@ for tool in "${wanted[@]}"; do
|
|||||||
case "$tool" in
|
case "$tool" in
|
||||||
kubeconform) install_kubeconform ;;
|
kubeconform) install_kubeconform ;;
|
||||||
shellcheck) install_shellcheck ;;
|
shellcheck) install_shellcheck ;;
|
||||||
|
jq) install_jq ;;
|
||||||
actionlint) install_actionlint ;;
|
actionlint) install_actionlint ;;
|
||||||
prettier) install_prettier ;;
|
prettier) install_prettier ;;
|
||||||
ruff) install_ruff ;;
|
ruff) install_ruff ;;
|
||||||
|
|||||||
@@ -2,9 +2,23 @@ name: renovate-ci
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- "renovate/**"
|
||||||
|
- ".gitea/workflows/renovate-ci.yaml"
|
||||||
|
- ".gitea/workflows/sync-renovate-configmap.sh"
|
||||||
|
- ".gitea/workflows/compose-lint.sh"
|
||||||
|
- ".gitea/workflows/install-ci-tools.sh"
|
||||||
|
- ".gitea/workflows/tool-versions.env"
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
|
paths:
|
||||||
|
- "renovate/**"
|
||||||
|
- ".gitea/workflows/renovate-ci.yaml"
|
||||||
|
- ".gitea/workflows/sync-renovate-configmap.sh"
|
||||||
|
- ".gitea/workflows/compose-lint.sh"
|
||||||
|
- ".gitea/workflows/install-ci-tools.sh"
|
||||||
|
- ".gitea/workflows/tool-versions.env"
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
# kubectl emits a List for files containing multiple resources.
|
||||||
|
(if .kind == "List" then .items[] else . end)
|
||||||
|
| (.metadata.namespace // "default") as $ns
|
||||||
|
| [
|
||||||
|
(.. | objects
|
||||||
|
| (.secretRef? // empty), (.secretKeyRef? // empty), (.secret? // empty)
|
||||||
|
| select(.optional != true)
|
||||||
|
| .name // .secretName // empty),
|
||||||
|
(.. | objects | .imagePullSecrets[]?.name)
|
||||||
|
]
|
||||||
|
| unique[]
|
||||||
|
| select(. != null and . != "")
|
||||||
|
| "\($ns) \(.)"
|
||||||
@@ -31,3 +31,6 @@ UV_VERSION="0.12.17"
|
|||||||
# so the tree that gets tested is the tree that gets built. Renovate keeps this
|
# so the tree that gets tested is the tree that gets built. Renovate keeps this
|
||||||
# in step with the Dockerfile's node: tag via the "node runtime" group.
|
# in step with the Dockerfile's node: tag via the "node runtime" group.
|
||||||
NODE_VERSION="22.23.3"
|
NODE_VERSION="22.23.3"
|
||||||
|
|
||||||
|
# Secret-reference regression tests parse rendered Kubernetes objects.
|
||||||
|
JQ_VERSION="1.8.1"
|
||||||
@@ -31,7 +31,7 @@ services:
|
|||||||
- "traefik.http.routers.adguard-dev.entrypoints=websecure"
|
- "traefik.http.routers.adguard-dev.entrypoints=websecure"
|
||||||
- "traefik.http.routers.adguard-dev.tls=true"
|
- "traefik.http.routers.adguard-dev.tls=true"
|
||||||
# DoH Router
|
# DoH Router
|
||||||
- "traefik.http.routers.dns-over-https.rule=(Host(`dns.forust.xyz` || Host(`adguard.forust.xyz`)) && PathPrefix(`/dns-query`))"
|
- "traefik.http.routers.dns-over-https.rule=(Host(`dns.forust.xyz`) || Host(`adguard.forust.xyz`)) && PathPrefix(`/dns-query`)"
|
||||||
- "traefik.http.routers.dns-over-https.entrypoints=websecure"
|
- "traefik.http.routers.dns-over-https.entrypoints=websecure"
|
||||||
- "traefik.http.routers.dns-over-https.tls.certresolver=letsencrypt"
|
- "traefik.http.routers.dns-over-https.tls.certresolver=letsencrypt"
|
||||||
|
|
||||||
|
|||||||
@@ -51,6 +51,8 @@ spec:
|
|||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
|
annotations:
|
||||||
|
reloader.stakater.com/auto: "true"
|
||||||
name: adguard-deployment
|
name: adguard-deployment
|
||||||
namespace: adguard
|
namespace: adguard
|
||||||
spec:
|
spec:
|
||||||
@@ -64,8 +66,6 @@ spec:
|
|||||||
metadata:
|
metadata:
|
||||||
labels:
|
labels:
|
||||||
app: adguard
|
app: adguard
|
||||||
annotations:
|
|
||||||
reloader.stakater.com/auto: "true"
|
|
||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: adguard
|
- name: adguard
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ spec:
|
|||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
|
annotations:
|
||||||
|
reloader.stakater.com/auto: "true"
|
||||||
name: authentik-server-deployment
|
name: authentik-server-deployment
|
||||||
namespace: authentik
|
namespace: authentik
|
||||||
spec:
|
spec:
|
||||||
@@ -63,6 +65,8 @@ spec:
|
|||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
|
annotations:
|
||||||
|
reloader.stakater.com/auto: "true"
|
||||||
name: authentik-worker-deployment
|
name: authentik-worker-deployment
|
||||||
namespace: authentik
|
namespace: authentik
|
||||||
spec:
|
spec:
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
|
annotations:
|
||||||
|
reloader.stakater.com/auto: "true"
|
||||||
name: cfddns
|
name: cfddns
|
||||||
labels:
|
labels:
|
||||||
app: cfddns
|
app: cfddns
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ spec:
|
|||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
|
annotations:
|
||||||
|
reloader.stakater.com/auto: "true"
|
||||||
name: checkmk-deployment
|
name: checkmk-deployment
|
||||||
namespace: checkmk
|
namespace: checkmk
|
||||||
spec:
|
spec:
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
|
annotations:
|
||||||
|
reloader.stakater.com/auto: "true"
|
||||||
name: cloudflared
|
name: cloudflared
|
||||||
labels:
|
labels:
|
||||||
app: cloudflared
|
app: cloudflared
|
||||||
@@ -18,7 +20,7 @@ spec:
|
|||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: cloudflared
|
- name: cloudflared
|
||||||
image: cloudflare/cloudflared:2026.9.3
|
image: cloudflare/cloudflared:2026.10.0
|
||||||
imagePullPolicy: IfNotPresent
|
imagePullPolicy: IfNotPresent
|
||||||
args:
|
args:
|
||||||
- tunnel
|
- tunnel
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ spec:
|
|||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
|
annotations:
|
||||||
|
reloader.stakater.com/auto: "true"
|
||||||
name: convertx-deployment
|
name: convertx-deployment
|
||||||
namespace: converters
|
namespace: converters
|
||||||
spec:
|
spec:
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
|
annotations:
|
||||||
|
reloader.stakater.com/auto: "true"
|
||||||
name: session-keeper
|
name: session-keeper
|
||||||
namespace: edu-master
|
namespace: edu-master
|
||||||
labels:
|
labels:
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
|
annotations:
|
||||||
|
reloader.stakater.com/auto: "true"
|
||||||
name: webinar-checker
|
name: webinar-checker
|
||||||
namespace: edu-master
|
namespace: edu-master
|
||||||
labels:
|
labels:
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM python:3.11-slim
|
FROM python:3.14-slim
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM python:3.11-slim
|
FROM python:3.14-slim
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ spec:
|
|||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
|
annotations:
|
||||||
|
reloader.stakater.com/auto: "true"
|
||||||
name: gitea-deployment
|
name: gitea-deployment
|
||||||
namespace: gitea
|
namespace: gitea
|
||||||
spec:
|
spec:
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ spec:
|
|||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
|
annotations:
|
||||||
|
reloader.stakater.com/auto: "true"
|
||||||
name: glance-deployment
|
name: glance-deployment
|
||||||
namespace: glance
|
namespace: glance
|
||||||
spec:
|
spec:
|
||||||
@@ -69,7 +71,7 @@ spec:
|
|||||||
name: glance-config
|
name: glance-config
|
||||||
- name: glance-assets
|
- name: glance-assets
|
||||||
configMap:
|
configMap:
|
||||||
name: glance-config
|
name: glance-assets
|
||||||
- name: docker-socket
|
- name: docker-socket
|
||||||
hostPath:
|
hostPath:
|
||||||
path: /var/run/docker.sock
|
path: /var/run/docker.sock
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
services:
|
services:
|
||||||
homarr:
|
homarr:
|
||||||
container_name: homarr
|
container_name: homarr
|
||||||
image: ghcr.io/homarr-labs/homarr:v2.1.2
|
image: ghcr.io/homarr-labs/homarr:v2.2.0
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
volumes:
|
volumes:
|
||||||
- ./appdata:/appdata
|
- ./appdata:/appdata
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ spec:
|
|||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
|
annotations:
|
||||||
|
reloader.stakater.com/auto: "true"
|
||||||
name: homarr-deployment
|
name: homarr-deployment
|
||||||
namespace: homarr
|
namespace: homarr
|
||||||
spec:
|
spec:
|
||||||
@@ -30,7 +32,7 @@ spec:
|
|||||||
serviceAccountName: homarr
|
serviceAccountName: homarr
|
||||||
containers:
|
containers:
|
||||||
- name: homarr
|
- name: homarr
|
||||||
image: ghcr.io/homarr-labs/homarr:v2.1.2
|
image: ghcr.io/homarr-labs/homarr:v2.2.0
|
||||||
envFrom:
|
envFrom:
|
||||||
- configMapRef:
|
- configMapRef:
|
||||||
name: homarr-config
|
name: homarr-config
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ spec:
|
|||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
|
annotations:
|
||||||
|
reloader.stakater.com/auto: "true"
|
||||||
name: immich-deployment
|
name: immich-deployment
|
||||||
namespace: immich
|
namespace: immich
|
||||||
labels:
|
labels:
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ spec:
|
|||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
|
annotations:
|
||||||
|
reloader.stakater.com/auto: "true"
|
||||||
name: immich-machine-learning-deployment
|
name: immich-machine-learning-deployment
|
||||||
namespace: immich
|
namespace: immich
|
||||||
labels:
|
labels:
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ spec:
|
|||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: StatefulSet
|
kind: StatefulSet
|
||||||
metadata:
|
metadata:
|
||||||
|
annotations:
|
||||||
|
reloader.stakater.com/auto: "true"
|
||||||
name: immich-valkey
|
name: immich-valkey
|
||||||
namespace: immich
|
namespace: immich
|
||||||
labels:
|
labels:
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ spec:
|
|||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
|
annotations:
|
||||||
|
reloader.stakater.com/auto: "true"
|
||||||
name: kener-deployment
|
name: kener-deployment
|
||||||
namespace: kener
|
namespace: kener
|
||||||
spec:
|
spec:
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ spec:
|
|||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
|
annotations:
|
||||||
|
reloader.stakater.com/auto: "true"
|
||||||
name: metube-deployment
|
name: metube-deployment
|
||||||
namespace: metube
|
namespace: metube
|
||||||
spec:
|
spec:
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
services:
|
services:
|
||||||
n8n:
|
n8n:
|
||||||
image: docker.n8n.io/n8nio/n8n:2.42.3
|
image: docker.n8n.io/n8nio/n8n:2.43.0
|
||||||
container_name: n8n
|
container_name: n8n
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
environment:
|
environment:
|
||||||
|
|||||||
+3
-1
@@ -13,6 +13,8 @@ spec:
|
|||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
|
annotations:
|
||||||
|
reloader.stakater.com/auto: "true"
|
||||||
name: n8n-deployment
|
name: n8n-deployment
|
||||||
namespace: n8n
|
namespace: n8n
|
||||||
spec:
|
spec:
|
||||||
@@ -29,7 +31,7 @@ spec:
|
|||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: n8n
|
- name: n8n
|
||||||
image: docker.n8n.io/n8nio/n8n:2.42.3
|
image: docker.n8n.io/n8nio/n8n:2.43.0
|
||||||
envFrom:
|
envFrom:
|
||||||
- configMapRef:
|
- configMapRef:
|
||||||
name: n8n-config
|
name: n8n-config
|
||||||
|
|||||||
Executable
+109
@@ -0,0 +1,109 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
umask 077
|
||||||
|
|
||||||
|
TEMPLATE_PATH=/opt/netbird/config.template.yaml
|
||||||
|
RENDERED_PATH=/run/netbird/config.yaml
|
||||||
|
RELAY_SECRET_PATH=/run/secrets/relay_auth_secret
|
||||||
|
ENCRYPTION_KEY_PATH=/run/secrets/datastore_encryption_key
|
||||||
|
|
||||||
|
is_valid_proxy_subnet() {
|
||||||
|
candidate="$1"
|
||||||
|
case "$candidate" in
|
||||||
|
0.0.0.0/0)
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
*/*)
|
||||||
|
address="${candidate%%/*}"
|
||||||
|
prefix="${candidate#*/}"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
case "$prefix" in
|
||||||
|
0|[1-9]|[1-2][0-9]|3[0-2]) ;;
|
||||||
|
*)
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
old_ifs="$IFS"
|
||||||
|
IFS=.
|
||||||
|
# shellcheck disable=SC2086
|
||||||
|
set -- $address
|
||||||
|
IFS="$old_ifs"
|
||||||
|
[ "$#" -eq 4 ] || return 1
|
||||||
|
|
||||||
|
for octet do
|
||||||
|
case "$octet" in
|
||||||
|
0|[1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]) ;;
|
||||||
|
*)
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
read_secret() {
|
||||||
|
secret_path="$1"
|
||||||
|
|
||||||
|
if [ ! -r "$secret_path" ]; then
|
||||||
|
echo "Required secret is not readable: $secret_path" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
secret_value="$(cat "$secret_path")"
|
||||||
|
if [ -z "$secret_value" ]; then
|
||||||
|
echo "Required secret is empty: $secret_path" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf '%s' "$secret_value"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ -z "${NETBIRD_DOMAIN:-}" ]; then
|
||||||
|
echo "NETBIRD_DOMAIN must be set" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$NETBIRD_DOMAIN" in
|
||||||
|
*[!A-Za-z0-9.-]*)
|
||||||
|
echo "NETBIRD_DOMAIN contains unsupported characters" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ -z "${NETBIRD_PROXY_SUBNET:-}" ] || [ "$NETBIRD_PROXY_SUBNET" = "auto" ]; then
|
||||||
|
echo "NETBIRD_PROXY_SUBNET must be an explicit IPv4 CIDR; run netbird/setup.sh first" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if ! is_valid_proxy_subnet "$NETBIRD_PROXY_SUBNET"; then
|
||||||
|
echo "NETBIRD_PROXY_SUBNET must be a non-default IPv4 CIDR, for example 172.20.0.0/16" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$#" -ne 2 ] || [ "$1" != "--config" ] || [ "$2" != "$RENDERED_PATH" ]; then
|
||||||
|
echo "Expected: --config $RENDERED_PATH" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
relay_secret="$(read_secret "$RELAY_SECRET_PATH")"
|
||||||
|
encryption_key="$(read_secret "$ENCRYPTION_KEY_PATH")"
|
||||||
|
|
||||||
|
mkdir -p "$(dirname "$RENDERED_PATH")"
|
||||||
|
sed \
|
||||||
|
-e "s|__NETBIRD_DOMAIN__|${NETBIRD_DOMAIN}|g" \
|
||||||
|
-e "s|__NETBIRD_AUTH_SECRET__|${relay_secret}|g" \
|
||||||
|
-e "s|__NETBIRD_ENCRYPTION_KEY__|${encryption_key}|g" \
|
||||||
|
-e "s|__NETBIRD_PROXY_SUBNET__|${NETBIRD_PROXY_SUBNET}|g" \
|
||||||
|
"$TEMPLATE_PATH" >"$RENDERED_PATH"
|
||||||
|
|
||||||
|
if grep -q '__NETBIRD_' "$RENDERED_PATH"; then
|
||||||
|
echo "Rendered NetBird configuration still contains unresolved placeholders" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec /go/bin/netbird-server "$@"
|
||||||
@@ -32,6 +32,8 @@ spec:
|
|||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
|
annotations:
|
||||||
|
reloader.stakater.com/auto: "true"
|
||||||
name: netbird-server-deployment
|
name: netbird-server-deployment
|
||||||
namespace: netbird
|
namespace: netbird
|
||||||
spec:
|
spec:
|
||||||
@@ -126,6 +128,8 @@ spec:
|
|||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
|
annotations:
|
||||||
|
reloader.stakater.com/auto: "true"
|
||||||
name: netbird-dashboard-deployment
|
name: netbird-dashboard-deployment
|
||||||
namespace: netbird
|
namespace: netbird
|
||||||
spec:
|
spec:
|
||||||
|
|||||||
Executable
+38
@@ -0,0 +1,38 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Prepare local Compose configuration without replacing existing credentials.
|
||||||
|
set -euo pipefail
|
||||||
|
cd "$(dirname "${BASH_SOURCE[0]}")"
|
||||||
|
umask 077
|
||||||
|
if [ ! -f .env ]; then
|
||||||
|
cp .env.example .env
|
||||||
|
fi
|
||||||
|
|
||||||
|
if grep -q '^NETBIRD_PROXY_SUBNET=auto$' .env; then
|
||||||
|
subnet="$(docker network inspect proxy --format '{{range .IPAM.Config}}{{println .Subnet}}{{end}}' | awk '/^[0-9]+\./ { print; exit }')"
|
||||||
|
if [ -z "$subnet" ]; then
|
||||||
|
echo "No IPv4 subnet found on the Docker proxy network. Set NETBIRD_PROXY_SUBNET in .env." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
# The detected value must be safe to substitute into the env file.
|
||||||
|
if [[ ! "$subnet" =~ ^[0-9.]+/[0-9]+$ ]]; then
|
||||||
|
echo "Unexpected Docker network subnet: $subnet" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
sed -i "s|^NETBIRD_PROXY_SUBNET=auto$|NETBIRD_PROXY_SUBNET=$subnet|" .env
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p secrets
|
||||||
|
chmod 700 secrets
|
||||||
|
for name in relay-auth-secret datastore-encryption-key; do
|
||||||
|
path="secrets/$name"
|
||||||
|
if [ -e "$path" ]; then
|
||||||
|
if [ ! -s "$path" ]; then
|
||||||
|
echo "Existing secret is empty: $path. Restore it before continuing." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
openssl rand -base64 32 >"$path"
|
||||||
|
fi
|
||||||
|
chmod 600 "$path"
|
||||||
|
done
|
||||||
|
printf '%s\n' 'Local files are ready. Review .env, then run docker compose config --quiet.'
|
||||||
@@ -14,6 +14,8 @@ spec:
|
|||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
|
annotations:
|
||||||
|
reloader.stakater.com/auto: "true"
|
||||||
name: netbox-deployment
|
name: netbox-deployment
|
||||||
namespace: netbox
|
namespace: netbox
|
||||||
labels:
|
labels:
|
||||||
@@ -118,6 +120,8 @@ spec:
|
|||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
|
annotations:
|
||||||
|
reloader.stakater.com/auto: "true"
|
||||||
name: netbox-worker-deployment
|
name: netbox-worker-deployment
|
||||||
namespace: netbox
|
namespace: netbox
|
||||||
labels:
|
labels:
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ spec:
|
|||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: StatefulSet
|
kind: StatefulSet
|
||||||
metadata:
|
metadata:
|
||||||
|
annotations:
|
||||||
|
reloader.stakater.com/auto: "true"
|
||||||
name: netbox-valkey
|
name: netbox-valkey
|
||||||
namespace: netbox
|
namespace: netbox
|
||||||
labels:
|
labels:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
services:
|
services:
|
||||||
netronome:
|
netronome:
|
||||||
image: ghcr.io/autobrr/netronome:v0.15.0
|
image: ghcr.io/autobrr/netronome:v0.16.0
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
container_name: netronome
|
container_name: netronome
|
||||||
ports:
|
ports:
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ spec:
|
|||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
|
annotations:
|
||||||
|
reloader.stakater.com/auto: "true"
|
||||||
name: netronome-deployment
|
name: netronome-deployment
|
||||||
namespace: netronome
|
namespace: netronome
|
||||||
labels:
|
labels:
|
||||||
@@ -32,7 +34,7 @@ spec:
|
|||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: netronome
|
- name: netronome
|
||||||
image: ghcr.io/autobrr/netronome:v0.15.0
|
image: ghcr.io/autobrr/netronome:v0.16.0
|
||||||
ports:
|
ports:
|
||||||
- name: netronome-port
|
- name: netronome-port
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
POSTGRES_ADMIN_PASSWORD=
|
POSTGRES_ADMIN_PASSWORD=
|
||||||
AUTHENTIK_DB_PASSWORD=
|
AUTHENTIK_DB_PASSWORD=
|
||||||
GITEA_DB_PASSWORD=
|
GITEA_DB_PASSWORD=
|
||||||
|
NETBOX_DB_PASSWORD=
|
||||||
NETRONOME_DB_PASSWORD=
|
NETRONOME_DB_PASSWORD=
|
||||||
PENPOT_DB_PASSWORD=
|
PENPOT_DB_PASSWORD=
|
||||||
STATUSPAGE_DB_PASSWORD=
|
STATUSPAGE_DB_PASSWORD=
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
# VictoriaMetrics
|
||||||
|
|
||||||
|
The `victoria-operator` Helm release converts Prometheus Operator
|
||||||
|
`ServiceMonitor` resources into owned `VMServiceScrape` resources. The
|
||||||
|
`VMAgent` selects converted scrapes labeled `release: prometheus-stack` in all
|
||||||
|
namespaces and writes them to the existing single-node VictoriaMetrics
|
||||||
|
instance. Changes to selected `ServiceMonitor` resources are reconciled
|
||||||
|
automatically; there is no copied Prometheus scrape-config blob to regenerate.
|
||||||
|
|
||||||
|
The agent drops targets for the Prometheus server service to avoid duplicating
|
||||||
|
its self-scrape. `scraper: victoria` identifies the samples ingested by this
|
||||||
|
VMAgent.
|
||||||
|
|
||||||
|
The VictoriaMetrics Operator chart and its CRDs are installed before the
|
||||||
|
Kubernetes manifests by the normal deploy workflow. On a cluster where the
|
||||||
|
operator CRDs are not installed yet, CI skips the server-side dry-run of the
|
||||||
|
`VMAgent` resource; the deploy installs the chart before applying that resource.
|
||||||
@@ -38,6 +38,8 @@ grafana:
|
|||||||
|
|
||||||
# One block covers both the dashboards and datasources sidecars (p95 91M / 80M).
|
# One block covers both the dashboards and datasources sidecars (p95 91M / 80M).
|
||||||
sidecar:
|
sidecar:
|
||||||
|
datasources:
|
||||||
|
defaultDatasourceEnabled: false
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
memory: "96Mi"
|
memory: "96Mi"
|
||||||
@@ -50,9 +52,18 @@ grafana:
|
|||||||
type: loki
|
type: loki
|
||||||
url: http://loki-gateway.prometheus.svc.cluster.local
|
url: http://loki-gateway.prometheus.svc.cluster.local
|
||||||
access: proxy
|
access: proxy
|
||||||
|
- name: VictoriaMetrics
|
||||||
|
type: prometheus
|
||||||
|
url: http://victoria-metrics.prometheus.svc.cluster.local:8428
|
||||||
|
access: proxy
|
||||||
|
isDefault: true
|
||||||
|
|
||||||
prometheus:
|
prometheus:
|
||||||
prometheusSpec:
|
prometheusSpec:
|
||||||
|
# VM trial: vmagent scrapes and remote-writes to VictoriaMetrics, so the
|
||||||
|
# Prometheus server itself stands down. Encoded here (not a kubectl patch)
|
||||||
|
# so helm keeps owning spec.replicas and upgrades do not conflict on it.
|
||||||
|
replicas: 0
|
||||||
retention: 60d
|
retention: 60d
|
||||||
retentionSize: 32GB
|
retentionSize: 32GB
|
||||||
storageSpec:
|
storageSpec:
|
||||||
|
|||||||
@@ -31,3 +31,105 @@ spec:
|
|||||||
port: 80
|
port: 80
|
||||||
tls:
|
tls:
|
||||||
secretName: internal-wildcard-tls
|
secretName: internal-wildcard-tls
|
||||||
|
---
|
||||||
|
apiVersion: traefik.io/v1alpha1
|
||||||
|
kind: IngressRoute
|
||||||
|
metadata:
|
||||||
|
name: prometheus-local
|
||||||
|
namespace: prometheus
|
||||||
|
spec:
|
||||||
|
entryPoints:
|
||||||
|
- websecure
|
||||||
|
routes:
|
||||||
|
- match: Host(`prom.workstation.internal`) || Host(`prom.gigaforust.internal`)
|
||||||
|
kind: Rule
|
||||||
|
services:
|
||||||
|
- name: prometheus-stack-kube-prom-prometheus
|
||||||
|
port: 9090
|
||||||
|
tls:
|
||||||
|
secretName: internal-wildcard-tls
|
||||||
|
---
|
||||||
|
apiVersion: traefik.io/v1alpha1
|
||||||
|
kind: IngressRoute
|
||||||
|
metadata:
|
||||||
|
name: alertmanager-local
|
||||||
|
namespace: prometheus
|
||||||
|
spec:
|
||||||
|
entryPoints:
|
||||||
|
- websecure
|
||||||
|
routes:
|
||||||
|
- match: Host(`am.workstation.internal`) || Host(`am.gigaforust.internal`)
|
||||||
|
kind: Rule
|
||||||
|
services:
|
||||||
|
- name: prometheus-stack-kube-prom-alertmanager
|
||||||
|
port: 9093
|
||||||
|
tls:
|
||||||
|
secretName: internal-wildcard-tls
|
||||||
|
---
|
||||||
|
apiVersion: traefik.io/v1alpha1
|
||||||
|
kind: IngressRoute
|
||||||
|
metadata:
|
||||||
|
name: loki-local
|
||||||
|
namespace: prometheus
|
||||||
|
spec:
|
||||||
|
entryPoints:
|
||||||
|
- websecure
|
||||||
|
routes:
|
||||||
|
- match: Host(`loki.workstation.internal`) || Host(`loki.gigaforust.internal`)
|
||||||
|
kind: Rule
|
||||||
|
services:
|
||||||
|
- name: loki-gateway
|
||||||
|
port: 80
|
||||||
|
tls:
|
||||||
|
secretName: internal-wildcard-tls
|
||||||
|
---
|
||||||
|
apiVersion: traefik.io/v1alpha1
|
||||||
|
kind: IngressRoute
|
||||||
|
metadata:
|
||||||
|
name: alloy-local
|
||||||
|
namespace: prometheus
|
||||||
|
spec:
|
||||||
|
entryPoints:
|
||||||
|
- websecure
|
||||||
|
routes:
|
||||||
|
- match: Host(`alloy.workstation.internal`) || Host(`alloy.gigaforust.internal`)
|
||||||
|
kind: Rule
|
||||||
|
services:
|
||||||
|
- name: alloy
|
||||||
|
port: 12345
|
||||||
|
tls:
|
||||||
|
secretName: internal-wildcard-tls
|
||||||
|
---
|
||||||
|
apiVersion: traefik.io/v1alpha1
|
||||||
|
kind: IngressRoute
|
||||||
|
metadata:
|
||||||
|
name: victoria-local
|
||||||
|
namespace: prometheus
|
||||||
|
spec:
|
||||||
|
entryPoints:
|
||||||
|
- websecure
|
||||||
|
routes:
|
||||||
|
- match: Host(`victoria.workstation.internal`) || Host(`victoria.gigaforust.internal`)
|
||||||
|
kind: Rule
|
||||||
|
services:
|
||||||
|
- name: victoria-metrics
|
||||||
|
port: 8428
|
||||||
|
tls:
|
||||||
|
secretName: internal-wildcard-tls
|
||||||
|
---
|
||||||
|
apiVersion: traefik.io/v1alpha1
|
||||||
|
kind: IngressRoute
|
||||||
|
metadata:
|
||||||
|
name: vmalert-local
|
||||||
|
namespace: prometheus
|
||||||
|
spec:
|
||||||
|
entryPoints:
|
||||||
|
- websecure
|
||||||
|
routes:
|
||||||
|
- match: Host(`vmalert.workstation.internal`) || Host(`vmalert.gigaforust.internal`)
|
||||||
|
kind: Rule
|
||||||
|
services:
|
||||||
|
- name: vmalert
|
||||||
|
port: 8880
|
||||||
|
tls:
|
||||||
|
secretName: internal-wildcard-tls
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
nameOverride: victoria-operator
|
||||||
|
|
||||||
|
operator:
|
||||||
|
enable_converter_ownership: true
|
||||||
|
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 96Mi
|
||||||
|
limits:
|
||||||
|
cpu: 200m
|
||||||
|
memory: 256Mi
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: victoria-metrics
|
||||||
|
namespace: prometheus
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: victoria-metrics
|
||||||
|
ports:
|
||||||
|
- port: 8428
|
||||||
|
targetPort: 8428
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: victoria-pvc
|
||||||
|
namespace: prometheus
|
||||||
|
spec:
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 10Gi
|
||||||
|
volumeMode: Filesystem
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: victoria-deployment
|
||||||
|
namespace: prometheus
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: victoria-metrics
|
||||||
|
strategy:
|
||||||
|
type: Recreate
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: victoria-metrics
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: victoria
|
||||||
|
image: victoriametrics/victoria-metrics:v1.153.0-scratch
|
||||||
|
args:
|
||||||
|
- -storageDataPath=/vmdata
|
||||||
|
- -retentionPeriod=30d
|
||||||
|
- -httpListenAddr=:8428
|
||||||
|
ports:
|
||||||
|
- containerPort: 8428
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /health
|
||||||
|
port: 8428
|
||||||
|
initialDelaySeconds: 15
|
||||||
|
periodSeconds: 10
|
||||||
|
failureThreshold: 6
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /health
|
||||||
|
port: 8428
|
||||||
|
initialDelaySeconds: 60
|
||||||
|
periodSeconds: 30
|
||||||
|
failureThreshold: 3
|
||||||
|
volumeMounts:
|
||||||
|
- name: vmdata
|
||||||
|
mountPath: /vmdata
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: "100m"
|
||||||
|
memory: "256Mi"
|
||||||
|
limits:
|
||||||
|
cpu: "1000m"
|
||||||
|
memory: "1Gi"
|
||||||
|
volumes:
|
||||||
|
- name: vmdata
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: victoria-pvc
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
apiVersion: operator.victoriametrics.com/v1beta1
|
||||||
|
kind: VMAgent
|
||||||
|
metadata:
|
||||||
|
name: vmagent
|
||||||
|
namespace: prometheus
|
||||||
|
spec:
|
||||||
|
image:
|
||||||
|
tag: v1.153.0
|
||||||
|
scrapeInterval: 30s
|
||||||
|
externalLabels:
|
||||||
|
scraper: victoria
|
||||||
|
serviceScrapeNamespaceSelector: {}
|
||||||
|
serviceScrapeSelector:
|
||||||
|
matchLabels:
|
||||||
|
release: prometheus-stack
|
||||||
|
globalScrapeRelabelConfigs:
|
||||||
|
- action: drop
|
||||||
|
source_labels:
|
||||||
|
- __meta_kubernetes_service_name
|
||||||
|
regex: prometheus-stack-kube-prom-prometheus
|
||||||
|
remoteWrite:
|
||||||
|
- url: http://victoria-metrics.prometheus.svc.cluster.local:8428/api/v1/write
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 256Mi
|
||||||
|
limits:
|
||||||
|
cpu: "1000m"
|
||||||
|
memory: 1Gi
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: vmalert
|
||||||
|
namespace: prometheus
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: vmalert
|
||||||
|
ports:
|
||||||
|
- port: 8880
|
||||||
|
targetPort: 8880
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: vmalert-deployment
|
||||||
|
namespace: prometheus
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: vmalert
|
||||||
|
strategy:
|
||||||
|
type: Recreate
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: vmalert
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: vmalert
|
||||||
|
image: victoriametrics/vmalert:v1.153.0
|
||||||
|
args:
|
||||||
|
- -datasource.url=http://victoria-metrics.prometheus.svc.cluster.local:8428
|
||||||
|
- -remoteWrite.url=http://victoria-metrics.prometheus.svc.cluster.local:8428
|
||||||
|
- -notifier.url=http://prometheus-stack-kube-prom-alertmanager.prometheus.svc.cluster.local:9093
|
||||||
|
- -rule=/etc/vm/rules/*.yaml
|
||||||
|
- -evaluationInterval=60s
|
||||||
|
- -httpListenAddr=:8880
|
||||||
|
ports:
|
||||||
|
- containerPort: 8880
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /metrics
|
||||||
|
port: 8880
|
||||||
|
initialDelaySeconds: 15
|
||||||
|
periodSeconds: 10
|
||||||
|
failureThreshold: 6
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /metrics
|
||||||
|
port: 8880
|
||||||
|
initialDelaySeconds: 60
|
||||||
|
periodSeconds: 30
|
||||||
|
failureThreshold: 3
|
||||||
|
volumeMounts:
|
||||||
|
- name: rules
|
||||||
|
mountPath: /etc/vm/rules
|
||||||
|
readOnly: true
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: "50m"
|
||||||
|
memory: "64Mi"
|
||||||
|
limits:
|
||||||
|
cpu: "200m"
|
||||||
|
memory: "256Mi"
|
||||||
|
volumes:
|
||||||
|
- name: rules
|
||||||
|
configMap:
|
||||||
|
name: prometheus-prometheus-stack-kube-prom-prometheus-rulefiles-0
|
||||||
Whitespace-only changes.
@@ -1,11 +1,17 @@
|
|||||||
# Pinned chart: stakater/reloader 2.2.17 (app v1.4.22).
|
# Pinned chart: stakater/reloader 2.2.17 (app v1.4.22).
|
||||||
# Deployed by the deploy workflow, namespace reloader.
|
# Deployed by the deploy workflow, namespace reloader.
|
||||||
# Restarts pods when a ConfigMap or Secret they consume changes. Opt-in per workload
|
# Restarts pods when a ConfigMap or Secret they consume changes. Opt-in per workload
|
||||||
# via the reloader.stakater.com/auto: "true" pod annotation; watchGlobally because
|
# via the reloader.stakater.com/auto: "true" workload annotation; watchGlobally because
|
||||||
# the workloads that need it are spread across a few dozen namespaces.
|
# the workloads that need it are spread across a few dozen namespaces.
|
||||||
|
|
||||||
reloader:
|
reloader:
|
||||||
watchGlobally: true
|
watchGlobally: true
|
||||||
|
# Only opted-in workloads are restarted. Keep scheduled jobs on their schedule.
|
||||||
|
autoReloadAll: false
|
||||||
|
ignoreJobs: true
|
||||||
|
ignoreCronJobs: true
|
||||||
|
# Change pod-template annotations rather than injecting STAKATER_* env vars.
|
||||||
|
reloadStrategy: annotations
|
||||||
|
|
||||||
deployment:
|
deployment:
|
||||||
replicas: 1
|
replicas: 1
|
||||||
|
|||||||
+48
-25
@@ -19,6 +19,9 @@ data:
|
|||||||
"dependencyDashboard": true,
|
"dependencyDashboard": true,
|
||||||
"prCreation": "immediate",
|
"prCreation": "immediate",
|
||||||
"labels": ["dependencies", "automated"],
|
"labels": ["dependencies", "automated"],
|
||||||
|
"docker-compose": {
|
||||||
|
"managerFilePatterns": ["renovate/renovate-compose.yaml"]
|
||||||
|
},
|
||||||
"helm-values": {
|
"helm-values": {
|
||||||
"managerFilePatterns": ["/k8s/.+values\\.ya?ml$/"]
|
"managerFilePatterns": ["/k8s/.+values\\.ya?ml$/"]
|
||||||
},
|
},
|
||||||
@@ -29,7 +32,7 @@ data:
|
|||||||
{
|
{
|
||||||
"customType": "regex",
|
"customType": "regex",
|
||||||
"description": "singlesource: playwright npm version pinned in npx command (k8s + compose)",
|
"description": "singlesource: playwright npm version pinned in npx command (k8s + compose)",
|
||||||
"managerFilePatterns": ["^edu_master/k8s/playwright\\.yaml$", "^edu_master/compose\\.yaml$"],
|
"managerFilePatterns": ["edu_master/k8s/playwright.yaml", "edu_master/compose.yaml"],
|
||||||
"matchStrings": ["playwright@(?<currentValue>\\d+\\.\\d+\\.\\d+)"],
|
"matchStrings": ["playwright@(?<currentValue>\\d+\\.\\d+\\.\\d+)"],
|
||||||
"datasourceTemplate": "npm",
|
"datasourceTemplate": "npm",
|
||||||
"depNameTemplate": "playwright"
|
"depNameTemplate": "playwright"
|
||||||
@@ -37,24 +40,42 @@ data:
|
|||||||
{
|
{
|
||||||
"customType": "regex",
|
"customType": "regex",
|
||||||
"description": "singlesource: PLAYWRIGHT_VERSION file",
|
"description": "singlesource: PLAYWRIGHT_VERSION file",
|
||||||
"managerFilePatterns": ["^edu_master/PLAYWRIGHT_VERSION$"],
|
"managerFilePatterns": ["edu_master/PLAYWRIGHT_VERSION"],
|
||||||
"matchStrings": ["^(?<currentValue>\\d+\\.\\d+\\.\\d+)$"],
|
"matchStrings": ["^(?<currentValue>\\d+\\.\\d+\\.\\d+)(?:\\r?\\n)?$"],
|
||||||
"datasourceTemplate": "pypi",
|
"datasourceTemplate": "pypi",
|
||||||
"depNameTemplate": "playwright"
|
"depNameTemplate": "playwright"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"customType": "regex",
|
||||||
|
"description": "singlesource: playwright Python client version pinned in Dockerfile ARG",
|
||||||
|
"managerFilePatterns": ["edu_master/webinar-checker/Dockerfile"],
|
||||||
|
"matchStrings": ["(?:^|\\n)ARG PLAYWRIGHT_VERSION=(?<currentValue>\\d+\\.\\d+\\.\\d+)(?:\\r?\\n|$)"],
|
||||||
|
"datasourceTemplate": "pypi",
|
||||||
|
"depNameTemplate": "playwright",
|
||||||
|
"versioningTemplate": "pep440"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"customType": "regex",
|
"customType": "regex",
|
||||||
"description": "kube-prometheus-stack chart version pinned in the deploy workflow",
|
"description": "kube-prometheus-stack chart version pinned in the deploy workflow",
|
||||||
"managerFilePatterns": ["^\\.gitea/workflows/deploy-lib\\.sh$"],
|
"managerFilePatterns": [".gitea/workflows/deploy-lib.sh"],
|
||||||
"matchStrings": ["\\|prometheus-community/kube-prometheus-stack\\|prometheus\\|(?<currentValue>[0-9.]+)\\|"],
|
"matchStrings": ["\\|prometheus-community/kube-prometheus-stack\\|prometheus\\|(?<currentValue>[0-9.]+)\\|"],
|
||||||
"datasourceTemplate": "helm",
|
"datasourceTemplate": "helm",
|
||||||
"depNameTemplate": "kube-prometheus-stack",
|
"depNameTemplate": "kube-prometheus-stack",
|
||||||
"registryUrlTemplate": "https://prometheus-community.github.io/helm-charts"
|
"registryUrlTemplate": "https://prometheus-community.github.io/helm-charts"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"customType": "regex",
|
||||||
|
"description": "VictoriaMetrics Operator chart version pinned in the deploy workflow",
|
||||||
|
"managerFilePatterns": [".gitea/workflows/deploy-lib.sh"],
|
||||||
|
"matchStrings": ["\\|victoriametrics/victoria-metrics-operator\\|prometheus\\|(?<currentValue>[0-9.]+)\\|"],
|
||||||
|
"datasourceTemplate": "helm",
|
||||||
|
"depNameTemplate": "victoria-metrics-operator",
|
||||||
|
"registryUrlTemplate": "https://victoriametrics.github.io/helm-charts"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"customType": "regex",
|
"customType": "regex",
|
||||||
"description": "grafana/loki chart version pinned in the deploy workflow",
|
"description": "grafana/loki chart version pinned in the deploy workflow",
|
||||||
"managerFilePatterns": ["^\\.gitea/workflows/deploy-lib\\.sh$"],
|
"managerFilePatterns": [".gitea/workflows/deploy-lib.sh"],
|
||||||
"matchStrings": ["\\|grafana/loki\\|prometheus\\|(?<currentValue>[0-9.]+)\\|"],
|
"matchStrings": ["\\|grafana/loki\\|prometheus\\|(?<currentValue>[0-9.]+)\\|"],
|
||||||
"datasourceTemplate": "helm",
|
"datasourceTemplate": "helm",
|
||||||
"depNameTemplate": "loki",
|
"depNameTemplate": "loki",
|
||||||
@@ -63,7 +84,7 @@ data:
|
|||||||
{
|
{
|
||||||
"customType": "regex",
|
"customType": "regex",
|
||||||
"description": "grafana/alloy chart version pinned in the deploy workflow",
|
"description": "grafana/alloy chart version pinned in the deploy workflow",
|
||||||
"managerFilePatterns": ["^\\.gitea/workflows/deploy-lib\\.sh$"],
|
"managerFilePatterns": [".gitea/workflows/deploy-lib.sh"],
|
||||||
"matchStrings": ["\\|grafana/alloy\\|prometheus\\|(?<currentValue>[0-9.]+)\\|"],
|
"matchStrings": ["\\|grafana/alloy\\|prometheus\\|(?<currentValue>[0-9.]+)\\|"],
|
||||||
"datasourceTemplate": "helm",
|
"datasourceTemplate": "helm",
|
||||||
"depNameTemplate": "alloy",
|
"depNameTemplate": "alloy",
|
||||||
@@ -72,7 +93,7 @@ data:
|
|||||||
{
|
{
|
||||||
"customType": "regex",
|
"customType": "regex",
|
||||||
"description": "actionlint version used by the ci workflow",
|
"description": "actionlint version used by the ci workflow",
|
||||||
"managerFilePatterns": ["^\\.gitea/workflows/tool-versions\\.env$"],
|
"managerFilePatterns": [".gitea/workflows/tool-versions.env"],
|
||||||
"matchStrings": ["(?:^|\\n)ACTIONLINT_VERSION=\"(?<currentValue>[0-9.]+)\""],
|
"matchStrings": ["(?:^|\\n)ACTIONLINT_VERSION=\"(?<currentValue>[0-9.]+)\""],
|
||||||
"datasourceTemplate": "github-tags",
|
"datasourceTemplate": "github-tags",
|
||||||
"depNameTemplate": "rhysd/actionlint"
|
"depNameTemplate": "rhysd/actionlint"
|
||||||
@@ -80,7 +101,7 @@ data:
|
|||||||
{
|
{
|
||||||
"customType": "regex",
|
"customType": "regex",
|
||||||
"description": "shellcheck version used by the ci workflow",
|
"description": "shellcheck version used by the ci workflow",
|
||||||
"managerFilePatterns": ["^\\.gitea/workflows/tool-versions\\.env$"],
|
"managerFilePatterns": [".gitea/workflows/tool-versions.env"],
|
||||||
"matchStrings": ["(?:^|\\n)SHELLCHECK_VERSION=\"(?<currentValue>[0-9.]+)\""],
|
"matchStrings": ["(?:^|\\n)SHELLCHECK_VERSION=\"(?<currentValue>[0-9.]+)\""],
|
||||||
"datasourceTemplate": "github-tags",
|
"datasourceTemplate": "github-tags",
|
||||||
"depNameTemplate": "koalaman/shellcheck"
|
"depNameTemplate": "koalaman/shellcheck"
|
||||||
@@ -88,7 +109,7 @@ data:
|
|||||||
{
|
{
|
||||||
"customType": "regex",
|
"customType": "regex",
|
||||||
"description": "kubeconform version used by the ci workflow",
|
"description": "kubeconform version used by the ci workflow",
|
||||||
"managerFilePatterns": ["^\\.gitea/workflows/tool-versions\\.env$"],
|
"managerFilePatterns": [".gitea/workflows/tool-versions.env"],
|
||||||
"matchStrings": ["(?:^|\\n)KUBECONFORM_VERSION=\"(?<currentValue>[0-9.]+)\""],
|
"matchStrings": ["(?:^|\\n)KUBECONFORM_VERSION=\"(?<currentValue>[0-9.]+)\""],
|
||||||
"datasourceTemplate": "github-tags",
|
"datasourceTemplate": "github-tags",
|
||||||
"depNameTemplate": "yannh/kubeconform"
|
"depNameTemplate": "yannh/kubeconform"
|
||||||
@@ -96,7 +117,7 @@ data:
|
|||||||
{
|
{
|
||||||
"customType": "regex",
|
"customType": "regex",
|
||||||
"description": "uv version used to build the pytest venv",
|
"description": "uv version used to build the pytest venv",
|
||||||
"managerFilePatterns": ["^\\.gitea/workflows/tool-versions\\.env$"],
|
"managerFilePatterns": [".gitea/workflows/tool-versions.env"],
|
||||||
"matchStrings": ["(?:^|\\n)UV_VERSION=\"(?<currentValue>[0-9.]+)\""],
|
"matchStrings": ["(?:^|\\n)UV_VERSION=\"(?<currentValue>[0-9.]+)\""],
|
||||||
"datasourceTemplate": "github-tags",
|
"datasourceTemplate": "github-tags",
|
||||||
"depNameTemplate": "astral-sh/uv"
|
"depNameTemplate": "astral-sh/uv"
|
||||||
@@ -104,7 +125,7 @@ data:
|
|||||||
{
|
{
|
||||||
"customType": "regex",
|
"customType": "regex",
|
||||||
"description": "prettier version used by the ci workflow",
|
"description": "prettier version used by the ci workflow",
|
||||||
"managerFilePatterns": ["^\\.gitea/workflows/tool-versions\\.env$"],
|
"managerFilePatterns": [".gitea/workflows/tool-versions.env"],
|
||||||
"matchStrings": ["(?:^|\\n)PRETTIER_VERSION=\"(?<currentValue>[0-9.]+)\""],
|
"matchStrings": ["(?:^|\\n)PRETTIER_VERSION=\"(?<currentValue>[0-9.]+)\""],
|
||||||
"datasourceTemplate": "npm",
|
"datasourceTemplate": "npm",
|
||||||
"depNameTemplate": "prettier"
|
"depNameTemplate": "prettier"
|
||||||
@@ -112,7 +133,7 @@ data:
|
|||||||
{
|
{
|
||||||
"customType": "regex",
|
"customType": "regex",
|
||||||
"description": "ruff version used by the ci workflow",
|
"description": "ruff version used by the ci workflow",
|
||||||
"managerFilePatterns": ["^\\.gitea/workflows/tool-versions\\.env$"],
|
"managerFilePatterns": [".gitea/workflows/tool-versions.env"],
|
||||||
"matchStrings": ["(?:^|\\n)RUFF_VERSION=\"(?<currentValue>[0-9.]+)\""],
|
"matchStrings": ["(?:^|\\n)RUFF_VERSION=\"(?<currentValue>[0-9.]+)\""],
|
||||||
"datasourceTemplate": "pypi",
|
"datasourceTemplate": "pypi",
|
||||||
"depNameTemplate": "ruff"
|
"depNameTemplate": "ruff"
|
||||||
@@ -120,7 +141,7 @@ data:
|
|||||||
{
|
{
|
||||||
"customType": "regex",
|
"customType": "regex",
|
||||||
"description": "pip-audit version used by the ci workflow",
|
"description": "pip-audit version used by the ci workflow",
|
||||||
"managerFilePatterns": ["^\\.gitea/workflows/tool-versions\\.env$"],
|
"managerFilePatterns": [".gitea/workflows/tool-versions.env"],
|
||||||
"matchStrings": ["(?:^|\\n)PIP_AUDIT_VERSION=\"(?<currentValue>[0-9.]+)\""],
|
"matchStrings": ["(?:^|\\n)PIP_AUDIT_VERSION=\"(?<currentValue>[0-9.]+)\""],
|
||||||
"datasourceTemplate": "pypi",
|
"datasourceTemplate": "pypi",
|
||||||
"depNameTemplate": "pip-audit"
|
"depNameTemplate": "pip-audit"
|
||||||
@@ -128,7 +149,7 @@ data:
|
|||||||
{
|
{
|
||||||
"customType": "regex",
|
"customType": "regex",
|
||||||
"description": "yamllint version used by the ci workflow",
|
"description": "yamllint version used by the ci workflow",
|
||||||
"managerFilePatterns": ["^\\.gitea/workflows/tool-versions\\.env$"],
|
"managerFilePatterns": [".gitea/workflows/tool-versions.env"],
|
||||||
"matchStrings": ["(?:^|\\n)YAMLLINT_VERSION=\"(?<currentValue>[0-9.]+)\""],
|
"matchStrings": ["(?:^|\\n)YAMLLINT_VERSION=\"(?<currentValue>[0-9.]+)\""],
|
||||||
"datasourceTemplate": "pypi",
|
"datasourceTemplate": "pypi",
|
||||||
"depNameTemplate": "yamllint"
|
"depNameTemplate": "yamllint"
|
||||||
@@ -136,7 +157,7 @@ data:
|
|||||||
{
|
{
|
||||||
"customType": "regex",
|
"customType": "regex",
|
||||||
"description": "hadolint version used by the ci workflow",
|
"description": "hadolint version used by the ci workflow",
|
||||||
"managerFilePatterns": ["^\\.gitea/workflows/tool-versions\\.env$"],
|
"managerFilePatterns": [".gitea/workflows/tool-versions.env"],
|
||||||
"matchStrings": ["(?:^|\\n)HADOLINT_VERSION=\"(?<currentValue>[0-9.]+)\""],
|
"matchStrings": ["(?:^|\\n)HADOLINT_VERSION=\"(?<currentValue>[0-9.]+)\""],
|
||||||
"datasourceTemplate": "github-tags",
|
"datasourceTemplate": "github-tags",
|
||||||
"depNameTemplate": "hadolint/hadolint"
|
"depNameTemplate": "hadolint/hadolint"
|
||||||
@@ -144,7 +165,7 @@ data:
|
|||||||
{
|
{
|
||||||
"customType": "regex",
|
"customType": "regex",
|
||||||
"description": "node version the ci workflow runs npm with",
|
"description": "node version the ci workflow runs npm with",
|
||||||
"managerFilePatterns": ["^\\.gitea/workflows/tool-versions\\.env$"],
|
"managerFilePatterns": [".gitea/workflows/tool-versions.env"],
|
||||||
"matchStrings": ["(?:^|\\n)NODE_VERSION=\"(?<currentValue>[0-9.]+)\""],
|
"matchStrings": ["(?:^|\\n)NODE_VERSION=\"(?<currentValue>[0-9.]+)\""],
|
||||||
"datasourceTemplate": "node",
|
"datasourceTemplate": "node",
|
||||||
"depNameTemplate": "node"
|
"depNameTemplate": "node"
|
||||||
@@ -152,7 +173,7 @@ data:
|
|||||||
{
|
{
|
||||||
"customType": "regex",
|
"customType": "regex",
|
||||||
"description": "stakater/reloader chart version pinned in the deploy workflow",
|
"description": "stakater/reloader chart version pinned in the deploy workflow",
|
||||||
"managerFilePatterns": ["^\\.gitea/workflows/deploy-lib\\.sh$"],
|
"managerFilePatterns": [".gitea/workflows/deploy-lib.sh"],
|
||||||
"matchStrings": ["\\|stakater/reloader\\|reloader\\|(?<currentValue>[0-9.]+)\\|"],
|
"matchStrings": ["\\|stakater/reloader\\|reloader\\|(?<currentValue>[0-9.]+)\\|"],
|
||||||
"datasourceTemplate": "helm",
|
"datasourceTemplate": "helm",
|
||||||
"depNameTemplate": "reloader",
|
"depNameTemplate": "reloader",
|
||||||
@@ -161,7 +182,7 @@ data:
|
|||||||
],
|
],
|
||||||
"packageRules": [
|
"packageRules": [
|
||||||
{
|
{
|
||||||
"description": "Automerge digest and patch updates - safe by definition, review adds nothing, keeps the renovate queue and the deploy line short. Specific no-automerge rules below still override this for playwright, helm and majors.",
|
"description": "Automerge ordinary digest and patch updates after successful checks; specific manual-review rules below override this.",
|
||||||
"matchUpdateTypes": ["digest", "patch"],
|
"matchUpdateTypes": ["digest", "patch"],
|
||||||
"automerge": true
|
"automerge": true
|
||||||
},
|
},
|
||||||
@@ -172,6 +193,12 @@ data:
|
|||||||
"groupSlug": "all-minor",
|
"groupSlug": "all-minor",
|
||||||
"automerge": false
|
"automerge": false
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"description": "Group ordinary patch updates; the specific groups and manual-review rules below take precedence",
|
||||||
|
"matchUpdateTypes": ["patch"],
|
||||||
|
"groupName": "all patch updates",
|
||||||
|
"groupSlug": "all-patch"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"description": "Keep private homelab images unchanged",
|
"description": "Keep private homelab images unchanged",
|
||||||
"matchDatasources": ["docker"],
|
"matchDatasources": ["docker"],
|
||||||
@@ -196,7 +223,7 @@ data:
|
|||||||
"automerge": false
|
"automerge": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "CI runs npm on the node the panel image is built from - the NODE_VERSION pin in tool-versions.env and node:22-alpine in the Dockerfile are the same dependency and move as one",
|
"description": "Keep CI Node runtime updates in a separate, manually reviewed group",
|
||||||
"matchPackageNames": ["node"],
|
"matchPackageNames": ["node"],
|
||||||
"groupName": "node runtime",
|
"groupName": "node runtime",
|
||||||
"groupSlug": "node",
|
"groupSlug": "node",
|
||||||
@@ -205,6 +232,8 @@ data:
|
|||||||
{
|
{
|
||||||
"description": "Helm chart bumps change PVC fields and admission behaviour, keep them reviewable",
|
"description": "Helm chart bumps change PVC fields and admission behaviour, keep them reviewable",
|
||||||
"matchDatasources": ["helm"],
|
"matchDatasources": ["helm"],
|
||||||
|
"groupName": "Helm chart {{depName}}",
|
||||||
|
"groupSlug": "helm-{{depName}}",
|
||||||
"automerge": false
|
"automerge": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -213,12 +242,6 @@ data:
|
|||||||
"dependencyDashboardApproval": true,
|
"dependencyDashboardApproval": true,
|
||||||
"automerge": false
|
"automerge": false
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"description": "Group patch updates from all sources - automerge still applies via the digest/patch rule above (helm/playwright stay manual via their own rules)",
|
|
||||||
"matchUpdateTypes": ["patch"],
|
|
||||||
"groupName": "all patch updates",
|
|
||||||
"groupSlug": "all-patch"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"description": "Python Y-bumps break compat (3.11->3.12->3.13->3.14) - keep the base image out of the shared minor/patch groups, review every bump separately. Placed last so its groupName wins.",
|
"description": "Python Y-bumps break compat (3.11->3.12->3.13->3.14) - keep the base image out of the shared minor/patch groups, review every bump separately. Placed last so its groupName wins.",
|
||||||
"matchDatasources": ["docker"],
|
"matchDatasources": ["docker"],
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ spec:
|
|||||||
restartPolicy: Never
|
restartPolicy: Never
|
||||||
containers:
|
containers:
|
||||||
- name: renovate
|
- name: renovate
|
||||||
image: renovate/renovate:44.136.0
|
image: renovate/renovate:44.140.0
|
||||||
env:
|
env:
|
||||||
- name: RENOVATE_PLATFORM
|
- name: RENOVATE_PLATFORM
|
||||||
value: gitea
|
value: gitea
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ services:
|
|||||||
renovate:
|
renovate:
|
||||||
# Kept in step with renovate/k8s/cronjob.yaml by the "renovate self-update"
|
# Kept in step with renovate/k8s/cronjob.yaml by the "renovate self-update"
|
||||||
# package rule in renovate/renovate.json.
|
# package rule in renovate/renovate.json.
|
||||||
image: renovate/renovate:44.115.9
|
image: renovate/renovate:44.136.0
|
||||||
container_name: renovate
|
container_name: renovate
|
||||||
restart: "no"
|
restart: "no"
|
||||||
env_file:
|
env_file:
|
||||||
|
|||||||
+48
-25
@@ -8,6 +8,9 @@
|
|||||||
"dependencyDashboard": true,
|
"dependencyDashboard": true,
|
||||||
"prCreation": "immediate",
|
"prCreation": "immediate",
|
||||||
"labels": ["dependencies", "automated"],
|
"labels": ["dependencies", "automated"],
|
||||||
|
"docker-compose": {
|
||||||
|
"managerFilePatterns": ["renovate/renovate-compose.yaml"]
|
||||||
|
},
|
||||||
"helm-values": {
|
"helm-values": {
|
||||||
"managerFilePatterns": ["/k8s/.+values\\.ya?ml$/"]
|
"managerFilePatterns": ["/k8s/.+values\\.ya?ml$/"]
|
||||||
},
|
},
|
||||||
@@ -18,7 +21,7 @@
|
|||||||
{
|
{
|
||||||
"customType": "regex",
|
"customType": "regex",
|
||||||
"description": "singlesource: playwright npm version pinned in npx command (k8s + compose)",
|
"description": "singlesource: playwright npm version pinned in npx command (k8s + compose)",
|
||||||
"managerFilePatterns": ["^edu_master/k8s/playwright\\.yaml$", "^edu_master/compose\\.yaml$"],
|
"managerFilePatterns": ["edu_master/k8s/playwright.yaml", "edu_master/compose.yaml"],
|
||||||
"matchStrings": ["playwright@(?<currentValue>\\d+\\.\\d+\\.\\d+)"],
|
"matchStrings": ["playwright@(?<currentValue>\\d+\\.\\d+\\.\\d+)"],
|
||||||
"datasourceTemplate": "npm",
|
"datasourceTemplate": "npm",
|
||||||
"depNameTemplate": "playwright"
|
"depNameTemplate": "playwright"
|
||||||
@@ -26,24 +29,42 @@
|
|||||||
{
|
{
|
||||||
"customType": "regex",
|
"customType": "regex",
|
||||||
"description": "singlesource: PLAYWRIGHT_VERSION file",
|
"description": "singlesource: PLAYWRIGHT_VERSION file",
|
||||||
"managerFilePatterns": ["^edu_master/PLAYWRIGHT_VERSION$"],
|
"managerFilePatterns": ["edu_master/PLAYWRIGHT_VERSION"],
|
||||||
"matchStrings": ["^(?<currentValue>\\d+\\.\\d+\\.\\d+)$"],
|
"matchStrings": ["^(?<currentValue>\\d+\\.\\d+\\.\\d+)(?:\\r?\\n)?$"],
|
||||||
"datasourceTemplate": "pypi",
|
"datasourceTemplate": "pypi",
|
||||||
"depNameTemplate": "playwright"
|
"depNameTemplate": "playwright"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"customType": "regex",
|
||||||
|
"description": "singlesource: playwright Python client version pinned in Dockerfile ARG",
|
||||||
|
"managerFilePatterns": ["edu_master/webinar-checker/Dockerfile"],
|
||||||
|
"matchStrings": ["(?:^|\\n)ARG PLAYWRIGHT_VERSION=(?<currentValue>\\d+\\.\\d+\\.\\d+)(?:\\r?\\n|$)"],
|
||||||
|
"datasourceTemplate": "pypi",
|
||||||
|
"depNameTemplate": "playwright",
|
||||||
|
"versioningTemplate": "pep440"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"customType": "regex",
|
"customType": "regex",
|
||||||
"description": "kube-prometheus-stack chart version pinned in the deploy workflow",
|
"description": "kube-prometheus-stack chart version pinned in the deploy workflow",
|
||||||
"managerFilePatterns": ["^\\.gitea/workflows/deploy-lib\\.sh$"],
|
"managerFilePatterns": [".gitea/workflows/deploy-lib.sh"],
|
||||||
"matchStrings": ["\\|prometheus-community/kube-prometheus-stack\\|prometheus\\|(?<currentValue>[0-9.]+)\\|"],
|
"matchStrings": ["\\|prometheus-community/kube-prometheus-stack\\|prometheus\\|(?<currentValue>[0-9.]+)\\|"],
|
||||||
"datasourceTemplate": "helm",
|
"datasourceTemplate": "helm",
|
||||||
"depNameTemplate": "kube-prometheus-stack",
|
"depNameTemplate": "kube-prometheus-stack",
|
||||||
"registryUrlTemplate": "https://prometheus-community.github.io/helm-charts"
|
"registryUrlTemplate": "https://prometheus-community.github.io/helm-charts"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"customType": "regex",
|
||||||
|
"description": "VictoriaMetrics Operator chart version pinned in the deploy workflow",
|
||||||
|
"managerFilePatterns": [".gitea/workflows/deploy-lib.sh"],
|
||||||
|
"matchStrings": ["\\|victoriametrics/victoria-metrics-operator\\|prometheus\\|(?<currentValue>[0-9.]+)\\|"],
|
||||||
|
"datasourceTemplate": "helm",
|
||||||
|
"depNameTemplate": "victoria-metrics-operator",
|
||||||
|
"registryUrlTemplate": "https://victoriametrics.github.io/helm-charts"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"customType": "regex",
|
"customType": "regex",
|
||||||
"description": "grafana/loki chart version pinned in the deploy workflow",
|
"description": "grafana/loki chart version pinned in the deploy workflow",
|
||||||
"managerFilePatterns": ["^\\.gitea/workflows/deploy-lib\\.sh$"],
|
"managerFilePatterns": [".gitea/workflows/deploy-lib.sh"],
|
||||||
"matchStrings": ["\\|grafana/loki\\|prometheus\\|(?<currentValue>[0-9.]+)\\|"],
|
"matchStrings": ["\\|grafana/loki\\|prometheus\\|(?<currentValue>[0-9.]+)\\|"],
|
||||||
"datasourceTemplate": "helm",
|
"datasourceTemplate": "helm",
|
||||||
"depNameTemplate": "loki",
|
"depNameTemplate": "loki",
|
||||||
@@ -52,7 +73,7 @@
|
|||||||
{
|
{
|
||||||
"customType": "regex",
|
"customType": "regex",
|
||||||
"description": "grafana/alloy chart version pinned in the deploy workflow",
|
"description": "grafana/alloy chart version pinned in the deploy workflow",
|
||||||
"managerFilePatterns": ["^\\.gitea/workflows/deploy-lib\\.sh$"],
|
"managerFilePatterns": [".gitea/workflows/deploy-lib.sh"],
|
||||||
"matchStrings": ["\\|grafana/alloy\\|prometheus\\|(?<currentValue>[0-9.]+)\\|"],
|
"matchStrings": ["\\|grafana/alloy\\|prometheus\\|(?<currentValue>[0-9.]+)\\|"],
|
||||||
"datasourceTemplate": "helm",
|
"datasourceTemplate": "helm",
|
||||||
"depNameTemplate": "alloy",
|
"depNameTemplate": "alloy",
|
||||||
@@ -61,7 +82,7 @@
|
|||||||
{
|
{
|
||||||
"customType": "regex",
|
"customType": "regex",
|
||||||
"description": "actionlint version used by the ci workflow",
|
"description": "actionlint version used by the ci workflow",
|
||||||
"managerFilePatterns": ["^\\.gitea/workflows/tool-versions\\.env$"],
|
"managerFilePatterns": [".gitea/workflows/tool-versions.env"],
|
||||||
"matchStrings": ["(?:^|\\n)ACTIONLINT_VERSION=\"(?<currentValue>[0-9.]+)\""],
|
"matchStrings": ["(?:^|\\n)ACTIONLINT_VERSION=\"(?<currentValue>[0-9.]+)\""],
|
||||||
"datasourceTemplate": "github-tags",
|
"datasourceTemplate": "github-tags",
|
||||||
"depNameTemplate": "rhysd/actionlint"
|
"depNameTemplate": "rhysd/actionlint"
|
||||||
@@ -69,7 +90,7 @@
|
|||||||
{
|
{
|
||||||
"customType": "regex",
|
"customType": "regex",
|
||||||
"description": "shellcheck version used by the ci workflow",
|
"description": "shellcheck version used by the ci workflow",
|
||||||
"managerFilePatterns": ["^\\.gitea/workflows/tool-versions\\.env$"],
|
"managerFilePatterns": [".gitea/workflows/tool-versions.env"],
|
||||||
"matchStrings": ["(?:^|\\n)SHELLCHECK_VERSION=\"(?<currentValue>[0-9.]+)\""],
|
"matchStrings": ["(?:^|\\n)SHELLCHECK_VERSION=\"(?<currentValue>[0-9.]+)\""],
|
||||||
"datasourceTemplate": "github-tags",
|
"datasourceTemplate": "github-tags",
|
||||||
"depNameTemplate": "koalaman/shellcheck"
|
"depNameTemplate": "koalaman/shellcheck"
|
||||||
@@ -77,7 +98,7 @@
|
|||||||
{
|
{
|
||||||
"customType": "regex",
|
"customType": "regex",
|
||||||
"description": "kubeconform version used by the ci workflow",
|
"description": "kubeconform version used by the ci workflow",
|
||||||
"managerFilePatterns": ["^\\.gitea/workflows/tool-versions\\.env$"],
|
"managerFilePatterns": [".gitea/workflows/tool-versions.env"],
|
||||||
"matchStrings": ["(?:^|\\n)KUBECONFORM_VERSION=\"(?<currentValue>[0-9.]+)\""],
|
"matchStrings": ["(?:^|\\n)KUBECONFORM_VERSION=\"(?<currentValue>[0-9.]+)\""],
|
||||||
"datasourceTemplate": "github-tags",
|
"datasourceTemplate": "github-tags",
|
||||||
"depNameTemplate": "yannh/kubeconform"
|
"depNameTemplate": "yannh/kubeconform"
|
||||||
@@ -85,7 +106,7 @@
|
|||||||
{
|
{
|
||||||
"customType": "regex",
|
"customType": "regex",
|
||||||
"description": "uv version used to build the pytest venv",
|
"description": "uv version used to build the pytest venv",
|
||||||
"managerFilePatterns": ["^\\.gitea/workflows/tool-versions\\.env$"],
|
"managerFilePatterns": [".gitea/workflows/tool-versions.env"],
|
||||||
"matchStrings": ["(?:^|\\n)UV_VERSION=\"(?<currentValue>[0-9.]+)\""],
|
"matchStrings": ["(?:^|\\n)UV_VERSION=\"(?<currentValue>[0-9.]+)\""],
|
||||||
"datasourceTemplate": "github-tags",
|
"datasourceTemplate": "github-tags",
|
||||||
"depNameTemplate": "astral-sh/uv"
|
"depNameTemplate": "astral-sh/uv"
|
||||||
@@ -93,7 +114,7 @@
|
|||||||
{
|
{
|
||||||
"customType": "regex",
|
"customType": "regex",
|
||||||
"description": "prettier version used by the ci workflow",
|
"description": "prettier version used by the ci workflow",
|
||||||
"managerFilePatterns": ["^\\.gitea/workflows/tool-versions\\.env$"],
|
"managerFilePatterns": [".gitea/workflows/tool-versions.env"],
|
||||||
"matchStrings": ["(?:^|\\n)PRETTIER_VERSION=\"(?<currentValue>[0-9.]+)\""],
|
"matchStrings": ["(?:^|\\n)PRETTIER_VERSION=\"(?<currentValue>[0-9.]+)\""],
|
||||||
"datasourceTemplate": "npm",
|
"datasourceTemplate": "npm",
|
||||||
"depNameTemplate": "prettier"
|
"depNameTemplate": "prettier"
|
||||||
@@ -101,7 +122,7 @@
|
|||||||
{
|
{
|
||||||
"customType": "regex",
|
"customType": "regex",
|
||||||
"description": "ruff version used by the ci workflow",
|
"description": "ruff version used by the ci workflow",
|
||||||
"managerFilePatterns": ["^\\.gitea/workflows/tool-versions\\.env$"],
|
"managerFilePatterns": [".gitea/workflows/tool-versions.env"],
|
||||||
"matchStrings": ["(?:^|\\n)RUFF_VERSION=\"(?<currentValue>[0-9.]+)\""],
|
"matchStrings": ["(?:^|\\n)RUFF_VERSION=\"(?<currentValue>[0-9.]+)\""],
|
||||||
"datasourceTemplate": "pypi",
|
"datasourceTemplate": "pypi",
|
||||||
"depNameTemplate": "ruff"
|
"depNameTemplate": "ruff"
|
||||||
@@ -109,7 +130,7 @@
|
|||||||
{
|
{
|
||||||
"customType": "regex",
|
"customType": "regex",
|
||||||
"description": "pip-audit version used by the ci workflow",
|
"description": "pip-audit version used by the ci workflow",
|
||||||
"managerFilePatterns": ["^\\.gitea/workflows/tool-versions\\.env$"],
|
"managerFilePatterns": [".gitea/workflows/tool-versions.env"],
|
||||||
"matchStrings": ["(?:^|\\n)PIP_AUDIT_VERSION=\"(?<currentValue>[0-9.]+)\""],
|
"matchStrings": ["(?:^|\\n)PIP_AUDIT_VERSION=\"(?<currentValue>[0-9.]+)\""],
|
||||||
"datasourceTemplate": "pypi",
|
"datasourceTemplate": "pypi",
|
||||||
"depNameTemplate": "pip-audit"
|
"depNameTemplate": "pip-audit"
|
||||||
@@ -117,7 +138,7 @@
|
|||||||
{
|
{
|
||||||
"customType": "regex",
|
"customType": "regex",
|
||||||
"description": "yamllint version used by the ci workflow",
|
"description": "yamllint version used by the ci workflow",
|
||||||
"managerFilePatterns": ["^\\.gitea/workflows/tool-versions\\.env$"],
|
"managerFilePatterns": [".gitea/workflows/tool-versions.env"],
|
||||||
"matchStrings": ["(?:^|\\n)YAMLLINT_VERSION=\"(?<currentValue>[0-9.]+)\""],
|
"matchStrings": ["(?:^|\\n)YAMLLINT_VERSION=\"(?<currentValue>[0-9.]+)\""],
|
||||||
"datasourceTemplate": "pypi",
|
"datasourceTemplate": "pypi",
|
||||||
"depNameTemplate": "yamllint"
|
"depNameTemplate": "yamllint"
|
||||||
@@ -125,7 +146,7 @@
|
|||||||
{
|
{
|
||||||
"customType": "regex",
|
"customType": "regex",
|
||||||
"description": "hadolint version used by the ci workflow",
|
"description": "hadolint version used by the ci workflow",
|
||||||
"managerFilePatterns": ["^\\.gitea/workflows/tool-versions\\.env$"],
|
"managerFilePatterns": [".gitea/workflows/tool-versions.env"],
|
||||||
"matchStrings": ["(?:^|\\n)HADOLINT_VERSION=\"(?<currentValue>[0-9.]+)\""],
|
"matchStrings": ["(?:^|\\n)HADOLINT_VERSION=\"(?<currentValue>[0-9.]+)\""],
|
||||||
"datasourceTemplate": "github-tags",
|
"datasourceTemplate": "github-tags",
|
||||||
"depNameTemplate": "hadolint/hadolint"
|
"depNameTemplate": "hadolint/hadolint"
|
||||||
@@ -133,7 +154,7 @@
|
|||||||
{
|
{
|
||||||
"customType": "regex",
|
"customType": "regex",
|
||||||
"description": "node version the ci workflow runs npm with",
|
"description": "node version the ci workflow runs npm with",
|
||||||
"managerFilePatterns": ["^\\.gitea/workflows/tool-versions\\.env$"],
|
"managerFilePatterns": [".gitea/workflows/tool-versions.env"],
|
||||||
"matchStrings": ["(?:^|\\n)NODE_VERSION=\"(?<currentValue>[0-9.]+)\""],
|
"matchStrings": ["(?:^|\\n)NODE_VERSION=\"(?<currentValue>[0-9.]+)\""],
|
||||||
"datasourceTemplate": "node",
|
"datasourceTemplate": "node",
|
||||||
"depNameTemplate": "node"
|
"depNameTemplate": "node"
|
||||||
@@ -141,7 +162,7 @@
|
|||||||
{
|
{
|
||||||
"customType": "regex",
|
"customType": "regex",
|
||||||
"description": "stakater/reloader chart version pinned in the deploy workflow",
|
"description": "stakater/reloader chart version pinned in the deploy workflow",
|
||||||
"managerFilePatterns": ["^\\.gitea/workflows/deploy-lib\\.sh$"],
|
"managerFilePatterns": [".gitea/workflows/deploy-lib.sh"],
|
||||||
"matchStrings": ["\\|stakater/reloader\\|reloader\\|(?<currentValue>[0-9.]+)\\|"],
|
"matchStrings": ["\\|stakater/reloader\\|reloader\\|(?<currentValue>[0-9.]+)\\|"],
|
||||||
"datasourceTemplate": "helm",
|
"datasourceTemplate": "helm",
|
||||||
"depNameTemplate": "reloader",
|
"depNameTemplate": "reloader",
|
||||||
@@ -150,7 +171,7 @@
|
|||||||
],
|
],
|
||||||
"packageRules": [
|
"packageRules": [
|
||||||
{
|
{
|
||||||
"description": "Automerge digest and patch updates - safe by definition, review adds nothing, keeps the renovate queue and the deploy line short. Specific no-automerge rules below still override this for playwright, helm and majors.",
|
"description": "Automerge ordinary digest and patch updates after successful checks; specific manual-review rules below override this.",
|
||||||
"matchUpdateTypes": ["digest", "patch"],
|
"matchUpdateTypes": ["digest", "patch"],
|
||||||
"automerge": true
|
"automerge": true
|
||||||
},
|
},
|
||||||
@@ -161,6 +182,12 @@
|
|||||||
"groupSlug": "all-minor",
|
"groupSlug": "all-minor",
|
||||||
"automerge": false
|
"automerge": false
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"description": "Group ordinary patch updates; the specific groups and manual-review rules below take precedence",
|
||||||
|
"matchUpdateTypes": ["patch"],
|
||||||
|
"groupName": "all patch updates",
|
||||||
|
"groupSlug": "all-patch"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"description": "Keep private homelab images unchanged",
|
"description": "Keep private homelab images unchanged",
|
||||||
"matchDatasources": ["docker"],
|
"matchDatasources": ["docker"],
|
||||||
@@ -185,7 +212,7 @@
|
|||||||
"automerge": false
|
"automerge": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "CI runs npm on the node the panel image is built from - the NODE_VERSION pin in tool-versions.env and node:22-alpine in the Dockerfile are the same dependency and move as one",
|
"description": "Keep CI Node runtime updates in a separate, manually reviewed group",
|
||||||
"matchPackageNames": ["node"],
|
"matchPackageNames": ["node"],
|
||||||
"groupName": "node runtime",
|
"groupName": "node runtime",
|
||||||
"groupSlug": "node",
|
"groupSlug": "node",
|
||||||
@@ -194,6 +221,8 @@
|
|||||||
{
|
{
|
||||||
"description": "Helm chart bumps change PVC fields and admission behaviour, keep them reviewable",
|
"description": "Helm chart bumps change PVC fields and admission behaviour, keep them reviewable",
|
||||||
"matchDatasources": ["helm"],
|
"matchDatasources": ["helm"],
|
||||||
|
"groupName": "Helm chart {{depName}}",
|
||||||
|
"groupSlug": "helm-{{depName}}",
|
||||||
"automerge": false
|
"automerge": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -202,12 +231,6 @@
|
|||||||
"dependencyDashboardApproval": true,
|
"dependencyDashboardApproval": true,
|
||||||
"automerge": false
|
"automerge": false
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"description": "Group patch updates from all sources - automerge still applies via the digest/patch rule above (helm/playwright stay manual via their own rules)",
|
|
||||||
"matchUpdateTypes": ["patch"],
|
|
||||||
"groupName": "all patch updates",
|
|
||||||
"groupSlug": "all-patch"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"description": "Python Y-bumps break compat (3.11->3.12->3.13->3.14) - keep the base image out of the shared minor/patch groups, review every bump separately. Placed last so its groupName wins.",
|
"description": "Python Y-bumps break compat (3.11->3.12->3.13->3.14) - keep the base image out of the shared minor/patch groups, review every bump separately. Placed last so its groupName wins.",
|
||||||
"matchDatasources": ["docker"],
|
"matchDatasources": ["docker"],
|
||||||
|
|||||||
@@ -12,11 +12,11 @@ services:
|
|||||||
- "traefik.enable=true"
|
- "traefik.enable=true"
|
||||||
- "traefik.http.services.searxng.loadbalancer.server.port=8080"
|
- "traefik.http.services.searxng.loadbalancer.server.port=8080"
|
||||||
# Prod Router
|
# Prod Router
|
||||||
- "traefik.http.routers.searxng.rule=Host(`s.forust.xyz` || `search.forust.xyz`)"
|
- "traefik.http.routers.searxng.rule=Host(`s.forust.xyz`) || Host(`search.forust.xyz`)"
|
||||||
- "traefik.http.routers.searxng.entrypoints=websecure"
|
- "traefik.http.routers.searxng.entrypoints=websecure"
|
||||||
- "traefik.http.routers.searxng.tls.certresolver=letsencrypt"
|
- "traefik.http.routers.searxng.tls.certresolver=letsencrypt"
|
||||||
# Local Router
|
# Local Router
|
||||||
- "traefik.http.routers.searxng-local.rule=Host(`s.workstation.internal` || `searxng.workstation.internal`)"
|
- "traefik.http.routers.searxng-local.rule=Host(`s.workstation.internal`) || Host(`searxng.workstation.internal`)"
|
||||||
- "traefik.http.routers.searxng-local.entrypoints=websecure"
|
- "traefik.http.routers.searxng-local.entrypoints=websecure"
|
||||||
- "traefik.http.routers.searxng-local.tls=true"
|
- "traefik.http.routers.searxng-local.tls=true"
|
||||||
# Dev Router
|
# Dev Router
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ spec:
|
|||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
|
annotations:
|
||||||
|
reloader.stakater.com/auto: "true"
|
||||||
name: searxng-deployment
|
name: searxng-deployment
|
||||||
namespace: searxng
|
namespace: searxng
|
||||||
spec:
|
spec:
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ services:
|
|||||||
- streaming
|
- streaming
|
||||||
|
|
||||||
qbittorrent:
|
qbittorrent:
|
||||||
image: lscr.io/linuxserver/qbittorrent:5.2.4
|
image: lscr.io/linuxserver/qbittorrent:20.04.1
|
||||||
container_name: qbittorrent
|
container_name: qbittorrent
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
environment:
|
environment:
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
services:
|
services:
|
||||||
termix:
|
termix:
|
||||||
image: ghcr.io/lukegus/termix:2.9.1
|
image: ghcr.io/lukegus/termix:2.9.2
|
||||||
container_name: termix
|
container_name: termix
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
# ports:
|
# ports:
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ spec:
|
|||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
|
annotations:
|
||||||
|
reloader.stakater.com/auto: "true"
|
||||||
name: termix-deployment
|
name: termix-deployment
|
||||||
namespace: termix
|
namespace: termix
|
||||||
spec:
|
spec:
|
||||||
@@ -29,7 +31,7 @@ spec:
|
|||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: termix
|
- name: termix
|
||||||
image: ghcr.io/lukegus/termix:2.9.1
|
image: ghcr.io/lukegus/termix:2.9.2
|
||||||
envFrom:
|
envFrom:
|
||||||
- configMapRef:
|
- configMapRef:
|
||||||
name: termix-config
|
name: termix-config
|
||||||
|
|||||||
@@ -0,0 +1,87 @@
|
|||||||
|
"""Exercise local setup and config rendering without a Docker daemon."""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import tempfile
|
||||||
|
import unittest
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
|
||||||
|
|
||||||
|
class NetbirdRuntimeTests(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.temp = tempfile.TemporaryDirectory()
|
||||||
|
self.addCleanup(self.temp.cleanup)
|
||||||
|
self.root = Path(self.temp.name)
|
||||||
|
self.stack = self.root / 'netbird'
|
||||||
|
self.stack.mkdir()
|
||||||
|
for name in ('setup.sh', '.env.example', 'config.template.yaml'):
|
||||||
|
shutil.copy(ROOT / 'netbird' / name, self.stack / name)
|
||||||
|
binary = self.root / 'bin'
|
||||||
|
binary.mkdir()
|
||||||
|
docker = binary / 'docker'
|
||||||
|
docker.write_text('#!/bin/sh\nprintf "%s\\n" 172.20.0.0/16\n')
|
||||||
|
docker.chmod(0o755)
|
||||||
|
self.env = dict(os.environ, PATH=f'{binary}:{os.environ["PATH"]}')
|
||||||
|
|
||||||
|
def setup(self):
|
||||||
|
return subprocess.run( # noqa: S603 - executes the repository script copied into this test's temp dir
|
||||||
|
['/bin/bash', str(self.stack / 'setup.sh')], env=self.env, capture_output=True, check=False
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_setup_preserves_existing_secrets_and_env(self):
|
||||||
|
self.assertEqual(self.setup().returncode, 0)
|
||||||
|
paths = [self.stack / '.env', *sorted((self.stack / 'secrets').iterdir())]
|
||||||
|
before = [p.read_bytes() for p in paths]
|
||||||
|
self.assertIn(b'NETBIRD_PROXY_SUBNET=172.20.0.0/16', before[0])
|
||||||
|
self.assertEqual(self.setup().returncode, 0)
|
||||||
|
self.assertEqual(before, [p.read_bytes() for p in paths])
|
||||||
|
for p in paths[1:]:
|
||||||
|
self.assertEqual(p.stat().st_mode & 0o777, 0o600)
|
||||||
|
|
||||||
|
def test_setup_rejects_empty_existing_secret(self):
|
||||||
|
(self.stack / 'secrets').mkdir()
|
||||||
|
secret = self.stack / 'secrets/datastore-encryption-key'
|
||||||
|
secret.touch()
|
||||||
|
self.assertNotEqual(self.setup().returncode, 0)
|
||||||
|
self.assertEqual(secret.read_bytes(), b'')
|
||||||
|
|
||||||
|
def render(self, subnet):
|
||||||
|
self.assertEqual(self.setup().returncode, 0)
|
||||||
|
rendered = self.root / 'run/config.yaml'
|
||||||
|
script = (ROOT / 'netbird/entrypoint.sh').read_text()
|
||||||
|
replacements = {
|
||||||
|
'/opt/netbird/config.template.yaml': str(self.stack / 'config.template.yaml'),
|
||||||
|
'/run/netbird/config.yaml': str(rendered),
|
||||||
|
'/run/secrets/relay_auth_secret': str(self.stack / 'secrets/relay-auth-secret'),
|
||||||
|
'/run/secrets/datastore_encryption_key': str(self.stack / 'secrets/datastore-encryption-key'),
|
||||||
|
'/go/bin/netbird-server': '/bin/true',
|
||||||
|
}
|
||||||
|
for original, local in replacements.items():
|
||||||
|
script = script.replace(original, local)
|
||||||
|
result = subprocess.run( # noqa: S603 - repository renderer, with test-local paths
|
||||||
|
['/bin/sh', '-c', script, 'entrypoint', '--config', str(rendered)],
|
||||||
|
env=dict(self.env, NETBIRD_DOMAIN='nb.example.com', NETBIRD_PROXY_SUBNET=subnet),
|
||||||
|
capture_output=True,
|
||||||
|
check=False,
|
||||||
|
)
|
||||||
|
return result, rendered
|
||||||
|
|
||||||
|
def test_renderer_replaces_placeholders_and_restricts_file_permissions(self):
|
||||||
|
result, rendered = self.render('172.20.0.0/16')
|
||||||
|
self.assertEqual(result.returncode, 0, result.stderr)
|
||||||
|
self.assertNotIn('__NETBIRD_', rendered.read_text())
|
||||||
|
self.assertIn('nb.example.com', rendered.read_text())
|
||||||
|
self.assertEqual(rendered.stat().st_mode & 0o777, 0o600)
|
||||||
|
|
||||||
|
def test_renderer_rejects_auto_and_default_route(self):
|
||||||
|
for subnet in ('auto', '0.0.0.0/0', '999.1.1.1/24'):
|
||||||
|
with self.subTest(subnet=subnet):
|
||||||
|
result, _ = self.render(subnet)
|
||||||
|
self.assertNotEqual(result.returncode, 0)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
services:
|
services:
|
||||||
server:
|
server:
|
||||||
container_name: vaultwarden-server
|
container_name: vaultwarden-server
|
||||||
image: vaultwarden/server:1.37.3
|
image: vaultwarden/server:1.37.4
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
ports:
|
ports:
|
||||||
- 9993:80
|
- 9993:80
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ spec:
|
|||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
|
annotations:
|
||||||
|
reloader.stakater.com/auto: "true"
|
||||||
name: vaultwarden-deployment
|
name: vaultwarden-deployment
|
||||||
namespace: vaultwarden
|
namespace: vaultwarden
|
||||||
spec:
|
spec:
|
||||||
@@ -29,7 +31,7 @@ spec:
|
|||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: vaultwarden
|
- name: vaultwarden
|
||||||
image: vaultwarden/server:1.37.3
|
image: vaultwarden/server:1.37.4
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 80
|
- containerPort: 80
|
||||||
envFrom:
|
envFrom:
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ spec:
|
|||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
|
annotations:
|
||||||
|
reloader.stakater.com/auto: "true"
|
||||||
name: xui-deployment
|
name: xui-deployment
|
||||||
namespace: xui
|
namespace: xui
|
||||||
spec:
|
spec:
|
||||||
@@ -36,7 +38,7 @@ spec:
|
|||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: xui
|
- name: xui
|
||||||
image: ghcr.io/mhsanaei/3x-ui:v3.8.5
|
image: ghcr.io/mhsanaei/3x-ui:v3.9.0
|
||||||
envFrom:
|
envFrom:
|
||||||
- configMapRef:
|
- configMapRef:
|
||||||
name: xui-config
|
name: xui-config
|
||||||
|
|||||||
Reference in new issue
Block a user