mirror of
https://github.com/dredx/prole.git
synced 2026-09-23 10:13:58 +00:00
Rename Prole storage objects to Synology and sync deployment updates
- Rename iSCSI storage class and PV/PVC selectors/labels from prole to synology across k8s and OpenTofu manifests\n- Update CNPG/OpenBao/Garage/monitoring init flows, render helpers, and mock scripts for synology-backed storage objects\n- Integrate related UI/core/service config/version updates and add supporting regression tests for CNPG storage/image behavior\n- Keep storage reconciliation tests aligned with current CNPG affinity output Co-authored-by: Junie <junie@jetbrains.com>
This commit is contained in:
parent
0262bd4be2
commit
9b9d6fdc88
83
_adopt_replica_pvcs.sh
Normal file
83
_adopt_replica_pvcs.sh
Normal file
@ -0,0 +1,83 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
NS=prole-db
|
||||
CLUSTER_UID=$(kubectl get cluster prole-db -n "$NS" -o jsonpath='{.metadata.uid}' 2>/dev/null)
|
||||
echo "Cluster UID: $CLUSTER_UID"
|
||||
|
||||
echo "=== Pausing CNPG controller ==="
|
||||
kubectl scale deployment cnpg-controller-manager -n cnpg-system --replicas=0
|
||||
sleep 5
|
||||
|
||||
echo "=== Cleaning up serial 8+ PVCs and jobs ==="
|
||||
for serial in 8 9 10; do
|
||||
kubectl delete pvc "prole-db-${serial}" "prole-db-${serial}-wal" -n "$NS" --ignore-not-found 2>/dev/null || true
|
||||
kubectl delete job -n "$NS" -l "cnpg.io/instanceName=prole-db-${serial}" --ignore-not-found 2>/dev/null || true
|
||||
done
|
||||
|
||||
echo "=== Patching replica PVCs with full CNPG labels/annotations ==="
|
||||
for serial in 3 7; do
|
||||
# Data PVC
|
||||
kubectl patch pvc "prole-db-${serial}" -n "$NS" --type=merge -p "{
|
||||
\"metadata\": {
|
||||
\"labels\": {
|
||||
\"app.kubernetes.io/component\": \"database\",
|
||||
\"app.kubernetes.io/managed-by\": \"cloudnative-pg\",
|
||||
\"app.kubernetes.io/name\": \"postgresql\",
|
||||
\"cnpg.io/cluster\": \"prole-db\",
|
||||
\"cnpg.io/instanceName\": \"prole-db-${serial}\",
|
||||
\"cnpg.io/instanceRole\": \"replica\",
|
||||
\"cnpg.io/pvcRole\": \"PG_DATA\",
|
||||
\"role\": \"replica\"
|
||||
},
|
||||
\"annotations\": {
|
||||
\"cnpg.io/nodeSerial\": \"${serial}\",
|
||||
\"cnpg.io/operatorVersion\": \"1.28.1\",
|
||||
\"cnpg.io/pvcStatus\": \"ready\"
|
||||
},
|
||||
\"ownerReferences\": [{
|
||||
\"apiVersion\": \"postgresql.cnpg.io/v1\",
|
||||
\"controller\": true,
|
||||
\"kind\": \"Cluster\",
|
||||
\"name\": \"prole-db\",
|
||||
\"uid\": \"${CLUSTER_UID}\"
|
||||
}]
|
||||
}
|
||||
}"
|
||||
echo " Patched prole-db-${serial}"
|
||||
|
||||
# WAL PVC
|
||||
kubectl patch pvc "prole-db-${serial}-wal" -n "$NS" --type=merge -p "{
|
||||
\"metadata\": {
|
||||
\"labels\": {
|
||||
\"app.kubernetes.io/component\": \"database\",
|
||||
\"app.kubernetes.io/managed-by\": \"cloudnative-pg\",
|
||||
\"app.kubernetes.io/name\": \"postgresql\",
|
||||
\"cnpg.io/cluster\": \"prole-db\",
|
||||
\"cnpg.io/instanceName\": \"prole-db-${serial}\",
|
||||
\"cnpg.io/instanceRole\": \"replica\",
|
||||
\"cnpg.io/pvcRole\": \"PG_WAL\",
|
||||
\"role\": \"replica\"
|
||||
},
|
||||
\"annotations\": {
|
||||
\"cnpg.io/nodeSerial\": \"${serial}\",
|
||||
\"cnpg.io/operatorVersion\": \"1.28.1\",
|
||||
\"cnpg.io/pvcStatus\": \"ready\"
|
||||
},
|
||||
\"ownerReferences\": [{
|
||||
\"apiVersion\": \"postgresql.cnpg.io/v1\",
|
||||
\"controller\": true,
|
||||
\"kind\": \"Cluster\",
|
||||
\"name\": \"prole-db\",
|
||||
\"uid\": \"${CLUSTER_UID}\"
|
||||
}]
|
||||
}
|
||||
}"
|
||||
echo " Patched prole-db-${serial}-wal"
|
||||
done
|
||||
|
||||
echo "=== Resuming CNPG controller ==="
|
||||
kubectl scale deployment cnpg-controller-manager -n cnpg-system --replicas=1
|
||||
echo "Done — CNPG should now create instance pods for serials 3 (pi) and 7 (merlin)"
|
||||
sleep 20
|
||||
kubectl get pods,jobs -n "$NS" -o wide 2>/dev/null | grep -v "Completed\|initdb"
|
||||
kubectl get cluster prole-db -n "$NS" -o jsonpath='Phase: {.status.phase} Ready: {.status.readyInstances}/{.spec.instances}{"\n"}' 2>/dev/null
|
||||
92
_fix_replica_merlin.sh
Normal file
92
_fix_replica_merlin.sh
Normal file
@ -0,0 +1,92 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
NS=prole-db
|
||||
|
||||
echo "=== Pausing CNPG controller ==="
|
||||
kubectl scale deployment cnpg-controller-manager -n cnpg-system --replicas=0
|
||||
sleep 5
|
||||
|
||||
echo "=== Cleaning up all pending/failed replica PVCs and jobs ==="
|
||||
# Keep prole-db-1 (primary) and prole-db-3 (pi replica). Delete everything else.
|
||||
for serial in 2 4 5 6 7 8 9; do
|
||||
kubectl delete pvc "prole-db-${serial}" "prole-db-${serial}-wal" -n "$NS" --ignore-not-found 2>/dev/null || true
|
||||
kubectl delete job -n "$NS" -l "cnpg.io/instanceName=prole-db-${serial}" --ignore-not-found 2>/dev/null || true
|
||||
done
|
||||
echo "Cleaned up stale PVCs and jobs"
|
||||
|
||||
echo "=== Clearing Released PV claimRefs ==="
|
||||
for pv in synology-iscsi-d002-data synology-iscsi-d002-wal; do
|
||||
kubectl patch pv "$pv" --type=json \
|
||||
-p '[{"op":"remove","path":"/spec/claimRef"}]' 2>/dev/null || \
|
||||
kubectl patch pv "$pv" --type=merge \
|
||||
-p '{"spec":{"claimRef":{"name":"","uid":"","namespace":""}}}' 2>/dev/null || true
|
||||
echo " Patched $pv"
|
||||
done
|
||||
|
||||
echo "=== Waiting for d002 PVs to become Available ==="
|
||||
for pv in synology-iscsi-d002-data synology-iscsi-d002-wal; do
|
||||
for i in $(seq 1 30); do
|
||||
phase=$(kubectl get pv "$pv" -o jsonpath='{.status.phase}' 2>/dev/null)
|
||||
echo " $pv: $phase"
|
||||
if [[ "$phase" == "Available" ]]; then break; fi
|
||||
sleep 3
|
||||
done
|
||||
done
|
||||
|
||||
echo "=== Getting CNPG PVC labels from existing prole-db-3 PVC ==="
|
||||
CNPG_LABELS=$(kubectl get pvc prole-db-3 -n "$NS" -o jsonpath='{.metadata.labels}' 2>/dev/null || echo "{}")
|
||||
echo " Labels: $CNPG_LABELS"
|
||||
|
||||
# Determine next serial CNPG will use (latestGeneratedNode + 1)
|
||||
NEXT_SERIAL=$(kubectl get cluster prole-db -n "$NS" -o jsonpath='{.status.latestGeneratedNode}' 2>/dev/null || echo "4")
|
||||
NEXT_SERIAL=$((NEXT_SERIAL + 1))
|
||||
echo "=== Pre-binding prole-db-${NEXT_SERIAL} PVCs to d002 (merlin) ==="
|
||||
|
||||
kubectl create -f - <<YAML
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: prole-db-${NEXT_SERIAL}
|
||||
namespace: ${NS}
|
||||
labels:
|
||||
cnpg.io/cluster: prole-db
|
||||
spec:
|
||||
accessModes: [ReadWriteOnce]
|
||||
resources:
|
||||
requests:
|
||||
storage: 1Gi
|
||||
storageClassName: synology-iscsi
|
||||
volumeName: synology-iscsi-d002-data
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: prole-db-${NEXT_SERIAL}-wal
|
||||
namespace: ${NS}
|
||||
labels:
|
||||
cnpg.io/cluster: prole-db
|
||||
spec:
|
||||
accessModes: [ReadWriteOnce]
|
||||
resources:
|
||||
requests:
|
||||
storage: 1Gi
|
||||
storageClassName: synology-iscsi
|
||||
volumeName: synology-iscsi-d002-wal
|
||||
YAML
|
||||
echo "Created pre-bound PVCs for serial ${NEXT_SERIAL}"
|
||||
|
||||
echo "=== Waiting for PVCs to bind ==="
|
||||
for pvc in "prole-db-${NEXT_SERIAL}" "prole-db-${NEXT_SERIAL}-wal"; do
|
||||
for i in $(seq 1 20); do
|
||||
phase=$(kubectl get pvc "$pvc" -n "$NS" -o jsonpath='{.status.phase}' 2>/dev/null)
|
||||
echo " $pvc: $phase"
|
||||
if [[ "$phase" == "Bound" ]]; then break; fi
|
||||
sleep 3
|
||||
done
|
||||
done
|
||||
|
||||
echo "=== Resuming CNPG controller ==="
|
||||
kubectl scale deployment cnpg-controller-manager -n cnpg-system --replicas=1
|
||||
echo "Done — CNPG will create prole-db-${NEXT_SERIAL}-join targeting merlin.prole.org"
|
||||
sleep 15
|
||||
kubectl get jobs,pods -n "$NS" -o wide | grep -v "Completed\|initdb"
|
||||
9
_import_pi.sh
Normal file
9
_import_pi.sh
Normal file
@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env bash
|
||||
echo "Importing knoe-db:18-140 to pi.prole.org..."
|
||||
docker save myrddin.prole.org:5000/knoe-db:18-140 \
|
||||
| ssh -o StrictHostKeyChecking=no -o BatchMode=yes \
|
||||
-o ServerAliveInterval=30 -o ServerAliveCountMax=20 \
|
||||
-i ~/.ssh/id_ed25519_ansible ansible@pi.prole.org \
|
||||
"sudo k3s ctr images import -" 2>&1 | tail -5
|
||||
echo "Done importing to pi."
|
||||
kubectl get jobs,pods -n prole-db -o wide 2>/dev/null | grep -v "Completed\|initdb"
|
||||
8
_monitor_run.sh
Normal file
8
_monitor_run.sh
Normal file
@ -0,0 +1,8 @@
|
||||
#!/usr/bin/env bash
|
||||
for i in $(seq 1 90); do
|
||||
sleep 10
|
||||
if ! pgrep -f "prole.sh.*service/prole.cfg" >/dev/null 2>&1; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
tail -60 /tmp/prole_run.log
|
||||
9
_patch_cluster.sh
Normal file
9
_patch_cluster.sh
Normal file
@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
cp k8s/prole/prole-db.yaml deploy/opentofu/k3s/manifests/prole/prole-db.yaml
|
||||
echo "Mirrored prole-db.yaml to opentofu"
|
||||
kubectl patch cluster prole-db -n prole-db --type=merge -p \
|
||||
'{"spec":{"imageName":"myrddin.prole.org:5000/knoe-db:18-140","affinity":{"podAntiAffinityType":"preferred","nodeAffinity":{"requiredDuringSchedulingIgnoredDuringExecution":{"nodeSelectorTerms":[{"matchExpressions":[{"key":"node.kubernetes.io/instance-type","operator":"In","values":["k3s"]}]}]}}}}}'
|
||||
echo "Patched live cluster"
|
||||
sleep 5
|
||||
kubectl get pods -n prole-db -o wide
|
||||
80
_prebind_pvcs.sh
Normal file
80
_prebind_pvcs.sh
Normal file
@ -0,0 +1,80 @@
|
||||
#!/usr/bin/env bash
|
||||
# Pre-bind CNPG PVCs to specific Synology iSCSI PVs so CNPG schedules replicas
|
||||
# on the correct nodes (merlin=d002, pi=d003) rather than defaulting to myrddin.
|
||||
set -euo pipefail
|
||||
NS=prole-db
|
||||
|
||||
# Delete any pending (unbound) PVCs for replicas 2 and 3
|
||||
for pvc in prole-db-2 prole-db-2-wal prole-db-3 prole-db-3-wal; do
|
||||
phase=$(kubectl get pvc "$pvc" -n "$NS" -o jsonpath='{.status.phase}' 2>/dev/null || true)
|
||||
if [[ "$phase" == "Pending" || -z "$phase" ]]; then
|
||||
kubectl delete pvc "$pvc" -n "$NS" --ignore-not-found
|
||||
echo "Deleted pending PVC: $pvc"
|
||||
fi
|
||||
done
|
||||
|
||||
# Pre-bind replica-2 PVCs → synology-iscsi-d002 on merlin.prole.org
|
||||
kubectl apply -f - <<'YAML'
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: prole-db-2
|
||||
namespace: prole-db
|
||||
spec:
|
||||
accessModes: [ReadWriteOnce]
|
||||
resources:
|
||||
requests:
|
||||
storage: 29Gi
|
||||
storageClassName: synology-iscsi
|
||||
volumeName: synology-iscsi-d002-data
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: prole-db-2-wal
|
||||
namespace: prole-db
|
||||
spec:
|
||||
accessModes: [ReadWriteOnce]
|
||||
resources:
|
||||
requests:
|
||||
storage: 29Gi
|
||||
storageClassName: synology-iscsi
|
||||
volumeName: synology-iscsi-d002-wal
|
||||
YAML
|
||||
|
||||
# Pre-bind replica-3 PVCs → synology-iscsi-d003 on pi.prole.org
|
||||
kubectl apply -f - <<'YAML'
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: prole-db-3
|
||||
namespace: prole-db
|
||||
spec:
|
||||
accessModes: [ReadWriteOnce]
|
||||
resources:
|
||||
requests:
|
||||
storage: 29Gi
|
||||
storageClassName: synology-iscsi
|
||||
volumeName: synology-iscsi-d003-data
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: prole-db-3-wal
|
||||
namespace: prole-db
|
||||
spec:
|
||||
accessModes: [ReadWriteOnce]
|
||||
resources:
|
||||
requests:
|
||||
storage: 29Gi
|
||||
storageClassName: synology-iscsi
|
||||
volumeName: synology-iscsi-d003-wal
|
||||
YAML
|
||||
|
||||
echo "Waiting for PVCs to bind..."
|
||||
sleep 5
|
||||
kubectl get pvc -n "$NS"
|
||||
|
||||
# Delete the stuck pod so CNPG recreates it with correct affinity
|
||||
kubectl delete pod -n "$NS" -l cnpg.io/instanceName=prole-db-2 --ignore-not-found
|
||||
echo "Done — CNPG will recreate replica-2 pod targeting merlin.prole.org"
|
||||
56
_rebind_d002.sh
Normal file
56
_rebind_d002.sh
Normal file
@ -0,0 +1,56 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
NS=prole-db
|
||||
|
||||
# Release d002 PVs by deleting old prole-db-2 PVCs
|
||||
kubectl delete pvc prole-db-2 prole-db-2-wal -n "$NS" --ignore-not-found
|
||||
echo "Deleted prole-db-2 PVCs"
|
||||
|
||||
# Wait for PVs to become Available again
|
||||
for pv in synology-iscsi-d002-data synology-iscsi-d002-wal; do
|
||||
for i in $(seq 1 20); do
|
||||
phase=$(kubectl get pv "$pv" -o jsonpath='{.status.phase}' 2>/dev/null || echo "")
|
||||
if [[ "$phase" == "Available" ]]; then
|
||||
echo " PV $pv is Available"
|
||||
break
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
done
|
||||
|
||||
# Pre-bind prole-db-4 PVCs to d002 PVs on merlin
|
||||
kubectl apply -f - <<'YAML'
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: prole-db-4
|
||||
namespace: prole-db
|
||||
spec:
|
||||
accessModes: [ReadWriteOnce]
|
||||
resources:
|
||||
requests:
|
||||
storage: 29Gi
|
||||
storageClassName: synology-iscsi
|
||||
volumeName: synology-iscsi-d002-data
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: prole-db-4-wal
|
||||
namespace: prole-db
|
||||
spec:
|
||||
accessModes: [ReadWriteOnce]
|
||||
resources:
|
||||
requests:
|
||||
storage: 29Gi
|
||||
storageClassName: synology-iscsi
|
||||
volumeName: synology-iscsi-d002-wal
|
||||
YAML
|
||||
echo "Created prole-db-4 PVCs pre-bound to d002 (merlin)"
|
||||
|
||||
# Delete the stuck prole-db-4-join Job so CNPG recreates it reading the new PVCs
|
||||
kubectl delete job -n "$NS" -l cnpg.io/instanceName=prole-db-4 --ignore-not-found
|
||||
echo "Deleted prole-db-4-join Job — CNPG will recreate targeting merlin"
|
||||
|
||||
sleep 10
|
||||
kubectl get pvc,pods -n "$NS" | grep -v "Completed\|initdb"
|
||||
50
_rebind_d002b.sh
Normal file
50
_rebind_d002b.sh
Normal file
@ -0,0 +1,50 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
NS=prole-db
|
||||
|
||||
# Delete the job first, then the PVCs CNPG created with wrong volumeName
|
||||
kubectl delete job -n "$NS" -l cnpg.io/instanceName=prole-db-4 --ignore-not-found
|
||||
kubectl delete pvc prole-db-4 prole-db-4-wal -n "$NS" --ignore-not-found
|
||||
echo "Deleted prole-db-4 job and PVCs"
|
||||
|
||||
# Wait for d002 PVs to become Available
|
||||
for pv in synology-iscsi-d002-data synology-iscsi-d002-wal; do
|
||||
for i in $(seq 1 30); do
|
||||
phase=$(kubectl get pv "$pv" -o jsonpath='{.status.phase}' 2>/dev/null || echo "")
|
||||
echo " $pv: $phase"
|
||||
if [[ "$phase" == "Available" ]]; then break; fi
|
||||
sleep 2
|
||||
done
|
||||
done
|
||||
|
||||
# Pre-bind with 1Gi (matching CNPG cluster spec size)
|
||||
kubectl create -f - <<'YAML'
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: prole-db-4
|
||||
namespace: prole-db
|
||||
spec:
|
||||
accessModes: [ReadWriteOnce]
|
||||
resources:
|
||||
requests:
|
||||
storage: 1Gi
|
||||
storageClassName: synology-iscsi
|
||||
volumeName: synology-iscsi-d002-data
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: prole-db-4-wal
|
||||
namespace: prole-db
|
||||
spec:
|
||||
accessModes: [ReadWriteOnce]
|
||||
resources:
|
||||
requests:
|
||||
storage: 1Gi
|
||||
storageClassName: synology-iscsi
|
||||
volumeName: synology-iscsi-d002-wal
|
||||
YAML
|
||||
echo "Created prole-db-4 PVCs pre-bound to d002 (merlin)"
|
||||
sleep 8
|
||||
kubectl get pvc -n "$NS"
|
||||
13
conf/database_versions.json
Normal file
13
conf/database_versions.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"postgresql": {
|
||||
"stable": "16",
|
||||
"current": "17",
|
||||
"latest": "18"
|
||||
},
|
||||
"percona": {
|
||||
"stable": "16",
|
||||
"current": "17",
|
||||
"latest": "18",
|
||||
"v18": "18"
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
; Prole Master Configuration File
|
||||
; Generated by install.py on 2026-03-22 05:28:56
|
||||
; Generated by install.py on 2026-03-22 21:34:24
|
||||
; This file is used as input for Ansible deployment and k8s cluster creation.
|
||||
|
||||
[User]
|
||||
@ -36,7 +36,7 @@ dependencies.opentofu.install = true
|
||||
dependencies.python.install = true
|
||||
dependencies.verify_all = false
|
||||
disk_selection.disk_type = local
|
||||
disk_selection.local_path = /Users/chrisfu
|
||||
disk_selection.local_path = /Users/chrisfu/dev/prole/prole-tools-app/dist
|
||||
disk_selection.removable_mount =
|
||||
env_setup.NAMESPACE = ${NAMESPACE}
|
||||
env_setup.PROLE_CONF = /Users/chrisfu/dev/prole/conf
|
||||
@ -49,9 +49,9 @@ init_cluster.at_rest_encryption_enabled = true
|
||||
init_cluster.cluster_env = dev
|
||||
init_cluster.deployment_target = prole-dev-cluster
|
||||
init_cluster.gitops_enabled = false
|
||||
init_cluster.k3s_server_url =
|
||||
init_cluster.k3s_token =
|
||||
init_cluster.kerberos_enabled = false
|
||||
init_cluster.k3s_server_url = https://myrddin.prole.org:6443
|
||||
init_cluster.k3s_token = ${PROLE_SECRET:v1:zaODrWdgRwk4Mn5f:5l3tyJapMmolvCe1YR8LpyfZZm_E4mApbEDdTwYdbIZ_hotg6TV6e19P60a8JAV_3CIKqgNBhGJ4wp_LY3o-5P-BJS8zs118bcPi3doRYItAQfRI9mPp0myMtKRb01xO7iWMY__t9M09m_tPsKd3LN_sobbpNNQRwxeY2w==}
|
||||
init_cluster.kerberos_enabled = true
|
||||
init_cluster.mode = k3d
|
||||
init_cluster.start_cluster = true
|
||||
init_cluster.supabase_enabled = false
|
||||
@ -60,35 +60,35 @@ init_cnpg_deploy.run_deploy = true
|
||||
init_db_build.run_build = true
|
||||
init_password.db_host_port = 5432
|
||||
init_password.db_namespace = ${NAMESPACE}
|
||||
init_password.db_password = ${PROLE_SECRET:v1:Ug4MMDdbizuLhRxp:7_zShAVRIyTwzI230RPi0DZkaYyec25z}
|
||||
init_password.db_password_confirm = ${PROLE_SECRET:v1:Ug4MMDdbizuLhRxp:7_zShAVRIyTwzI230RPi0DZkaYyec25z}
|
||||
init_password.db_password = ${PROLE_SECRET:v1:vb6MFP3JQ8ZA-kCH:P09DQs-Tf_unwlEZGjQiQug9imzKxk7z}
|
||||
init_password.db_password_confirm = ${PROLE_SECRET:v1:vb6MFP3JQ8ZA-kCH:P09DQs-Tf_unwlEZGjQiQug9imzKxk7z}
|
||||
init_password.db_username = root
|
||||
init_password.generate_ssh_key = true
|
||||
init_scripts.run_scripts = true
|
||||
kerberos_config.enabled = false
|
||||
kerberos_config.kdc =
|
||||
kerberos_config.password = ${PROLE_SECRET:v1:HY4WS78rVJaooM8W:JXfyvQkXR-Pg3Hg5FCItCMNfTIsXlW_mNDTEHElowhJ9zv2z}
|
||||
kerberos_config.realm =
|
||||
kerberos_config.enabled = true
|
||||
kerberos_config.kdc = 10.0.0.3
|
||||
kerberos_config.password = ${PROLE_SECRET:v1:vYQE4jE-zNwvWosG:LB5ajSn0j84cLnbtg6x8o-jjIwdZh5ELNW1h1pp012xDcy7R}
|
||||
kerberos_config.realm = PROLE.ORG
|
||||
kerberos_config.test_connection = false
|
||||
kerberos_config.user = administrator
|
||||
network_scan.run = true
|
||||
ollama_config.model =
|
||||
ollama_config.server_host =
|
||||
ollama_config.server_host = fairyland.prole.org
|
||||
ollama_config.server_port = 11434
|
||||
|
||||
[Global]
|
||||
; Variables used by name in more than one place or assumed global scope
|
||||
CLUSTER_ENV = dev
|
||||
DB_HOST_PORT = 5432
|
||||
DB_PASSWORD = ${PROLE_SECRET:v1:UfmNthRE-DSKbvW2:F64wGEHyh2iCF0MbYgKOUU_y4PQnzMhk}
|
||||
DB_PASSWORD = ${PROLE_SECRET:v1:RdWFdqimNbYIof7M:rIB4trg7FLDfUWzYoXLFsU-1BUywEDE4}
|
||||
DEPLOYMENT_MODE = k3d
|
||||
DEPLOYMENT_TARGET = prole-dev-cluster
|
||||
DOCKER_PRELOAD = false
|
||||
NAMESPACE = knoe-db
|
||||
OPTIONAL_WORKLOADS_MIN_READY_SCHEDULABLE_NODES = 2
|
||||
PROLE_DB_USER = root
|
||||
PROLE_K3S_SERVER =
|
||||
PROLE_K3S_TOKEN =
|
||||
PROLE_K3S_SERVER = https://myrddin.prole.org:6443
|
||||
PROLE_K3S_TOKEN = ${PROLE_SECRET:v1:zaODrWdgRwk4Mn5f:5l3tyJapMmolvCe1YR8LpyfZZm_E4mApbEDdTwYdbIZ_hotg6TV6e19P60a8JAV_3CIKqgNBhGJ4wp_LY3o-5P-BJS8zs118bcPi3doRYItAQfRI9mPp0myMtKRb01xO7iWMY__t9M09m_tPsKd3LN_sobbpNNQRwxeY2w==}
|
||||
PROLE_OPENTOFU_URL = http://127.0.0.1:8080
|
||||
SERVICE_NAMESPACE = knoe-system
|
||||
|
||||
@ -107,12 +107,18 @@ ANSIBLE_INVENTORY = /Users/chrisfu/dev/prole/infrastructure/inventory
|
||||
ANSIBLE_REALM = PROLE.ORG
|
||||
ANSIBLE_TOPOLOGY = {"domain":"prole.org","realm":"PROLE.ORG","internal_records":{"aventage.prole.org":"10.0.0.206","fairyland.prole.org":"10.0.0.208","loghost.prole.org":"10.0.0.3","merlin.prole.org":"10.0.0.6","morana.prole.org":"10.0.0.66","morgoth.prole.org":"10.0.0.204","myrddin.prole.org":"10.0.0.3","pi.prole.org":"10.0.0.5","raspberry.prole.org":"10.0.0.4","retropie.prole.org":"10.0.0.207","synology.prole.org":"10.0.0.203","zinfandel.prole.org":"10.0.0.205"},"ad_dc":{"host":"myrddin.prole.org","ip":"10.0.0.3"},"k3s":{"server_url":"https://myrddin.prole.org:6443","server_host":"myrddin.prole.org","token_present":true},"groups":{"iscsi":["pi.prole.org","raspberry.prole.org","myrddin.prole.org","retropie.prole.org","merlin.prole.org"],"pihole":["pi.prole.org","raspberry.prole.org"],"ad_dc":["myrddin.prole.org"],"k3s_servers":["myrddin.prole.org"],"k3s_agents":["pi.prole.org","merlin.prole.org"],"k3s_hosts:children":["k3s_servers","k3s_agents"],"linux_hosts":["pi.prole.org","raspberry.prole.org","myrddin.prole.org","retropie.prole.org","merlin.prole.org"],"ssl_hosts":["myrddin.prole.org"],"mariadb_primary":["merlin.prole.org"],"mariadb_replica":["raspberry.prole.org"],"mariadb:children":["mariadb_primary","mariadb_replica"],"merlin_bootstrap":["merlin"]},"hosts":{"merlin":"10.0.0.6","merlin.prole.org":"10.0.0.6","myrddin.prole.org":"10.0.0.3","pi.prole.org":"10.0.0.5","raspberry.prole.org":"10.0.0.4","retropie.prole.org":"10.0.0.207"},"unmapped_hosts":["k3s_agents","k3s_servers","mariadb_primary","mariadb_replica"]}
|
||||
KDC_ANSIBLE_DETECTED = 10.0.0.3
|
||||
KDC_AUTO_DETECTED = 10.0.0.3
|
||||
KERBEROS_AUTO_ENABLED = True
|
||||
|
||||
[Port Forwards]
|
||||
; No configuration values captured yet for this section.
|
||||
|
||||
[System Environment]
|
||||
; No configuration values captured yet for this section.
|
||||
PROLE_CONF = /Users/chrisfu/dev/prole/conf
|
||||
PROLE_DATA = /Users/chrisfu/dev/prole/data
|
||||
PROLE_HOME = /Users/chrisfu/dev/prole
|
||||
PROLE_LOGS = /Users/chrisfu/dev/prole/logs
|
||||
PROLE_SERVICE = /Users/chrisfu/dev/prole/etc
|
||||
|
||||
[Monitoring]
|
||||
; No configuration values captured yet for this section.
|
||||
@ -121,10 +127,16 @@ KDC_ANSIBLE_DETECTED = 10.0.0.3
|
||||
; No configuration values captured yet for this section.
|
||||
|
||||
[Ollama]
|
||||
; No configuration values captured yet for this section.
|
||||
OLLAMA_HOST = http://fairyland.prole.org:11434
|
||||
OLLAMA_SERVERS = fairyland.prole.org:11434,k3d.localhost:11434,morgoth.prole.org:11434
|
||||
OLLAMA_SERVER_HOST = fairyland.prole.org
|
||||
OLLAMA_SERVER_PORT = 11434
|
||||
|
||||
[Optional Features]
|
||||
AT_REST_ENCRYPTION_ENABLED = True
|
||||
GITOPS_ENABLED = False
|
||||
KERBEROS_ENABLED = True
|
||||
SUPABASE_ENABLED = False
|
||||
|
||||
[GitOps]
|
||||
; No configuration values captured yet for this section.
|
||||
@ -133,7 +145,9 @@ GITOPS_ENABLED = False
|
||||
; No configuration values captured yet for this section.
|
||||
|
||||
[Initialize Cluster]
|
||||
; No configuration values captured yet for this section.
|
||||
ENVIRONMENT = dev
|
||||
K3S_SERVER_URL = https://myrddin.prole.org:6443
|
||||
K3S_TOKEN = ${PROLE_SECRET:v1:zaODrWdgRwk4Mn5f:5l3tyJapMmolvCe1YR8LpyfZZm_E4mApbEDdTwYdbIZ_hotg6TV6e19P60a8JAV_3CIKqgNBhGJ4wp_LY3o-5P-BJS8zs118bcPi3doRYItAQfRI9mPp0myMtKRb01xO7iWMY__t9M09m_tPsKd3LN_sobbpNNQRwxeY2w==}
|
||||
|
||||
[Dev Cluster (k3d)]
|
||||
CLUSTER_ENV = dev
|
||||
@ -144,20 +158,21 @@ MODE = k3d
|
||||
[Service Cluster (k3s)]
|
||||
CLUSTER_ENV = prole-service-cluster
|
||||
DISPLAY_NAME = prole-service-cluster
|
||||
K3S_SERVER_URL =
|
||||
K3S_TOKEN =
|
||||
K3S_SERVER_URL = https://myrddin.prole.org:6443
|
||||
K3S_TOKEN = ${PROLE_SECRET:v1:zaODrWdgRwk4Mn5f:5l3tyJapMmolvCe1YR8LpyfZZm_E4mApbEDdTwYdbIZ_hotg6TV6e19P60a8JAV_3CIKqgNBhGJ4wp_LY3o-5P-BJS8zs118bcPi3doRYItAQfRI9mPp0myMtKRb01xO7iWMY__t9M09m_tPsKd3LN_sobbpNNQRwxeY2w==}
|
||||
MODE = k3s
|
||||
PIPELINE_URL = http://127.0.0.1:8080
|
||||
|
||||
[Prod Cluster (k8s)]
|
||||
ARTIFACTS_DIR = /private/var/folders/rt/pywlnmxj3dn7t5552vwdcpp80000gn/T/pytest-of-chrisfu/pytest-54/test_encryption_toggle0/data/staging
|
||||
ARTIFACTS_DIR = /Users/chrisfu/dev/prole/data/staging
|
||||
CLUSTER_ENV = prole-prod-cluster
|
||||
DISPLAY_NAME = prole-prod-cluster
|
||||
MODE = k8s
|
||||
PIPELINE_URL = http://127.0.0.1:8080
|
||||
|
||||
[Docker Build]
|
||||
; No configuration values captured yet for this section.
|
||||
LOCAL_REGISTRY = localhost:5000
|
||||
LOCAL_REGISTRY_INTERNAL = k3d-prole-registry.localhost:5000
|
||||
|
||||
[Initialization Scripts]
|
||||
; No configuration values captured yet for this section.
|
||||
|
||||
@ -1,180 +0,0 @@
|
||||
; Prole Master Configuration File
|
||||
; Generated by install.py on 2026-03-21 13:37:28
|
||||
; This file is used as input for Ansible deployment and k8s cluster creation.
|
||||
|
||||
[User]
|
||||
; User-editable values; derived values below reference these by default.
|
||||
; No user values captured yet for this section.
|
||||
|
||||
[Inputs]
|
||||
; Screen-scoped inputs used for unattended replays (-S)
|
||||
build.deploy_env = Dev
|
||||
build.run_build = false
|
||||
database_options.distribution = percona
|
||||
database_options.ext.dblink = true
|
||||
database_options.ext.pg_buffercache = true
|
||||
database_options.ext.pg_freespacemap = true
|
||||
database_options.ext.pg_repack = true
|
||||
database_options.ext.pg_stat_monitor = true
|
||||
database_options.ext.pg_stat_statements = true
|
||||
database_options.ext.pgaudit = true
|
||||
database_options.ext.pgbadger = true
|
||||
database_options.ext.pgcrypto = true
|
||||
database_options.ext.pgrowlocks = true
|
||||
database_options.ext.pgvector = true
|
||||
database_options.ext.postgis = true
|
||||
database_options.ext.postgres_fdw = true
|
||||
database_options.version_type = v18
|
||||
dependencies.ansible.install = true
|
||||
dependencies.auto_install_missing = true
|
||||
dependencies.brew.install = true
|
||||
dependencies.docker.install = true
|
||||
dependencies.k3d.install = true
|
||||
dependencies.kubectl.install = true
|
||||
dependencies.kubectx.install = true
|
||||
dependencies.opentofu.install = true
|
||||
dependencies.python.install = true
|
||||
dependencies.verify_all = false
|
||||
disk_selection.disk_type = local
|
||||
disk_selection.local_path = /Users/chrisfu/dev/prole/prole-tools-app/dist
|
||||
disk_selection.removable_mount =
|
||||
env_setup.NAMESPACE = ${NAMESPACE}
|
||||
env_setup.PROLE_CONF = /Users/chrisfu/dev/prole/conf
|
||||
env_setup.PROLE_DATA = /Users/chrisfu/dev/prole/data
|
||||
env_setup.PROLE_HOME = /Users/chrisfu/dev/prole
|
||||
env_setup.PROLE_LOGS = /Users/chrisfu/dev/prole/logs
|
||||
env_setup.PROLE_SERVICE = /Users/chrisfu/dev/prole/etc
|
||||
init_cluster.argocd_enabled = false
|
||||
init_cluster.at_rest_encryption_enabled = true
|
||||
init_cluster.cluster_env = service
|
||||
init_cluster.deployment_target = prole-service-cluster
|
||||
init_cluster.gitops_enabled = false
|
||||
init_cluster.k3s_server_url = https://myrddin.prole.org:6443
|
||||
init_cluster.k3s_token = ${PROLE_SECRET:v1:_r5tIPt5VZcr0SrV:e2_sHY49gG2i-vhQZr-42M1kekln4D4ZHq6tJrDRCn8f4KOVSn59rndLt4PuHmsebPSPP4tGHZV0MaVtdBMm4RJmk9IXbqV7BjSNruK2SXi62NOXIIUWZGNcVIOFjmv7EovfOifo3nye8142zKDspTeyo5Y2KY6qGLtS2g==}
|
||||
init_cluster.kerberos_enabled = true
|
||||
init_cluster.mode = k3s
|
||||
init_cluster.start_cluster = true
|
||||
init_cluster.supabase_enabled = false
|
||||
init_cnpg_deploy.force_rollout = false
|
||||
init_cnpg_deploy.run_deploy = true
|
||||
init_db_build.run_build = true
|
||||
init_password.db_host_port = 5432
|
||||
init_password.db_namespace = ${NAMESPACE}
|
||||
init_password.db_password =
|
||||
init_password.db_password_confirm =
|
||||
init_password.db_username = root
|
||||
init_password.generate_ssh_key = true
|
||||
init_scripts.run_scripts = true
|
||||
kerberos_config.enabled = true
|
||||
kerberos_config.kdc = 10.0.0.3
|
||||
kerberos_config.password = ${PROLE_SECRET:v1:71ROfYyYysQDJDpX:0K4cB3p9nnMb1yi2OImqUm-pa9Zg21JYTmYHzYB_7czTKMQJ}
|
||||
kerberos_config.realm = PROLE.ORG
|
||||
kerberos_config.test_connection = false
|
||||
kerberos_config.user = administrator
|
||||
network_scan.run = true
|
||||
ollama_config.model =
|
||||
ollama_config.server_host = fairyland.prole.org
|
||||
ollama_config.server_port = 11434
|
||||
|
||||
[Global]
|
||||
; Variables used by name in more than one place or assumed global scope
|
||||
CLUSTER_ENV = service
|
||||
DB_HOST_PORT = 5432
|
||||
DB_PASSWORD =
|
||||
DEPLOYMENT_MODE = k3s
|
||||
DEPLOYMENT_TARGET = prole-service-cluster
|
||||
DOCKER_PRELOAD = false
|
||||
NAMESPACE = prole-db
|
||||
OPTIONAL_WORKLOADS_MIN_READY_SCHEDULABLE_NODES = 2
|
||||
PROLE_DB_USER = root
|
||||
PROLE_HOME = $HOME/dev/prole
|
||||
PROLE_K3S_SERVER = https://myrddin.prole.org:6443
|
||||
PROLE_K3S_TOKEN = ${PROLE_SECRET:v1:_r5tIPt5VZcr0SrV:e2_sHY49gG2i-vhQZr-42M1kekln4D4ZHq6tJrDRCn8f4KOVSn59rndLt4PuHmsebPSPP4tGHZV0MaVtdBMm4RJmk9IXbqV7BjSNruK2SXi62NOXIIUWZGNcVIOFjmv7EovfOifo3nye8142zKDspTeyo5Y2KY6qGLtS2g==}
|
||||
PROLE_OPENTOFU_URL = http://127.0.0.1:8080
|
||||
SERVICE_NAMESPACE = knoe-system
|
||||
|
||||
[Welcome]
|
||||
; No configuration values captured yet for this section.
|
||||
|
||||
[Dependencies]
|
||||
; No configuration values captured yet for this section.
|
||||
|
||||
[Network]
|
||||
AD_DC_HOST = myrddin.prole.org
|
||||
AD_DC_IP = 10.0.0.3
|
||||
ANSIBLE_DOMAIN = prole.org
|
||||
ANSIBLE_INFRASTRUCTURE = /Users/chrisfu/dev/prole/infrastructure
|
||||
ANSIBLE_INVENTORY = /Users/chrisfu/dev/prole/infrastructure/inventory
|
||||
ANSIBLE_REALM = PROLE.ORG
|
||||
ANSIBLE_TOPOLOGY = {"domain":"prole.org","realm":"PROLE.ORG","internal_records":{"aventage.prole.org":"10.0.0.206","fairyland.prole.org":"10.0.0.208","loghost.prole.org":"10.0.0.3","merlin.prole.org":"10.0.0.6","morana.prole.org":"10.0.0.66","morgoth.prole.org":"10.0.0.204","myrddin.prole.org":"10.0.0.3","pi.prole.org":"10.0.0.5","raspberry.prole.org":"10.0.0.4","retropie.prole.org":"10.0.0.207","synology.prole.org":"10.0.0.203","zinfandel.prole.org":"10.0.0.205"},"ad_dc":{"host":"myrddin.prole.org","ip":"10.0.0.3"},"k3s":{"server_url":"https://myrddin.prole.org:6443","server_host":"myrddin.prole.org","token_present":true},"groups":{"iscsi":["pi.prole.org","raspberry.prole.org","myrddin.prole.org","retropie.prole.org","merlin.prole.org"],"pihole":["pi.prole.org","raspberry.prole.org"],"ad_dc":["myrddin.prole.org"],"k3s_servers":["myrddin.prole.org"],"k3s_agents":["pi.prole.org","merlin.prole.org"],"k3s_hosts:children":["k3s_servers","k3s_agents"],"linux_hosts":["pi.prole.org","raspberry.prole.org","myrddin.prole.org","retropie.prole.org","merlin.prole.org"],"ssl_hosts":["myrddin.prole.org"],"mariadb_primary":["merlin.prole.org"],"mariadb_replica":["raspberry.prole.org"],"mariadb:children":["mariadb_primary","mariadb_replica"],"merlin_bootstrap":["merlin"]},"hosts":{"merlin":"10.0.0.6","merlin.prole.org":"10.0.0.6","myrddin.prole.org":"10.0.0.3","pi.prole.org":"10.0.0.5","raspberry.prole.org":"10.0.0.4","retropie.prole.org":"10.0.0.207"},"unmapped_hosts":["k3s_agents","k3s_servers","mariadb_primary","mariadb_replica"]}
|
||||
KDC_ANSIBLE_DETECTED = 10.0.0.3
|
||||
KDC_AUTO_DETECTED = 10.0.0.3
|
||||
KERBEROS_AUTO_ENABLED = True
|
||||
|
||||
[Port Forwards]
|
||||
; No configuration values captured yet for this section.
|
||||
|
||||
[System Environment]
|
||||
PROLE_CONF = /Users/chrisfu/dev/prole/conf
|
||||
PROLE_DATA = /Users/chrisfu/dev/prole/data
|
||||
PROLE_HOME = /Users/chrisfu/dev/prole
|
||||
PROLE_LOGS = /Users/chrisfu/dev/prole/logs
|
||||
PROLE_SERVICE = /Users/chrisfu/dev/prole/etc
|
||||
|
||||
[Monitoring]
|
||||
; No configuration values captured yet for this section.
|
||||
|
||||
[Kerberos Authentication]
|
||||
; No configuration values captured yet for this section.
|
||||
|
||||
[Ollama]
|
||||
OLLAMA_HOST = http://fairyland.prole.org:11434
|
||||
OLLAMA_SERVERS = fairyland.prole.org:11434,k3d.localhost:11434,morgoth.prole.org:11434
|
||||
OLLAMA_SERVER_HOST = fairyland.prole.org
|
||||
OLLAMA_SERVER_PORT = 11434
|
||||
|
||||
[Optional Features]
|
||||
GITOPS_ENABLED = False
|
||||
|
||||
[GitOps]
|
||||
; No configuration values captured yet for this section.
|
||||
|
||||
[Database Creation]
|
||||
; No configuration values captured yet for this section.
|
||||
|
||||
[Initialize Cluster]
|
||||
; No configuration values captured yet for this section.
|
||||
|
||||
[Dev Cluster (k3d)]
|
||||
CLUSTER_ENV = dev
|
||||
DISPLAY_NAME = knoe-dev-cluster
|
||||
KUBECTL_CONTEXT =
|
||||
MODE = k3d
|
||||
|
||||
[Service Cluster (k3s)]
|
||||
CLUSTER_ENV = prole-service-cluster
|
||||
DISPLAY_NAME = prole-service-cluster
|
||||
K3S_SERVER_URL = https://myrddin.prole.org:6443
|
||||
K3S_TOKEN = ${PROLE_SECRET:v1:_r5tIPt5VZcr0SrV:e2_sHY49gG2i-vhQZr-42M1kekln4D4ZHq6tJrDRCn8f4KOVSn59rndLt4PuHmsebPSPP4tGHZV0MaVtdBMm4RJmk9IXbqV7BjSNruK2SXi62NOXIIUWZGNcVIOFjmv7EovfOifo3nye8142zKDspTeyo5Y2KY6qGLtS2g==}
|
||||
MODE = k3s
|
||||
PIPELINE_URL = http://127.0.0.1:8080
|
||||
|
||||
[Prod Cluster (k8s)]
|
||||
ARTIFACTS_DIR = /Users/chrisfu/dev/prole/data/staging
|
||||
CLUSTER_ENV = prole-prod-cluster
|
||||
DISPLAY_NAME = prole-prod-cluster
|
||||
MODE = k8s
|
||||
PIPELINE_URL = http://127.0.0.1:8080
|
||||
|
||||
[Docker Build]
|
||||
; No configuration values captured yet for this section.
|
||||
|
||||
[Initialization Scripts]
|
||||
; No configuration values captured yet for this section.
|
||||
|
||||
[Deployment]
|
||||
MODE = k3s
|
||||
TARGET = prole-service-cluster
|
||||
|
||||
[Install]
|
||||
; No configuration values captured yet for this section.
|
||||
1
conf/service/prole.cfg
Symbolic link
1
conf/service/prole.cfg
Symbolic link
@ -0,0 +1 @@
|
||||
service/prole.cfg
|
||||
195
conf/service/prole.cfg.legacy.1774223813
Normal file
195
conf/service/prole.cfg.legacy.1774223813
Normal file
@ -0,0 +1,195 @@
|
||||
; Prole Master Configuration File
|
||||
; Generated by install.py on 2026-03-22 16:46:41
|
||||
; This file is used as input for Ansible deployment and k8s cluster creation.
|
||||
|
||||
[User]
|
||||
; User-editable values; derived values below reference these by default.
|
||||
; No user values captured yet for this section.
|
||||
|
||||
[Inputs]
|
||||
; Screen-scoped inputs used for unattended replays (-S)
|
||||
build.deploy_env = Dev
|
||||
build.run_build = false
|
||||
database_options.distribution = percona
|
||||
database_options.ext.dblink = true
|
||||
database_options.ext.pg_buffercache = true
|
||||
database_options.ext.pg_freespacemap = true
|
||||
database_options.ext.pg_repack = true
|
||||
database_options.ext.pg_stat_monitor = true
|
||||
database_options.ext.pg_stat_statements = true
|
||||
database_options.ext.pgaudit = true
|
||||
database_options.ext.pgbadger = true
|
||||
database_options.ext.pgcrypto = true
|
||||
database_options.ext.pgrowlocks = true
|
||||
database_options.ext.pgvector = true
|
||||
database_options.ext.postgis = true
|
||||
database_options.ext.postgres_fdw = true
|
||||
database_options.version_type = v18
|
||||
dependencies.ansible.install = true
|
||||
dependencies.auto_install_missing = true
|
||||
dependencies.brew.install = true
|
||||
dependencies.docker.install = true
|
||||
dependencies.k3d.install = true
|
||||
dependencies.kubectl.install = true
|
||||
dependencies.kubectx.install = true
|
||||
dependencies.opentofu.install = true
|
||||
dependencies.python.install = true
|
||||
dependencies.verify_all = false
|
||||
disk_selection.disk_type = local
|
||||
disk_selection.local_path = /Users/chrisfu/dev/prole/prole-tools-app/dist
|
||||
disk_selection.removable_mount =
|
||||
env_setup.NAMESPACE = ${NAMESPACE}
|
||||
env_setup.PROLE_CONF = /Users/chrisfu/dev/prole/conf
|
||||
env_setup.PROLE_DATA = /Users/chrisfu/dev/prole/data
|
||||
env_setup.PROLE_HOME = /Users/chrisfu/dev/prole
|
||||
env_setup.PROLE_LOGS = /Users/chrisfu/dev/prole/logs
|
||||
env_setup.PROLE_SERVICE = /Users/chrisfu/dev/prole/etc
|
||||
init_cluster.argocd_enabled = false
|
||||
init_cluster.at_rest_encryption_enabled = true
|
||||
init_cluster.cluster_env = service
|
||||
init_cluster.deployment_target = prole-service-cluster
|
||||
init_cluster.gitops_enabled = false
|
||||
init_cluster.k3s_server_url = https://myrddin.prole.org:6443
|
||||
init_cluster.k3s_token = ${PROLE_SECRET:v1:_r5tIPt5VZcr0SrV:e2_sHY49gG2i-vhQZr-42M1kekln4D4ZHq6tJrDRCn8f4KOVSn59rndLt4PuHmsebPSPP4tGHZV0MaVtdBMm4RJmk9IXbqV7BjSNruK2SXi62NOXIIUWZGNcVIOFjmv7EovfOifo3nye8142zKDspTeyo5Y2KY6qGLtS2g==}
|
||||
init_cluster.kerberos_enabled = true
|
||||
init_cluster.mode = k3s
|
||||
init_cluster.start_cluster = true
|
||||
init_cluster.supabase_enabled = false
|
||||
init_cnpg_deploy.force_rollout = false
|
||||
init_cnpg_deploy.run_deploy = true
|
||||
init_db_build.run_build = true
|
||||
init_password.db_host_port = 5432
|
||||
init_password.db_namespace = ${NAMESPACE}
|
||||
init_password.db_password = ${PROLE_SECRET:v1:LtY6hRqgZOeWP8OX:wWt4cT0CS2c4GZPB1RpSAo9cIFhLYvhw}
|
||||
init_password.db_password_confirm = ${PROLE_SECRET:v1:LtY6hRqgZOeWP8OX:wWt4cT0CS2c4GZPB1RpSAo9cIFhLYvhw}
|
||||
init_password.db_username = root
|
||||
init_password.generate_ssh_key = true
|
||||
init_scripts.run_scripts = true
|
||||
kerberos_config.enabled = true
|
||||
kerberos_config.init_authority = false
|
||||
kerberos_config.kdc = 10.0.0.3
|
||||
kerberos_config.password = ${PROLE_SECRET:v1:71ROfYyYysQDJDpX:0K4cB3p9nnMb1yi2OImqUm-pa9Zg21JYTmYHzYB_7czTKMQJ}
|
||||
kerberos_config.realm = PROLE.ORG
|
||||
kerberos_config.test_connection = false
|
||||
kerberos_config.user = administrator
|
||||
network_scan.run = true
|
||||
ollama_config.model =
|
||||
ollama_config.server_host = fairyland.prole.org
|
||||
ollama_config.server_port = 11434
|
||||
|
||||
[Global]
|
||||
; Variables used by name in more than one place or assumed global scope
|
||||
ARGOCD_NAMESPACE = argocd
|
||||
CLUSTER_ENV = service
|
||||
DB_HOST_PORT = 5432
|
||||
DB_PASSWORD = ${PROLE_SECRET:v1:NmgNZUhCsk-p0_DF:VB1tKREj45eEWcnN1GAlcGV6b_Lrl9sx}
|
||||
DEPLOYMENT_MODE = k3s
|
||||
DEPLOYMENT_TARGET = prole-service-cluster
|
||||
DOCKER_IMPORT_DIR =
|
||||
DOCKER_PRELOAD = false
|
||||
NAMESPACE = prole-db
|
||||
OPTIONAL_WORKLOADS_MIN_READY_SCHEDULABLE_NODES = 2
|
||||
PROLE_DB_USER = root
|
||||
PROLE_HOME = /Users/chrisfu/dev/prole
|
||||
PROLE_K3S_SERVER = https://myrddin.prole.org:6443
|
||||
PROLE_K3S_TOKEN = ${PROLE_SECRET:v1:_r5tIPt5VZcr0SrV:e2_sHY49gG2i-vhQZr-42M1kekln4D4ZHq6tJrDRCn8f4KOVSn59rndLt4PuHmsebPSPP4tGHZV0MaVtdBMm4RJmk9IXbqV7BjSNruK2SXi62NOXIIUWZGNcVIOFjmv7EovfOifo3nye8142zKDspTeyo5Y2KY6qGLtS2g==}
|
||||
PROLE_OPENTOFU_URL = http://127.0.0.1:8080
|
||||
REGISTRY_NAMESPACE = knoe-system
|
||||
SERVICE_NAMESPACE = knoe-system
|
||||
|
||||
[Welcome]
|
||||
; No configuration values captured yet for this section.
|
||||
|
||||
[Dependencies]
|
||||
STATUS = All installed
|
||||
|
||||
[Network]
|
||||
AD_DC_HOST = myrddin.prole.org
|
||||
AD_DC_IP = 10.0.0.3
|
||||
ANSIBLE_DOMAIN = prole.org
|
||||
ANSIBLE_INFRASTRUCTURE = /Users/chrisfu/dev/prole/infrastructure
|
||||
ANSIBLE_INVENTORY = /Users/chrisfu/dev/prole/infrastructure/inventory
|
||||
ANSIBLE_REALM = PROLE.ORG
|
||||
ANSIBLE_TOPOLOGY = {"domain":"prole.org","realm":"PROLE.ORG","internal_records":{"aventage.prole.org":"10.0.0.206","fairyland.prole.org":"10.0.0.208","loghost.prole.org":"10.0.0.3","merlin.prole.org":"10.0.0.6","morana.prole.org":"10.0.0.66","morgoth.prole.org":"10.0.0.204","myrddin.prole.org":"10.0.0.3","pi.prole.org":"10.0.0.5","raspberry.prole.org":"10.0.0.4","retropie.prole.org":"10.0.0.207","synology.prole.org":"10.0.0.203","zinfandel.prole.org":"10.0.0.205"},"ad_dc":{"host":"myrddin.prole.org","ip":"10.0.0.3"},"k3s":{"server_url":"https://myrddin.prole.org:6443","server_host":"myrddin.prole.org","token_present":true},"groups":{"iscsi":["pi.prole.org","raspberry.prole.org","myrddin.prole.org","retropie.prole.org","merlin.prole.org"],"pihole":["pi.prole.org","raspberry.prole.org"],"ad_dc":["myrddin.prole.org"],"k3s_servers":["myrddin.prole.org"],"k3s_agents":["pi.prole.org","merlin.prole.org"],"k3s_hosts:children":["k3s_servers","k3s_agents"],"linux_hosts":["pi.prole.org","raspberry.prole.org","myrddin.prole.org","retropie.prole.org","merlin.prole.org"],"ssl_hosts":["myrddin.prole.org"],"mariadb_primary":["merlin.prole.org"],"mariadb_replica":["raspberry.prole.org"],"mariadb:children":["mariadb_primary","mariadb_replica"],"merlin_bootstrap":["merlin"]},"hosts":{"merlin":"10.0.0.6","merlin.prole.org":"10.0.0.6","myrddin.prole.org":"10.0.0.3","pi.prole.org":"10.0.0.5","raspberry.prole.org":"10.0.0.4","retropie.prole.org":"10.0.0.207"},"unmapped_hosts":["k3s_agents","k3s_servers","mariadb_primary","mariadb_replica"]}
|
||||
KDC_ANSIBLE_DETECTED = 10.0.0.3
|
||||
KDC_AUTO_DETECTED = 10.0.0.3
|
||||
KERBEROS_AUTO_ENABLED = True
|
||||
|
||||
[Port Forwards]
|
||||
PORT_FORWARD_K3S_MAPPING_1 = id=argocd;namespace=argocd;target=svc/argocd-server;address=0.0.0.0;hostPort=8081;servicePort=80;protocol=TCP;description=ArgoCD
|
||||
PORT_FORWARD_K3S_MAPPING_2 = id=garage;namespace=knoe-system;target=svc/garage;address=0.0.0.0;hostPort=3900;servicePort=3900;protocol=TCP;description=Garage S3
|
||||
PORT_FORWARD_K3S_MAPPING_3 = id=openbao;namespace=knoe-system;target=svc/openbao;address=0.0.0.0;hostPort=8200;servicePort=8200;protocol=TCP;description=OpenBao
|
||||
PORT_FORWARD_K3S_MAPPING_4 = id=opentofu;namespace=knoe-system;target=svc/opentofu;address=0.0.0.0;hostPort=8080;servicePort=8080;protocol=TCP;description=OpenTofu
|
||||
PORT_FORWARD_K3S_MAPPING_5 = id=dashboard;namespace=kubernetes-dashboard;target=svc/kubernetes-dashboard-kong-proxy;address=127.0.0.1;hostPort=8443;servicePort=443;protocol=TCP;description=Kubernetes Dashboard
|
||||
PORT_FORWARD_K3S_MAPPING_6 = id=postgres;namespace=${NAMESPACE};target=svc/prole-db-rw;address=0.0.0.0;hostPort=5432;servicePort=5432;protocol=TCP;description=PostgreSQL (primary)
|
||||
PORT_FORWARD_K3S_MAPPING_7 = id=prometheus;namespace=monitoring;target=svc/kps-kube-prometheus-stack-prometheus;address=127.0.0.1;hostPort=9090;servicePort=9090;protocol=TCP;description=Prometheus UI
|
||||
PORT_FORWARD_K3S_MAPPING_8 = id=grafana;namespace=monitoring;target=svc/kps-grafana;address=0.0.0.0;hostPort=3000;servicePort=80;protocol=TCP;description=Grafana UI
|
||||
|
||||
[System Environment]
|
||||
NAMESPACE = prole-db
|
||||
PROLE_CONF = /Users/chrisfu/dev/prole/conf
|
||||
PROLE_DATA = /Users/chrisfu/dev/prole/data
|
||||
PROLE_HOME = /Users/chrisfu/dev/prole
|
||||
PROLE_LOGS = /Users/chrisfu/dev/prole/logs
|
||||
PROLE_SERVICE = /Users/chrisfu/dev/prole/etc
|
||||
|
||||
[Monitoring]
|
||||
; No configuration values captured yet for this section.
|
||||
|
||||
[Kerberos Authentication]
|
||||
; No configuration values captured yet for this section.
|
||||
|
||||
[Ollama]
|
||||
OLLAMA_HOST = http://fairyland.prole.org:11434
|
||||
OLLAMA_SERVERS = fairyland.prole.org:11434,k3d.localhost:11434,morgoth.prole.org:11434
|
||||
OLLAMA_SERVER_HOST = fairyland.prole.org
|
||||
OLLAMA_SERVER_PORT = 11434
|
||||
|
||||
[Optional Features]
|
||||
AT_REST_ENCRYPTION_ENABLED = true
|
||||
GITOPS_ENABLED = false
|
||||
KERBEROS_ENABLED = true
|
||||
SUPABASE_ENABLED = false
|
||||
|
||||
[GitOps]
|
||||
|
||||
[Database Creation]
|
||||
DB_NAME = prole-db
|
||||
DB_USER = root
|
||||
|
||||
[Initialize Cluster]
|
||||
; No configuration values captured yet for this section.
|
||||
|
||||
[Dev Cluster (k3d)]
|
||||
CLUSTER_ENV = k3d-knoe-dev-cluster
|
||||
DISPLAY_NAME = knoe-dev-cluster
|
||||
KUBECTL_CONTEXT = service
|
||||
MODE = k3d
|
||||
|
||||
[Service Cluster (k3s)]
|
||||
CLUSTER_ENV = prole-service-cluster
|
||||
DISPLAY_NAME = prole-service-cluster
|
||||
K3S_SERVER_URL = https://myrddin.prole.org:6443
|
||||
K3S_TOKEN = ${PROLE_SECRET:v1:_r5tIPt5VZcr0SrV:e2_sHY49gG2i-vhQZr-42M1kekln4D4ZHq6tJrDRCn8f4KOVSn59rndLt4PuHmsebPSPP4tGHZV0MaVtdBMm4RJmk9IXbqV7BjSNruK2SXi62NOXIIUWZGNcVIOFjmv7EovfOifo3nye8142zKDspTeyo5Y2KY6qGLtS2g==}
|
||||
MODE = k3s
|
||||
PIPELINE_URL = http://127.0.0.1:8080
|
||||
|
||||
[Prod Cluster (k8s)]
|
||||
ARTIFACTS_DIR =
|
||||
CLUSTER_ENV = prole-prod-cluster
|
||||
DISPLAY_NAME = prole-prod-cluster
|
||||
MODE = k8s
|
||||
PIPELINE_URL = http://127.0.0.1:8080
|
||||
|
||||
[Docker Build]
|
||||
; No configuration values captured yet for this section.
|
||||
|
||||
[Initialization Scripts]
|
||||
; No configuration values captured yet for this section.
|
||||
|
||||
[Deployment]
|
||||
MODE = k3s
|
||||
TARGET = prole-service-cluster
|
||||
|
||||
[Install]
|
||||
STATUS = Failed
|
||||
195
conf/service/service/prole.cfg
Normal file
195
conf/service/service/prole.cfg
Normal file
@ -0,0 +1,195 @@
|
||||
; Prole Master Configuration File
|
||||
; Generated by install.py on 2026-03-22 20:46:43
|
||||
; This file is used as input for Ansible deployment and k8s cluster creation.
|
||||
|
||||
[User]
|
||||
; User-editable values; derived values below reference these by default.
|
||||
; No user values captured yet for this section.
|
||||
|
||||
[Inputs]
|
||||
; Screen-scoped inputs used for unattended replays (-S)
|
||||
build.deploy_env = Dev
|
||||
build.run_build = false
|
||||
database_options.distribution = percona
|
||||
database_options.ext.dblink = true
|
||||
database_options.ext.pg_buffercache = true
|
||||
database_options.ext.pg_freespacemap = true
|
||||
database_options.ext.pg_repack = true
|
||||
database_options.ext.pg_stat_monitor = true
|
||||
database_options.ext.pg_stat_statements = true
|
||||
database_options.ext.pgaudit = true
|
||||
database_options.ext.pgbadger = true
|
||||
database_options.ext.pgcrypto = true
|
||||
database_options.ext.pgrowlocks = true
|
||||
database_options.ext.pgvector = true
|
||||
database_options.ext.postgis = true
|
||||
database_options.ext.postgres_fdw = true
|
||||
database_options.version_type = v18
|
||||
dependencies.ansible.install = true
|
||||
dependencies.auto_install_missing = true
|
||||
dependencies.brew.install = true
|
||||
dependencies.docker.install = true
|
||||
dependencies.k3d.install = true
|
||||
dependencies.kubectl.install = true
|
||||
dependencies.kubectx.install = true
|
||||
dependencies.opentofu.install = true
|
||||
dependencies.python.install = true
|
||||
dependencies.verify_all = false
|
||||
disk_selection.disk_type = local
|
||||
disk_selection.local_path = /Users/chrisfu/dev/prole/prole-tools-app/dist
|
||||
disk_selection.removable_mount =
|
||||
env_setup.NAMESPACE = ${NAMESPACE}
|
||||
env_setup.PROLE_CONF = /Users/chrisfu/dev/prole/conf
|
||||
env_setup.PROLE_DATA = /Users/chrisfu/dev/prole/data
|
||||
env_setup.PROLE_HOME = /Users/chrisfu/dev/prole
|
||||
env_setup.PROLE_LOGS = /Users/chrisfu/dev/prole/logs
|
||||
env_setup.PROLE_SERVICE = /Users/chrisfu/dev/prole/etc
|
||||
init_cluster.argocd_enabled = false
|
||||
init_cluster.at_rest_encryption_enabled = true
|
||||
init_cluster.cluster_env = service
|
||||
init_cluster.deployment_target = prole-service-cluster
|
||||
init_cluster.gitops_enabled = false
|
||||
init_cluster.k3s_server_url = https://myrddin.prole.org:6443
|
||||
init_cluster.k3s_token = ${PROLE_SECRET:v1:_r5tIPt5VZcr0SrV:e2_sHY49gG2i-vhQZr-42M1kekln4D4ZHq6tJrDRCn8f4KOVSn59rndLt4PuHmsebPSPP4tGHZV0MaVtdBMm4RJmk9IXbqV7BjSNruK2SXi62NOXIIUWZGNcVIOFjmv7EovfOifo3nye8142zKDspTeyo5Y2KY6qGLtS2g==}
|
||||
init_cluster.kerberos_enabled = true
|
||||
init_cluster.mode = k3s
|
||||
init_cluster.start_cluster = true
|
||||
init_cluster.supabase_enabled = false
|
||||
init_cnpg_deploy.force_rollout = false
|
||||
init_cnpg_deploy.run_deploy = true
|
||||
init_db_build.run_build = true
|
||||
init_password.db_host_port = 5432
|
||||
init_password.db_namespace = ${NAMESPACE}
|
||||
init_password.db_password = ${PROLE_SECRET:v1:vz4oaR5QA3zIJWDs:blYR6vqpY0e_GqGWFufDwlY4yxXWXrGF}
|
||||
init_password.db_password_confirm = ${PROLE_SECRET:v1:vz4oaR5QA3zIJWDs:blYR6vqpY0e_GqGWFufDwlY4yxXWXrGF}
|
||||
init_password.db_username = root
|
||||
init_password.generate_ssh_key = true
|
||||
init_scripts.run_scripts = true
|
||||
kerberos_config.enabled = true
|
||||
kerberos_config.init_authority = false
|
||||
kerberos_config.kdc = 10.0.0.3
|
||||
kerberos_config.password = ${PROLE_SECRET:v1:71ROfYyYysQDJDpX:0K4cB3p9nnMb1yi2OImqUm-pa9Zg21JYTmYHzYB_7czTKMQJ}
|
||||
kerberos_config.realm = PROLE.ORG
|
||||
kerberos_config.test_connection = false
|
||||
kerberos_config.user = administrator
|
||||
network_scan.run = true
|
||||
ollama_config.model =
|
||||
ollama_config.server_host = fairyland.prole.org
|
||||
ollama_config.server_port = 11434
|
||||
|
||||
[Global]
|
||||
; Variables used by name in more than one place or assumed global scope
|
||||
ARGOCD_NAMESPACE = argocd
|
||||
CLUSTER_ENV = service
|
||||
DB_HOST_PORT = 5432
|
||||
DB_PASSWORD = ${PROLE_SECRET:v1:NmgNZUhCsk-p0_DF:VB1tKREj45eEWcnN1GAlcGV6b_Lrl9sx}
|
||||
DEPLOYMENT_MODE = k3s
|
||||
DEPLOYMENT_TARGET = prole-service-cluster
|
||||
DOCKER_IMPORT_DIR =
|
||||
DOCKER_PRELOAD = false
|
||||
NAMESPACE = prole-db
|
||||
OPTIONAL_WORKLOADS_MIN_READY_SCHEDULABLE_NODES = 2
|
||||
PROLE_DB_USER = root
|
||||
PROLE_HOME = /Users/chrisfu/dev/prole
|
||||
PROLE_K3S_SERVER = https://myrddin.prole.org:6443
|
||||
PROLE_K3S_TOKEN = ${PROLE_SECRET:v1:_r5tIPt5VZcr0SrV:e2_sHY49gG2i-vhQZr-42M1kekln4D4ZHq6tJrDRCn8f4KOVSn59rndLt4PuHmsebPSPP4tGHZV0MaVtdBMm4RJmk9IXbqV7BjSNruK2SXi62NOXIIUWZGNcVIOFjmv7EovfOifo3nye8142zKDspTeyo5Y2KY6qGLtS2g==}
|
||||
PROLE_OPENTOFU_URL = http://myrddin.prole.org:8080
|
||||
REGISTRY_NAMESPACE = knoe-system
|
||||
SERVICE_NAMESPACE = knoe-system
|
||||
|
||||
[Welcome]
|
||||
; No configuration values captured yet for this section.
|
||||
|
||||
[Dependencies]
|
||||
STATUS = All installed
|
||||
|
||||
[Network]
|
||||
AD_DC_HOST = myrddin.prole.org
|
||||
AD_DC_IP = 10.0.0.3
|
||||
ANSIBLE_DOMAIN = prole.org
|
||||
ANSIBLE_INFRASTRUCTURE = /Users/chrisfu/dev/prole/infrastructure
|
||||
ANSIBLE_INVENTORY = /Users/chrisfu/dev/prole/infrastructure/inventory
|
||||
ANSIBLE_REALM = PROLE.ORG
|
||||
ANSIBLE_TOPOLOGY = {"domain":"prole.org","realm":"PROLE.ORG","internal_records":{"aventage.prole.org":"10.0.0.206","fairyland.prole.org":"10.0.0.208","loghost.prole.org":"10.0.0.3","merlin.prole.org":"10.0.0.6","morana.prole.org":"10.0.0.66","morgoth.prole.org":"10.0.0.204","myrddin.prole.org":"10.0.0.3","pi.prole.org":"10.0.0.5","raspberry.prole.org":"10.0.0.4","retropie.prole.org":"10.0.0.207","synology.prole.org":"10.0.0.203","zinfandel.prole.org":"10.0.0.205"},"ad_dc":{"host":"myrddin.prole.org","ip":"10.0.0.3"},"k3s":{"server_url":"https://myrddin.prole.org:6443","server_host":"myrddin.prole.org","token_present":true},"groups":{"iscsi":["pi.prole.org","raspberry.prole.org","myrddin.prole.org","retropie.prole.org","merlin.prole.org"],"pihole":["pi.prole.org","raspberry.prole.org"],"ad_dc":["myrddin.prole.org"],"k3s_servers":["myrddin.prole.org"],"k3s_agents":["pi.prole.org","merlin.prole.org"],"k3s_hosts:children":["k3s_servers","k3s_agents"],"linux_hosts":["pi.prole.org","raspberry.prole.org","myrddin.prole.org","retropie.prole.org","merlin.prole.org"],"ssl_hosts":["myrddin.prole.org"],"mariadb_primary":["merlin.prole.org"],"mariadb_replica":["raspberry.prole.org"],"mariadb:children":["mariadb_primary","mariadb_replica"],"merlin_bootstrap":["merlin"]},"hosts":{"merlin":"10.0.0.6","merlin.prole.org":"10.0.0.6","myrddin.prole.org":"10.0.0.3","pi.prole.org":"10.0.0.5","raspberry.prole.org":"10.0.0.4","retropie.prole.org":"10.0.0.207"},"unmapped_hosts":["k3s_agents","k3s_servers","mariadb_primary","mariadb_replica"]}
|
||||
KDC_ANSIBLE_DETECTED = 10.0.0.3
|
||||
KDC_AUTO_DETECTED = 10.0.0.3
|
||||
KERBEROS_AUTO_ENABLED = True
|
||||
|
||||
[Port Forwards]
|
||||
PORT_FORWARD_K3S_MAPPING_1 = id=argocd;namespace=argocd;target=svc/argocd-server;address=0.0.0.0;hostPort=8081;servicePort=80;protocol=TCP;description=ArgoCD
|
||||
PORT_FORWARD_K3S_MAPPING_2 = id=garage;namespace=knoe-system;target=svc/garage;address=0.0.0.0;hostPort=3900;servicePort=3900;protocol=TCP;description=Garage S3
|
||||
PORT_FORWARD_K3S_MAPPING_3 = id=openbao;namespace=knoe-system;target=svc/openbao;address=0.0.0.0;hostPort=8200;servicePort=8200;protocol=TCP;description=OpenBao
|
||||
PORT_FORWARD_K3S_MAPPING_4 = id=opentofu;namespace=knoe-system;target=svc/opentofu;address=0.0.0.0;hostPort=8080;servicePort=8080;protocol=TCP;description=OpenTofu
|
||||
PORT_FORWARD_K3S_MAPPING_5 = id=dashboard;namespace=kubernetes-dashboard;target=svc/kubernetes-dashboard-kong-proxy;address=127.0.0.1;hostPort=8443;servicePort=443;protocol=TCP;description=Kubernetes Dashboard
|
||||
PORT_FORWARD_K3S_MAPPING_6 = id=postgres;namespace=${NAMESPACE};target=svc/prole-db-rw;address=0.0.0.0;hostPort=5432;servicePort=5432;protocol=TCP;description=PostgreSQL (primary)
|
||||
PORT_FORWARD_K3S_MAPPING_7 = id=prometheus;namespace=monitoring;target=svc/kps-kube-prometheus-stack-prometheus;address=127.0.0.1;hostPort=9090;servicePort=9090;protocol=TCP;description=Prometheus UI
|
||||
PORT_FORWARD_K3S_MAPPING_8 = id=grafana;namespace=monitoring;target=svc/kps-grafana;address=0.0.0.0;hostPort=3000;servicePort=80;protocol=TCP;description=Grafana UI
|
||||
|
||||
[System Environment]
|
||||
NAMESPACE = prole-db
|
||||
PROLE_CONF = /Users/chrisfu/dev/prole/conf
|
||||
PROLE_DATA = /Users/chrisfu/dev/prole/data
|
||||
PROLE_HOME = /Users/chrisfu/dev/prole
|
||||
PROLE_LOGS = /Users/chrisfu/dev/prole/logs
|
||||
PROLE_SERVICE = /Users/chrisfu/dev/prole/etc
|
||||
|
||||
[Monitoring]
|
||||
; No configuration values captured yet for this section.
|
||||
|
||||
[Kerberos Authentication]
|
||||
; No configuration values captured yet for this section.
|
||||
|
||||
[Ollama]
|
||||
OLLAMA_HOST = http://fairyland.prole.org:11434
|
||||
OLLAMA_SERVERS = fairyland.prole.org:11434,k3d.localhost:11434,morgoth.prole.org:11434
|
||||
OLLAMA_SERVER_HOST = fairyland.prole.org
|
||||
OLLAMA_SERVER_PORT = 11434
|
||||
|
||||
[Optional Features]
|
||||
AT_REST_ENCRYPTION_ENABLED = true
|
||||
GITOPS_ENABLED = false
|
||||
KERBEROS_ENABLED = true
|
||||
SUPABASE_ENABLED = false
|
||||
|
||||
[GitOps]
|
||||
|
||||
[Database Creation]
|
||||
DB_NAME = prole-db
|
||||
DB_USER = root
|
||||
|
||||
[Initialize Cluster]
|
||||
; No configuration values captured yet for this section.
|
||||
|
||||
[Dev Cluster (k3d)]
|
||||
CLUSTER_ENV = k3d-knoe-dev-cluster
|
||||
DISPLAY_NAME = knoe-dev-cluster
|
||||
KUBECTL_CONTEXT = service
|
||||
MODE = k3d
|
||||
|
||||
[Service Cluster (k3s)]
|
||||
CLUSTER_ENV = prole-service-cluster
|
||||
DISPLAY_NAME = prole-service-cluster
|
||||
K3S_SERVER_URL = https://myrddin.prole.org:6443
|
||||
K3S_TOKEN = ${PROLE_SECRET:v1:_r5tIPt5VZcr0SrV:e2_sHY49gG2i-vhQZr-42M1kekln4D4ZHq6tJrDRCn8f4KOVSn59rndLt4PuHmsebPSPP4tGHZV0MaVtdBMm4RJmk9IXbqV7BjSNruK2SXi62NOXIIUWZGNcVIOFjmv7EovfOifo3nye8142zKDspTeyo5Y2KY6qGLtS2g==}
|
||||
MODE = k3s
|
||||
PIPELINE_URL = http://myrddin.prole.org:8080
|
||||
|
||||
[Prod Cluster (k8s)]
|
||||
ARTIFACTS_DIR =
|
||||
CLUSTER_ENV = prole-prod-cluster
|
||||
DISPLAY_NAME = prole-prod-cluster
|
||||
MODE = k8s
|
||||
PIPELINE_URL = http://myrddin.prole.org:8080
|
||||
|
||||
[Docker Build]
|
||||
; No configuration values captured yet for this section.
|
||||
|
||||
[Initialization Scripts]
|
||||
; No configuration values captured yet for this section.
|
||||
|
||||
[Deployment]
|
||||
MODE = k3s
|
||||
TARGET = prole-service-cluster
|
||||
|
||||
[Install]
|
||||
STATUS = Failed
|
||||
@ -71,8 +71,8 @@ spec:
|
||||
resources:
|
||||
requests:
|
||||
storage: 29Gi
|
||||
storageClassName: prole-iscsi
|
||||
storageClassName: synology-iscsi
|
||||
selector:
|
||||
matchLabels:
|
||||
prole.storage/role: garage
|
||||
prole.storage/volume: d001
|
||||
synology.storage/role: garage
|
||||
synology.storage/volume: d001
|
||||
|
||||
@ -1,17 +1,17 @@
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: prole-iscsi-d001-data
|
||||
name: synology-iscsi-d001-data
|
||||
labels:
|
||||
prole.storage/role: data
|
||||
prole.storage/volume: d001
|
||||
synology.storage/role: data
|
||||
synology.storage/volume: d001
|
||||
spec:
|
||||
capacity:
|
||||
storage: 29Gi
|
||||
volumeMode: Filesystem
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
storageClassName: prole-iscsi
|
||||
storageClassName: synology-iscsi
|
||||
persistentVolumeReclaimPolicy: Retain
|
||||
local:
|
||||
path: /synology/d001/data
|
||||
@ -27,17 +27,17 @@ spec:
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: prole-iscsi-d001-wal
|
||||
name: synology-iscsi-d001-wal
|
||||
labels:
|
||||
prole.storage/role: wal
|
||||
prole.storage/volume: d001
|
||||
synology.storage/role: wal
|
||||
synology.storage/volume: d001
|
||||
spec:
|
||||
capacity:
|
||||
storage: 29Gi
|
||||
volumeMode: Filesystem
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
storageClassName: prole-iscsi
|
||||
storageClassName: synology-iscsi
|
||||
persistentVolumeReclaimPolicy: Retain
|
||||
local:
|
||||
path: /synology/d001/wal
|
||||
@ -53,17 +53,17 @@ spec:
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: prole-iscsi-d001-garage
|
||||
name: synology-iscsi-d001-garage
|
||||
labels:
|
||||
prole.storage/role: garage
|
||||
prole.storage/volume: d001
|
||||
synology.storage/role: garage
|
||||
synology.storage/volume: d001
|
||||
spec:
|
||||
capacity:
|
||||
storage: 29Gi
|
||||
volumeMode: Filesystem
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
storageClassName: prole-iscsi
|
||||
storageClassName: synology-iscsi
|
||||
persistentVolumeReclaimPolicy: Retain
|
||||
local:
|
||||
path: /synology/d001/garage
|
||||
@ -79,17 +79,17 @@ spec:
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: prole-iscsi-d002-data
|
||||
name: synology-iscsi-d002-data
|
||||
labels:
|
||||
prole.storage/role: data
|
||||
prole.storage/volume: d002
|
||||
synology.storage/role: data
|
||||
synology.storage/volume: d002
|
||||
spec:
|
||||
capacity:
|
||||
storage: 29Gi
|
||||
volumeMode: Filesystem
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
storageClassName: prole-iscsi
|
||||
storageClassName: synology-iscsi
|
||||
persistentVolumeReclaimPolicy: Retain
|
||||
local:
|
||||
path: /synology/d002/data
|
||||
@ -105,17 +105,17 @@ spec:
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: prole-iscsi-d002-wal
|
||||
name: synology-iscsi-d002-wal
|
||||
labels:
|
||||
prole.storage/role: wal
|
||||
prole.storage/volume: d002
|
||||
synology.storage/role: wal
|
||||
synology.storage/volume: d002
|
||||
spec:
|
||||
capacity:
|
||||
storage: 29Gi
|
||||
volumeMode: Filesystem
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
storageClassName: prole-iscsi
|
||||
storageClassName: synology-iscsi
|
||||
persistentVolumeReclaimPolicy: Retain
|
||||
local:
|
||||
path: /synology/d002/wal
|
||||
@ -131,17 +131,17 @@ spec:
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: prole-iscsi-d003-data
|
||||
name: synology-iscsi-d003-data
|
||||
labels:
|
||||
prole.storage/role: data
|
||||
prole.storage/volume: d003
|
||||
synology.storage/role: data
|
||||
synology.storage/volume: d003
|
||||
spec:
|
||||
capacity:
|
||||
storage: 29Gi
|
||||
volumeMode: Filesystem
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
storageClassName: prole-iscsi
|
||||
storageClassName: synology-iscsi
|
||||
persistentVolumeReclaimPolicy: Retain
|
||||
local:
|
||||
path: /synology/d003/data
|
||||
@ -157,17 +157,17 @@ spec:
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: prole-iscsi-d003-wal
|
||||
name: synology-iscsi-d003-wal
|
||||
labels:
|
||||
prole.storage/role: wal
|
||||
prole.storage/volume: d003
|
||||
synology.storage/role: wal
|
||||
synology.storage/volume: d003
|
||||
spec:
|
||||
capacity:
|
||||
storage: 29Gi
|
||||
volumeMode: Filesystem
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
storageClassName: prole-iscsi
|
||||
storageClassName: synology-iscsi
|
||||
persistentVolumeReclaimPolicy: Retain
|
||||
local:
|
||||
path: /synology/d003/wal
|
||||
@ -183,17 +183,17 @@ spec:
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: prole-iscsi-d003-grafana
|
||||
name: synology-iscsi-d003-grafana
|
||||
labels:
|
||||
prole.storage/role: grafana
|
||||
prole.storage/volume: d003
|
||||
synology.storage/role: grafana
|
||||
synology.storage/volume: d003
|
||||
spec:
|
||||
capacity:
|
||||
storage: 5Gi
|
||||
volumeMode: Filesystem
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
storageClassName: prole-iscsi
|
||||
storageClassName: synology-iscsi
|
||||
persistentVolumeReclaimPolicy: Retain
|
||||
local:
|
||||
path: /synology/d003/grafana
|
||||
@ -209,17 +209,17 @@ spec:
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: prole-iscsi-d002-prometheus
|
||||
name: synology-iscsi-d002-prometheus
|
||||
labels:
|
||||
prole.storage/role: prometheus
|
||||
prole.storage/volume: d002
|
||||
synology.storage/role: prometheus
|
||||
synology.storage/volume: d002
|
||||
spec:
|
||||
capacity:
|
||||
storage: 20Gi
|
||||
volumeMode: Filesystem
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
storageClassName: prole-iscsi
|
||||
storageClassName: synology-iscsi
|
||||
persistentVolumeReclaimPolicy: Retain
|
||||
local:
|
||||
path: /synology/d002/prometheus
|
||||
@ -235,17 +235,17 @@ spec:
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: prole-iscsi-d001-openbao
|
||||
name: synology-iscsi-d001-openbao
|
||||
labels:
|
||||
prole.storage/role: openbao
|
||||
prole.storage/volume: d001
|
||||
synology.storage/role: openbao
|
||||
synology.storage/volume: d001
|
||||
spec:
|
||||
capacity:
|
||||
storage: 5Gi
|
||||
volumeMode: Filesystem
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
storageClassName: prole-iscsi
|
||||
storageClassName: synology-iscsi
|
||||
persistentVolumeReclaimPolicy: Retain
|
||||
local:
|
||||
path: /synology/d001/openbao
|
||||
|
||||
@ -51,7 +51,7 @@ spec:
|
||||
resources:
|
||||
requests:
|
||||
storage: 1Gi
|
||||
storageClassName: prole-iscsi
|
||||
storageClassName: synology-iscsi
|
||||
selector:
|
||||
matchLabels:
|
||||
prole.storage/role: openbao
|
||||
synology.storage/role: openbao
|
||||
|
||||
@ -4,27 +4,23 @@ metadata:
|
||||
name: prole-db
|
||||
spec:
|
||||
instances: 3
|
||||
imageName: k3d-prole-registry:5000/knoe-db:18-138
|
||||
imageName: k3d-prole-registry:5000/knoe-db:18-140
|
||||
postgresUID: 100
|
||||
postgresGID: 101
|
||||
maxSyncReplicas: 1
|
||||
affinity:
|
||||
# CloudNativePG uses its own affinity schema (not corev1.Affinity). See: `kubectl explain cluster.spec.affinity`
|
||||
enablePodAntiAffinity: true
|
||||
podAntiAffinityType: required
|
||||
podAntiAffinityType: preferred
|
||||
topologyKey: kubernetes.io/hostname
|
||||
tolerations:
|
||||
- key: "node-role.kubernetes.io/control-plane"
|
||||
operator: "Exists"
|
||||
effect: "NoSchedule"
|
||||
nodeAffinity:
|
||||
requiredDuringSchedulingIgnoredDuringExecution:
|
||||
nodeSelectorTerms:
|
||||
- matchExpressions:
|
||||
- key: prole.org/node-role
|
||||
- key: node.kubernetes.io/instance-type
|
||||
operator: In
|
||||
values:
|
||||
- db
|
||||
- k3s
|
||||
|
||||
postgresql:
|
||||
parameters:
|
||||
@ -92,10 +88,10 @@ spec:
|
||||
resources:
|
||||
requests:
|
||||
storage: 1Gi
|
||||
storageClassName: prole-iscsi
|
||||
storageClassName: synology-iscsi
|
||||
selector:
|
||||
matchLabels:
|
||||
prole.storage/role: data
|
||||
synology.storage/role: data
|
||||
walStorage:
|
||||
size: 1Gi
|
||||
pvcTemplate:
|
||||
@ -104,9 +100,9 @@ spec:
|
||||
resources:
|
||||
requests:
|
||||
storage: 1Gi
|
||||
storageClassName: prole-iscsi
|
||||
storageClassName: synology-iscsi
|
||||
selector:
|
||||
matchLabels:
|
||||
prole.storage/role: wal
|
||||
synology.storage/role: wal
|
||||
monitoring:
|
||||
enablePodMonitor: false
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
apiVersion: storage.k8s.io/v1
|
||||
kind: StorageClass
|
||||
metadata:
|
||||
name: prole-iscsi
|
||||
name: synology-iscsi
|
||||
provisioner: kubernetes.io/no-provisioner
|
||||
reclaimPolicy: Retain
|
||||
volumeBindingMode: WaitForFirstConsumer
|
||||
@ -101,9 +101,9 @@ CERT_MANAGER_MANIFEST_URL=${CERT_MANAGER_MANIFEST_URL:-}
|
||||
CERT_MANAGER_FALLBACK_VERSION=${CERT_MANAGER_FALLBACK_VERSION:-1.19.3}
|
||||
|
||||
# Protected storage requirements (k3s only)
|
||||
PROLE_CNPG_STORAGE_CLASS=${PROLE_CNPG_STORAGE_CLASS:-prole-iscsi}
|
||||
PROLE_PROTECTED_DATA_PATH=${PROLE_PROTECTED_DATA_PATH:-/prole/d001/data}
|
||||
PROLE_PROTECTED_WAL_PATH=${PROLE_PROTECTED_WAL_PATH:-/prole/d001/wal}
|
||||
PROLE_CNPG_STORAGE_CLASS=${PROLE_CNPG_STORAGE_CLASS:-synology-iscsi}
|
||||
PROLE_PROTECTED_DATA_PATH=${PROLE_PROTECTED_DATA_PATH:-/synology/d001/data}
|
||||
PROLE_PROTECTED_WAL_PATH=${PROLE_PROTECTED_WAL_PATH:-/synology/d001/wal}
|
||||
|
||||
if [[ "$ACTION" != "deploy" && "$ACTION" != "rollout" && "$ACTION" != "force-rollout" ]]; then
|
||||
if [[ -n "${2:-}" ]]; then
|
||||
@ -265,9 +265,9 @@ validate_cnpg_manifest_storage() {
|
||||
wal_sc="$v"
|
||||
fi
|
||||
fi
|
||||
if [[ -n "$block" && "$line" =~ prole\.storage/role: ]]; then
|
||||
if [[ -n "$block" && "$line" =~ synology\.storage/role: ]]; then
|
||||
local r
|
||||
r=$(printf '%s' "$line" | sed -E 's/^.*prole\.storage\/role:[[:space:]]*//; s/[[:space:]]+$//')
|
||||
r=$(printf '%s' "$line" | sed -E 's/^.*synology\.storage\/role:[[:space:]]*//; s/[[:space:]]+$//')
|
||||
if [[ "$block" == "storage" && -z "$data_role" ]]; then
|
||||
data_role="$r"
|
||||
elif [[ "$block" == "wal" && -z "$wal_role" ]]; then
|
||||
@ -283,7 +283,7 @@ validate_cnpg_manifest_storage() {
|
||||
fi
|
||||
|
||||
if [[ "$data_role" != "data" || "$wal_role" != "wal" ]]; then
|
||||
echo "ERROR: CNPG Cluster manifest must include explicit PV selectors for Prole storage (prole.storage/role=data and prole.storage/role=wal)." >&2
|
||||
echo "ERROR: CNPG Cluster manifest must include explicit PV selectors for Prole storage (synology.storage/role=data and synology.storage/role=wal)." >&2
|
||||
echo "Got selector roles: data='${data_role:-<missing>}', wal='${wal_role:-<missing>}'" >&2
|
||||
return 1
|
||||
fi
|
||||
@ -307,8 +307,8 @@ validate_cnpg_runtime_storage() {
|
||||
local data_sc wal_sc data_role wal_role
|
||||
data_sc=$(printf '%s' "$cluster_json" | jq -r '.spec.storage.pvcTemplate.storageClassName // empty')
|
||||
wal_sc=$(printf '%s' "$cluster_json" | jq -r '.spec.walStorage.pvcTemplate.storageClassName // empty')
|
||||
data_role=$(printf '%s' "$cluster_json" | jq -r '.spec.storage.pvcTemplate.selector.matchLabels["prole.storage/role"] // empty')
|
||||
wal_role=$(printf '%s' "$cluster_json" | jq -r '.spec.walStorage.pvcTemplate.selector.matchLabels["prole.storage/role"] // empty')
|
||||
data_role=$(printf '%s' "$cluster_json" | jq -r '.spec.storage.pvcTemplate.selector.matchLabels["synology.storage/role"] // empty')
|
||||
wal_role=$(printf '%s' "$cluster_json" | jq -r '.spec.walStorage.pvcTemplate.selector.matchLabels["synology.storage/role"] // empty')
|
||||
|
||||
if [[ "$data_sc" != "$sc" || "$wal_sc" != "$sc" ]]; then
|
||||
echo "ERROR: Live CNPG Cluster storageClassName must be '${sc}' for both data and walStorage (got data='${data_sc:-<missing>}', wal='${wal_sc:-<missing>}')." >&2
|
||||
@ -366,9 +366,9 @@ validate_cnpg_runtime_storage() {
|
||||
return 1
|
||||
fi
|
||||
case "$pv_path" in
|
||||
/prole/*) ;;
|
||||
/synology/*) ;;
|
||||
*)
|
||||
echo "ERROR: Bound PV '${pv}' path '${pv_path}' is not under /prole/. Refusing deployment." >&2
|
||||
echo "ERROR: Bound PV '${pv}' path '${pv_path}' is not under /synology/. Refusing deployment." >&2
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
@ -448,16 +448,20 @@ wait_for_apiserver_ready() {
|
||||
}
|
||||
|
||||
ensure_namespace() {
|
||||
if [[ -z "${PROLE_NAMESPACE:-}" ]]; then
|
||||
echo "ERROR: PROLE_NAMESPACE is empty. Set NAMESPACE in conf/prole.cfg." >&2
|
||||
exit 1
|
||||
fi
|
||||
require_namespace_configured
|
||||
if ! kubectl get namespace "$PROLE_NAMESPACE" >/dev/null 2>&1; then
|
||||
echo "Creating namespace '$PROLE_NAMESPACE' ..."
|
||||
kubectl create namespace "$PROLE_NAMESPACE" >/dev/null 2>&1 || true
|
||||
fi
|
||||
}
|
||||
|
||||
require_namespace_configured() {
|
||||
if [[ -z "${PROLE_NAMESPACE:-}" ]]; then
|
||||
echo "ERROR: PROLE_NAMESPACE is empty. Set NAMESPACE in conf/prole.cfg." >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
kubectl_apply_retry() {
|
||||
local namespace="${1:-}"
|
||||
local attempts=${2:-8}
|
||||
@ -540,6 +544,17 @@ get_latest_image() {
|
||||
echo "knoe-db:${pg_version}-${release}"
|
||||
}
|
||||
|
||||
_desired_cnpg_image() {
|
||||
local image
|
||||
if [[ "$VERSION" == "latest" || -z "$VERSION" ]]; then
|
||||
image=$(get_latest_image)
|
||||
else
|
||||
image="knoe-db:$VERSION"
|
||||
fi
|
||||
image=$(resolve_cnpg_image "$image")
|
||||
printf '%s' "$image"
|
||||
}
|
||||
|
||||
_cnpg_current_image_name() {
|
||||
if ! kubectl -n "$NAMESPACE" get cluster "$CNPG_CLUSTER_NAME" >/dev/null 2>&1; then
|
||||
echo ""
|
||||
@ -1287,6 +1302,151 @@ apply_prole_manifest_file() {
|
||||
return 1
|
||||
}
|
||||
|
||||
_prole_k3s_registry_host_for_cache() {
|
||||
# Best-effort host:port for the k3s registry, used as an optional cache source in k3d mode.
|
||||
# Intentionally avoids k3d registry names and localhost-ish endpoints.
|
||||
local r="${PROLE_K3S_REGISTRY:-${K3S_REGISTRY_HOST:-${LOCAL_REGISTRY_INTERNAL:-${LOCAL_REGISTRY:-}}}}"
|
||||
|
||||
r="${r#http://}"
|
||||
r="${r#https://}"
|
||||
|
||||
case "${r}" in
|
||||
"")
|
||||
r="myrddin.prole.org:5000"
|
||||
;;
|
||||
localhost:5000|127.0.0.1:5000|*.localhost|*.localhost:5000)
|
||||
r="myrddin.prole.org:5000"
|
||||
;;
|
||||
k3d-*|*/k3d-*)
|
||||
r="myrddin.prole.org:5000"
|
||||
;;
|
||||
esac
|
||||
|
||||
printf '%s' "$r"
|
||||
}
|
||||
|
||||
_docker_build_knoe_db_image() {
|
||||
# Build the knoe-db image with BuildKit and optional cache source.
|
||||
# Args: <tag> <context_dir> [cache_ref]
|
||||
local tag="$1"
|
||||
local context_dir="$2"
|
||||
local cache_ref="${3:-}"
|
||||
|
||||
local ssh_args=()
|
||||
if [[ -n "${SSH_AUTH_SOCK:-}" ]]; then
|
||||
ssh_args+=(--ssh default)
|
||||
fi
|
||||
|
||||
if docker buildx version >/dev/null 2>&1; then
|
||||
# Prefer an isolated docker-container builder to avoid host snapshot/cache corruption.
|
||||
local builder_name="${PROLE_BUILDX_BUILDER:-prole-buildkit}"
|
||||
if ! docker buildx inspect "$builder_name" >/dev/null 2>&1; then
|
||||
docker buildx create --name "$builder_name" --driver docker-container --use >/dev/null 2>&1 || true
|
||||
else
|
||||
docker buildx use "$builder_name" >/dev/null 2>&1 || true
|
||||
fi
|
||||
|
||||
local cache_args=()
|
||||
if [[ -n "$cache_ref" ]]; then
|
||||
cache_args+=(--cache-from "type=registry,ref=${cache_ref}")
|
||||
fi
|
||||
|
||||
if docker buildx build \
|
||||
--pull \
|
||||
--tag "$tag" \
|
||||
--load \
|
||||
"${ssh_args[@]}" \
|
||||
"${cache_args[@]}" \
|
||||
"$context_dir"; then
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# Fallback to docker build (still BuildKit-enabled); cache-from here only works if the cache image is present locally.
|
||||
local cache_from_args=()
|
||||
if [[ -n "$cache_ref" ]]; then
|
||||
docker pull "$cache_ref" >/dev/null 2>&1 || true
|
||||
cache_from_args+=(--cache-from "$cache_ref")
|
||||
fi
|
||||
|
||||
DOCKER_BUILDKIT=1 docker build \
|
||||
--pull \
|
||||
"${ssh_args[@]}" \
|
||||
"${cache_from_args[@]}" \
|
||||
-t "$tag" \
|
||||
"$context_dir"
|
||||
}
|
||||
|
||||
# Import a Docker image directly to each k3s node via SSH + 'k3s ctr images import'.
|
||||
# Used as a last-resort fallback when the in-cluster registry is unreachable and
|
||||
# the kubectl port-forward push also fails (e.g. registry service not yet deployed).
|
||||
# Respects optional PROLE_SSH_KEY (path to private key) and K3S_SSH_USER env vars.
|
||||
_import_image_to_k3s_nodes() {
|
||||
local image="$1"
|
||||
local ssh_user="${K3S_SSH_USER:-${ANSIBLE_USER:-ansible}}"
|
||||
local ssh_key_args=()
|
||||
# Auto-detect the SSH key: explicit override → ~/.ssh/id_ed25519_ansible (ansible user key)
|
||||
# → prole ssh-keys dir → ssh-agent default.
|
||||
local _auto_key_ansible="${HOME}/.ssh/id_ed25519_ansible"
|
||||
local _auto_key_prole="${PROLE_HOME:-$SCRIPT_DIR/..}/ssh-keys/id_prole_ed25519"
|
||||
local _ssh_key="${PROLE_SSH_KEY:-${K3S_SSH_KEY:-}}"
|
||||
if [[ -z "$_ssh_key" && -f "$_auto_key_ansible" ]]; then
|
||||
_ssh_key="$_auto_key_ansible"
|
||||
elif [[ -z "$_ssh_key" && -f "$_auto_key_prole" ]]; then
|
||||
_ssh_key="$_auto_key_prole"
|
||||
fi
|
||||
if [[ -n "$_ssh_key" && -f "$_ssh_key" ]]; then
|
||||
ssh_key_args=(-i "$_ssh_key")
|
||||
fi
|
||||
|
||||
local nodes=()
|
||||
mapfile -t nodes < <(kubectl get nodes \
|
||||
-o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}' 2>/dev/null || true)
|
||||
if [[ ${#nodes[@]} -eq 0 ]]; then
|
||||
echo " WARN: No k3s nodes found for direct image import." >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
local tar_file
|
||||
tar_file=$(mktemp /tmp/prole-img-XXXXXX.tar)
|
||||
echo " Saving image '$image' for k3s node import ..."
|
||||
if ! docker save "$image" -o "$tar_file" 2>/dev/null; then
|
||||
echo " WARN: docker save failed for '$image'." >&2
|
||||
rm -f "$tar_file" 2>/dev/null || true
|
||||
return 1
|
||||
fi
|
||||
|
||||
local imported=0
|
||||
for node in "${nodes[@]}"; do
|
||||
# Skip nodes that already have the image in k3s containerd.
|
||||
if ssh -o StrictHostKeyChecking=no -o BatchMode=yes -o ConnectTimeout=10 \
|
||||
"${ssh_key_args[@]}" "${ssh_user}@${node}" \
|
||||
"sudo k3s ctr images ls 2>/dev/null | grep -qF '${plain_image}'" 2>/dev/null; then
|
||||
echo " ✓ Image already in k3s containerd on '$node'; skipping import."
|
||||
imported=$((imported + 1))
|
||||
continue
|
||||
fi
|
||||
echo " Importing '$image' to k3s node '$node' ..."
|
||||
if ssh -o StrictHostKeyChecking=no -o BatchMode=yes -o ConnectTimeout=30 \
|
||||
-o ServerAliveInterval=30 -o ServerAliveCountMax=10 \
|
||||
"${ssh_key_args[@]}" "${ssh_user}@${node}" \
|
||||
"sudo k3s ctr images import -" < "$tar_file" >/dev/null 2>&1; then
|
||||
echo " ✓ Image imported on node '$node'."
|
||||
imported=$((imported + 1))
|
||||
else
|
||||
echo " WARN: Failed to import image on node '$node'; skipping." >&2
|
||||
fi
|
||||
done
|
||||
|
||||
rm -f "$tar_file" 2>/dev/null || true
|
||||
if [[ $imported -eq 0 ]]; then
|
||||
echo " WARN: Image import failed on all k3s nodes." >&2
|
||||
return 1
|
||||
fi
|
||||
echo " ✓ Image '$image' imported on $imported/${#nodes[@]} k3s node(s)."
|
||||
return 0
|
||||
}
|
||||
|
||||
_push_to_k3s_registry() {
|
||||
local image="$1"
|
||||
local push_host="${LOCAL_REGISTRY:-${LOCAL_REGISTRY_INTERNAL:-myrddin.prole.org:5000}}"
|
||||
@ -1434,6 +1594,7 @@ _ensure_prole_db_image() {
|
||||
local prole_db_dir="${PROLE_DB_BUILD_CONTEXT_DIR:-${runtime_home}/build/${mode_key}/knoe-db}"
|
||||
local source_db_dir="${PROLE_HOME:-$SCRIPT_DIR/..}/prole-db"
|
||||
local plain_image="${image##*/}" # e.g. knoe-db:18-088
|
||||
local k3s_cache_ref=""
|
||||
|
||||
if [[ ! -f "$prole_db_dir/Dockerfile" ]]; then
|
||||
if [[ -d "$source_db_dir" ]]; then
|
||||
@ -1446,6 +1607,32 @@ _ensure_prole_db_image() {
|
||||
|
||||
if [[ "${PROLE_MODE:-}" == "k3s" ]]; then
|
||||
echo "Pre-flight: ensuring image '$image' is available in k3s registry/import path ..."
|
||||
# Step 1 (k3s): if the CNPG cluster already exists and is running with this exact image
|
||||
# the image is already present in k3s containerd on the nodes — skip push entirely.
|
||||
local _k3s_current_image _k3s_ready
|
||||
_k3s_current_image=$(kubectl get cluster "${CNPG_CLUSTER_NAME:-prole-db}" \
|
||||
-n "${CNPG_NAMESPACE:-${NAMESPACE:-prole-db}}" \
|
||||
-o jsonpath='{.spec.imageName}' 2>/dev/null || true)
|
||||
_k3s_ready=$(kubectl get cluster "${CNPG_CLUSTER_NAME:-prole-db}" \
|
||||
-n "${CNPG_NAMESPACE:-${NAMESPACE:-prole-db}}" \
|
||||
-o jsonpath='{.status.readyInstances}' 2>/dev/null || true)
|
||||
if [[ "$_k3s_current_image" == "$image" && "${_k3s_ready:-0}" -gt 0 ]]; then
|
||||
echo " ✓ CNPG cluster already running with image '$image'; no push needed."
|
||||
return 0
|
||||
fi
|
||||
# Step 1b: check if image already exists in the registry via a quick manifest HEAD request.
|
||||
local _reg_host="${LOCAL_REGISTRY:-${LOCAL_REGISTRY_INTERNAL:-myrddin.prole.org:5000}}"
|
||||
_reg_host="${_reg_host#http://}"; _reg_host="${_reg_host#https://}"
|
||||
local _img_name="${plain_image%%:*}" _img_tag="${plain_image##*:}"
|
||||
if command -v curl >/dev/null 2>&1; then
|
||||
if curl -k -fsS -m 3 \
|
||||
"https://${_reg_host}/v2/${_img_name}/manifests/${_img_tag}" >/dev/null 2>&1 \
|
||||
|| curl -fsS -m 3 \
|
||||
"http://${_reg_host}/v2/${_img_name}/manifests/${_img_tag}" >/dev/null 2>&1; then
|
||||
echo " ✓ Image '$image' already present in registry at '${_reg_host}'; no push needed."
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
else
|
||||
# Auto-detect active k3d cluster name
|
||||
local cluster_name="${K3D_CLUSTER_NAME:-}"
|
||||
@ -1454,6 +1641,13 @@ _ensure_prole_db_image() {
|
||||
fi
|
||||
cluster_name="${cluster_name:-knoe-dev-cluster}"
|
||||
|
||||
# In k3d mode, optionally consult the k3s registry as a cache/source of truth before building.
|
||||
local k3s_host
|
||||
k3s_host=$(_prole_k3s_registry_host_for_cache)
|
||||
if [[ -n "${k3s_host:-}" ]]; then
|
||||
k3s_cache_ref="${k3s_host}/${plain_image}"
|
||||
fi
|
||||
|
||||
echo "Pre-flight: verifying image '$image' is available in k3d cluster '$cluster_name' ..."
|
||||
|
||||
# Step 1: check if already present in k3d containerd with matching digest
|
||||
@ -1526,6 +1720,18 @@ _ensure_prole_db_image() {
|
||||
return $?
|
||||
fi
|
||||
|
||||
# Step 3b (k3d only): try to reuse a previously-built image from the k3s registry.
|
||||
# If present, retag it to the desired image name and push/import into the k3d cluster.
|
||||
if [[ "${PROLE_MODE:-}" == "k3d" && -n "${k3s_cache_ref:-}" && "${k3s_cache_ref}" != "${image}" ]]; then
|
||||
if docker image inspect "$k3s_cache_ref" >/dev/null 2>&1 || docker pull "$k3s_cache_ref" >/dev/null 2>&1; then
|
||||
echo " ✓ Found '$plain_image' in k3s registry (${k3s_cache_ref}); re-tagging for k3d as '$image' ..."
|
||||
docker tag "$k3s_cache_ref" "$image" 2>/dev/null || true
|
||||
_push_to_k3d_registry "$image" "$cluster_name"
|
||||
return $?
|
||||
fi
|
||||
echo " (cache) '$plain_image' not present in k3s registry (${k3s_cache_ref}); building locally ..."
|
||||
fi
|
||||
|
||||
# Step 4: image not found anywhere — build from source then push + import
|
||||
if [[ ! -f "$prole_db_dir/Dockerfile" ]]; then
|
||||
echo "ERROR: Dockerfile not found in '$prole_db_dir'; cannot build knoe-db image." >&2
|
||||
@ -1537,7 +1743,7 @@ _ensure_prole_db_image() {
|
||||
echo " Image '$image' not found in k3d, Docker daemon, or docker-import dir."
|
||||
fi
|
||||
echo " Building knoe-db image from '$prole_db_dir' ..."
|
||||
if ! docker build -t "$plain_image" "$prole_db_dir"; then
|
||||
if ! _docker_build_knoe_db_image "$plain_image" "$prole_db_dir" "${k3s_cache_ref:-}"; then
|
||||
echo "ERROR: docker build failed for image '$plain_image'." >&2
|
||||
return 1
|
||||
fi
|
||||
@ -2538,14 +2744,14 @@ restore_cnpg_cluster() {
|
||||
}
|
||||
|
||||
recycle_released_prole_iscsi_pvs() {
|
||||
# StorageClass `prole-iscsi` uses `Retain` PV reclaim policy. After a CNPG reset, PVs can remain
|
||||
# StorageClass `synology-iscsi` uses `Retain` PV reclaim policy. After a CNPG reset, PVs can remain
|
||||
# in `Released` with a stale `claimRef`, which prevents new PVCs (same names) from binding.
|
||||
# In that case, CNPG init jobs remain `Pending` with "didn't find available persistent volumes".
|
||||
echo "Recycling Released prole-iscsi PVs (clearing stale claimRefs) for namespace '$NAMESPACE' ..."
|
||||
echo "Recycling Released synology-iscsi PVs (clearing stale claimRefs) for namespace '$NAMESPACE' ..."
|
||||
local pvs
|
||||
pvs=$(kubectl get pv -o json \
|
||||
| jq -r --arg ns "$NAMESPACE" '.items[]
|
||||
| select(.spec.storageClassName == "prole-iscsi")
|
||||
| select(.spec.storageClassName == "synology-iscsi")
|
||||
| select(.status.phase == "Released")
|
||||
| select((.spec.claimRef.namespace // "") == $ns)
|
||||
| .metadata.name' 2>/dev/null || true)
|
||||
@ -2827,8 +3033,22 @@ get_latest_cnpg_version() {
|
||||
|
||||
initialize() {
|
||||
ensure_tools
|
||||
ensure_namespace
|
||||
require_namespace_configured
|
||||
wait_for_apiserver_ready 180
|
||||
|
||||
local desired_image current_image
|
||||
desired_image=$(_desired_cnpg_image)
|
||||
current_image=$(_cnpg_current_image_name)
|
||||
|
||||
if [[ -n "$current_image" && "$current_image" == "$desired_image" ]]; then
|
||||
echo "✓ Namespace '$NAMESPACE' already contains CNPG cluster '$CNPG_CLUSTER_NAME' using image '$desired_image'; no re-deploy needed."
|
||||
echo " (Use 'update'/'reload' if you intended to re-apply manifests.)"
|
||||
return 0
|
||||
fi
|
||||
|
||||
_enforce_namespace_image_policy "$desired_image" || return 1
|
||||
|
||||
ensure_namespace
|
||||
attempt_backup_if_active
|
||||
ensure_cnpg_operator
|
||||
pin_cnpg_controller
|
||||
@ -2906,6 +3126,21 @@ update_reload() {
|
||||
|
||||
deploy_cluster() {
|
||||
ensure_tools
|
||||
require_namespace_configured
|
||||
|
||||
wait_for_apiserver_ready 180
|
||||
|
||||
local image current_image_before
|
||||
image=$(_desired_cnpg_image)
|
||||
current_image_before=$(_cnpg_current_image_name)
|
||||
|
||||
if [[ -n "$current_image_before" && "$current_image_before" == "$image" ]]; then
|
||||
echo "✓ Namespace '$NAMESPACE' already contains CNPG cluster '$CNPG_CLUSTER_NAME' using image '$image'; skipping deploy."
|
||||
return 0
|
||||
fi
|
||||
|
||||
_enforce_namespace_image_policy "$image" || return 1
|
||||
|
||||
ensure_namespace
|
||||
ensure_cnpg_operator
|
||||
pin_cnpg_controller
|
||||
@ -2913,13 +3148,6 @@ deploy_cluster() {
|
||||
|
||||
ensure_prole_protected_storage
|
||||
|
||||
local image
|
||||
if [[ "$VERSION" == "latest" || -z "$VERSION" ]]; then
|
||||
image=$(get_latest_image)
|
||||
else
|
||||
image="knoe-db:$VERSION"
|
||||
fi
|
||||
image=$(resolve_cnpg_image "$image")
|
||||
sync_manifest_image "$image"
|
||||
|
||||
generate_tls_if_missing
|
||||
@ -2949,11 +3177,20 @@ deploy_cluster() {
|
||||
kubectl cnpg restart "$CNPG_CLUSTER_NAME" -n "$NAMESPACE" || true
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "${PROLE_UPGRADE:-0}" == "1" && -n "$current_image_before" && "$current_image_before" != "$image" ]]; then
|
||||
echo "Upgrade requested; forcing CNPG rollout to ensure pods pick up image '$image' ..."
|
||||
if kubectl cnpg version >/dev/null 2>&1; then
|
||||
kubectl cnpg restart "$CNPG_CLUSTER_NAME" -n "$NAMESPACE" || true
|
||||
else
|
||||
force_rollout || true
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
preflight_image() {
|
||||
ensure_tools
|
||||
ensure_namespace
|
||||
require_namespace_configured
|
||||
_ensure_prole_db_image
|
||||
}
|
||||
|
||||
|
||||
@ -60,7 +60,7 @@ else
|
||||
fi
|
||||
|
||||
GARAGE_FILES=(
|
||||
"$GARAGE_MANIFEST_DIR/storageclass-prole-iscsi.yaml"
|
||||
"$GARAGE_MANIFEST_DIR/storageclass-synology-iscsi.yaml"
|
||||
"$GARAGE_MANIFEST_DIR/iscsi-pvs.yaml"
|
||||
"$GARAGE_MANIFEST_DIR/garage-configmap.yaml"
|
||||
"$GARAGE_MANIFEST_DIR/garage-statefulset.yaml"
|
||||
@ -133,7 +133,7 @@ k3d_cleanup_pending_pvc() {
|
||||
return 0
|
||||
fi
|
||||
selector=$(kubectl get pvc data-garage-0 -n "$NAMESPACE" -o jsonpath='{.spec.selector}' 2>/dev/null || true)
|
||||
if printf '%s' "$selector" | grep -q "prole.storage/"; then
|
||||
if printf '%s' "$selector" | grep -q "synology.storage/"; then
|
||||
echo "Removing pending Garage PVC with selector for k3d local-path ..."
|
||||
kubectl delete statefulset "$GARAGE_NAME" -n "$NAMESPACE" --ignore-not-found >/dev/null 2>&1 || true
|
||||
kubectl delete pvc data-garage-0 -n "$NAMESPACE" --ignore-not-found >/dev/null 2>&1 || true
|
||||
@ -160,6 +160,24 @@ apply_manifests() {
|
||||
continue
|
||||
fi
|
||||
if [[ $diff_rc -ne 1 ]]; then
|
||||
# For immutable StatefulSet VolumeClaimTemplates, kubectl diff itself returns an
|
||||
# error (diff_rc != 1 but contains the immutable spec error). Handle it here.
|
||||
if [[ "$(basename "$f")" == "garage-statefulset.yaml" ]] \
|
||||
&& echo "$diff_out" | grep -q "updates to statefulset spec"; then
|
||||
echo "WARN: Garage StatefulSet VolumeClaimTemplates changed (diff-stage); deleting and recreating ..."
|
||||
kubectl delete statefulset "$GARAGE_NAME" -n "$NAMESPACE" --ignore-not-found >/dev/null 2>&1 || true
|
||||
local _pvc_sc_d
|
||||
_pvc_sc_d=$(kubectl get pvc "data-garage-0" -n "$NAMESPACE" \
|
||||
-o jsonpath='{.spec.storageClassName}' 2>/dev/null || true)
|
||||
if [[ -n "$_pvc_sc_d" && "$_pvc_sc_d" != "synology-iscsi" ]]; then
|
||||
echo " Removing stale PVC 'data-garage-0' (storageClass: $_pvc_sc_d) ..."
|
||||
kubectl delete pvc "data-garage-0" -n "$NAMESPACE" --ignore-not-found >/dev/null 2>&1 || true
|
||||
fi
|
||||
printf '%s' "$rendered" | kubectl apply --validate=false -n "$NAMESPACE" -f -
|
||||
GARAGE_APPLY_CHANGED=1
|
||||
GARAGE_STATEFULSET_CHANGED=1
|
||||
continue
|
||||
fi
|
||||
echo "$diff_out" >&2
|
||||
exit 1
|
||||
fi
|
||||
@ -175,6 +193,23 @@ apply_manifests() {
|
||||
&& echo "$output" | grep -q "updates to statefulset spec"; then
|
||||
echo "WARN: Garage StatefulSet immutable in k3d; skipping apply."
|
||||
continue
|
||||
elif [[ "$(basename "$f")" == "garage-statefulset.yaml" ]] \
|
||||
&& echo "$output" | grep -q "updates to statefulset spec"; then
|
||||
# VolumeClaimTemplates are immutable; delete the StatefulSet (PVCs are orphaned/preserved)
|
||||
# and recreate so the new storageClass name takes effect.
|
||||
echo "WARN: Garage StatefulSet VolumeClaimTemplates changed; deleting and recreating ..."
|
||||
kubectl delete statefulset "$GARAGE_NAME" -n "$NAMESPACE" --ignore-not-found >/dev/null 2>&1 || true
|
||||
local _pvc_sc
|
||||
_pvc_sc=$(kubectl get pvc "data-garage-0" -n "$NAMESPACE" \
|
||||
-o jsonpath='{.spec.storageClassName}' 2>/dev/null || true)
|
||||
if [[ -n "$_pvc_sc" && "$_pvc_sc" != "synology-iscsi" ]]; then
|
||||
echo " Removing stale PVC 'data-garage-0' (storageClass: $_pvc_sc) ..."
|
||||
kubectl delete pvc "data-garage-0" -n "$NAMESPACE" --ignore-not-found >/dev/null 2>&1 || true
|
||||
fi
|
||||
printf '%s' "$rendered" | kubectl apply --validate=false -n "$NAMESPACE" -f -
|
||||
GARAGE_APPLY_CHANGED=1
|
||||
GARAGE_STATEFULSET_CHANGED=1
|
||||
continue
|
||||
fi
|
||||
echo "$output" >&2
|
||||
exit 1
|
||||
@ -283,7 +318,7 @@ dump_debug() {
|
||||
}
|
||||
|
||||
recycle_released_prole_iscsi_pv_for_pvc() {
|
||||
# StorageClass `prole-iscsi` uses `Retain` PV reclaim policy. On restart, PVs can remain
|
||||
# StorageClass `synology-iscsi` uses `Retain` PV reclaim policy. On restart, PVs can remain
|
||||
# in `Released` with a stale `claimRef`, which prevents a same-named PVC from binding.
|
||||
local ns="$1"
|
||||
local pvc="$2"
|
||||
@ -301,7 +336,7 @@ recycle_released_prole_iscsi_pv_for_pvc() {
|
||||
|
||||
local pv sc rp phase claim_ns claim_name claim_uid
|
||||
while IFS=$'\t' read -r pv sc rp phase claim_ns claim_name claim_uid; do
|
||||
[[ "$sc" == "prole-iscsi" ]] || continue
|
||||
[[ "$sc" == "synology-iscsi" ]] || continue
|
||||
[[ "$rp" == "Retain" ]] || continue
|
||||
[[ "$phase" == "Released" ]] || continue
|
||||
[[ "$claim_ns" == "$ns" ]] || continue
|
||||
@ -322,7 +357,7 @@ wait_ready() {
|
||||
|
||||
local initial_timeout="${PVC_REPAIR_WAIT_TIMEOUT:-30s}"
|
||||
if ! kubectl rollout status statefulset/$GARAGE_NAME -n "$NAMESPACE" --timeout="$initial_timeout"; then
|
||||
echo "WARN: Garage not ready after $initial_timeout; checking for Released prole-iscsi PVs with stale claimRefs ..." >&2
|
||||
echo "WARN: Garage not ready after $initial_timeout; checking for Released synology-iscsi PVs with stale claimRefs ..." >&2
|
||||
recycle_released_prole_iscsi_pv_for_pvc "$NAMESPACE" "data-garage-0" || true
|
||||
fi
|
||||
|
||||
|
||||
@ -313,8 +313,8 @@ kind: PersistentVolume
|
||||
metadata:
|
||||
name: merlin-local-iscsi-${volume_id}-prometheus
|
||||
labels:
|
||||
prole.storage/role: prometheus
|
||||
prole.storage/volume: ${volume_id}
|
||||
synology.storage/role: prometheus
|
||||
synology.storage/volume: ${volume_id}
|
||||
spec:
|
||||
capacity:
|
||||
storage: 30Gi
|
||||
@ -339,8 +339,8 @@ kind: PersistentVolume
|
||||
metadata:
|
||||
name: merlin-local-iscsi-${volume_id}-alertmanager
|
||||
labels:
|
||||
prole.storage/role: alertmanager
|
||||
prole.storage/volume: ${volume_id}
|
||||
synology.storage/role: alertmanager
|
||||
synology.storage/volume: ${volume_id}
|
||||
spec:
|
||||
capacity:
|
||||
storage: 5Gi
|
||||
@ -365,8 +365,8 @@ kind: PersistentVolume
|
||||
metadata:
|
||||
name: merlin-local-iscsi-${volume_id}-grafana
|
||||
labels:
|
||||
prole.storage/role: grafana
|
||||
prole.storage/volume: ${volume_id}
|
||||
synology.storage/role: grafana
|
||||
synology.storage/volume: ${volume_id}
|
||||
spec:
|
||||
capacity:
|
||||
storage: 10Gi
|
||||
|
||||
@ -423,7 +423,7 @@ iscsi_pv_names_from_manifest() {
|
||||
awk '
|
||||
$1=="kind:" && $2=="PersistentVolume" {in_pv=1; next}
|
||||
in_pv && $1=="name:" {print $2; in_pv=0}
|
||||
' "$manifest" | sed 's/["\r]//g' | grep -v '^$' || true
|
||||
' "$manifest" | tr -d $'"\r' | grep -v '^$' || true
|
||||
}
|
||||
|
||||
desired_pv_path_from_manifest() {
|
||||
@ -435,7 +435,7 @@ desired_pv_path_from_manifest() {
|
||||
$1=="kind:" && $2=="PersistentVolume" {is_pv=1}
|
||||
is_pv && $1=="name:" && $2==pv {hit=1}
|
||||
hit && $1=="path:" {print $2; exit}
|
||||
' "$manifest" | sed 's/["\r]//g' | head -1 || true
|
||||
' "$manifest" | tr -d $'"\r' | head -1 || true
|
||||
}
|
||||
|
||||
desired_pv_node_from_manifest() {
|
||||
@ -448,7 +448,7 @@ desired_pv_node_from_manifest() {
|
||||
is_pv && $1=="name:" && $2==pv {hit=1}
|
||||
hit && $1=="values:" {in_values=1; next}
|
||||
in_values && $1=="-" {print $2; exit}
|
||||
' "$manifest" | sed 's/["\r]//g' | head -1 || true
|
||||
' "$manifest" | tr -d $'"\r' | head -1 || true
|
||||
}
|
||||
|
||||
ensure_iscsi_pvs() {
|
||||
@ -503,9 +503,9 @@ apply_k8s() {
|
||||
fi
|
||||
if [[ "$use_statefulset" == "1" ]]; then
|
||||
# Ensure storage class and PVs exist for k3s
|
||||
if [[ -f "$SCRIPT_DIR/../k8s/prole/storageclass-prole-iscsi.yaml" ]]; then
|
||||
echo "Applying StorageClass 'prole-iscsi' ..."
|
||||
kubectl apply -f "$SCRIPT_DIR/../k8s/prole/storageclass-prole-iscsi.yaml"
|
||||
if [[ -f "$SCRIPT_DIR/../k8s/prole/storageclass-synology-iscsi.yaml" ]]; then
|
||||
echo "Applying StorageClass 'synology-iscsi' ..."
|
||||
kubectl apply -f "$SCRIPT_DIR/../k8s/prole/storageclass-synology-iscsi.yaml"
|
||||
fi
|
||||
if [[ -f "$SCRIPT_DIR/../k8s/prole/iscsi-pvs.yaml" ]]; then
|
||||
ensure_iscsi_pvs "$SCRIPT_DIR/../k8s/prole/iscsi-pvs.yaml"
|
||||
@ -518,6 +518,20 @@ apply_k8s() {
|
||||
else
|
||||
if [[ "${PROLE_MODE:-}" == "k3d" && "$output" == *"updates to statefulset spec"* ]]; then
|
||||
echo "WARN: OpenBao StatefulSet immutable in k3d; skipping apply."
|
||||
elif [[ "$output" == *"updates to statefulset spec"* ]]; then
|
||||
# VolumeClaimTemplates are immutable; delete the StatefulSet (PVCs are orphaned/preserved)
|
||||
# and recreate so the new storageClass name takes effect.
|
||||
echo "WARN: OpenBao StatefulSet VolumeClaimTemplates changed; deleting and recreating ..."
|
||||
kubectl delete statefulset "$OPENBAO_NAME" -n "$OPENBAO_RESOURCE_NAMESPACE" --ignore-not-found >/dev/null 2>&1 || true
|
||||
local _pvc_sc
|
||||
_pvc_sc=$(kubectl get pvc "data-openbao-0" -n "$OPENBAO_RESOURCE_NAMESPACE" \
|
||||
-o jsonpath='{.spec.storageClassName}' 2>/dev/null || true)
|
||||
if [[ -n "$_pvc_sc" && "$_pvc_sc" != "synology-iscsi" ]]; then
|
||||
echo " Removing stale PVC 'data-openbao-0' (storageClass: $_pvc_sc) ..."
|
||||
kubectl delete pvc "data-openbao-0" -n "$OPENBAO_RESOURCE_NAMESPACE" --ignore-not-found >/dev/null 2>&1 || true
|
||||
fi
|
||||
prole_render_manifest "$SCRIPT_DIR/../k8s/prole/openbao-statefulset.yaml" \
|
||||
| kubectl apply --validate=false -n "$OPENBAO_RESOURCE_NAMESPACE" -f -
|
||||
else
|
||||
echo "$output" >&2
|
||||
return 1
|
||||
@ -554,7 +568,7 @@ k3d_cleanup_pending_openbao_pvc() {
|
||||
return 0
|
||||
fi
|
||||
selector=$(kubectl get pvc data-openbao-0 -n "$OPENBAO_RESOURCE_NAMESPACE" -o jsonpath='{.spec.selector}' 2>/dev/null || true)
|
||||
if printf '%s' "$selector" | grep -q "prole.storage/"; then
|
||||
if printf '%s' "$selector" | grep -q "synology.storage/"; then
|
||||
echo "Removing pending OpenBao PVC with selector for k3d local-path ..."
|
||||
kubectl delete statefulset "$OPENBAO_NAME" -n "$OPENBAO_RESOURCE_NAMESPACE" --ignore-not-found >/dev/null 2>&1 || true
|
||||
kubectl delete pvc data-openbao-0 -n "$OPENBAO_RESOURCE_NAMESPACE" --ignore-not-found >/dev/null 2>&1 || true
|
||||
@ -562,7 +576,7 @@ k3d_cleanup_pending_openbao_pvc() {
|
||||
}
|
||||
|
||||
recycle_released_prole_iscsi_pv_for_pvc() {
|
||||
# StorageClass `prole-iscsi` uses `Retain` PV reclaim policy. On restart, PVs can remain
|
||||
# StorageClass `synology-iscsi` uses `Retain` PV reclaim policy. On restart, PVs can remain
|
||||
# in `Released` with a stale `claimRef`, which prevents a same-named PVC from binding.
|
||||
local ns="$1"
|
||||
local pvc="$2"
|
||||
@ -580,7 +594,7 @@ recycle_released_prole_iscsi_pv_for_pvc() {
|
||||
|
||||
local pv sc rp phase claim_ns claim_name claim_uid
|
||||
while IFS=$'\t' read -r pv sc rp phase claim_ns claim_name claim_uid; do
|
||||
[[ "$sc" == "prole-iscsi" ]] || continue
|
||||
[[ "$sc" == "synology-iscsi" ]] || continue
|
||||
[[ "$rp" == "Retain" ]] || continue
|
||||
[[ "$phase" == "Released" ]] || continue
|
||||
[[ "$claim_ns" == "$ns" ]] || continue
|
||||
@ -621,13 +635,13 @@ wait_for_openbao() {
|
||||
echo "Waiting for OpenBao to become ready in namespace '$wait_ns' ..."
|
||||
if kubectl get statefulset/$OPENBAO_NAME -n "$wait_ns" >/dev/null 2>&1; then
|
||||
if ! kubectl rollout status statefulset/$OPENBAO_NAME -n "$wait_ns" --timeout="$initial_timeout"; then
|
||||
echo "WARN: OpenBao not ready after $initial_timeout; checking for Released prole-iscsi PVs with stale claimRefs ..." >&2
|
||||
echo "WARN: OpenBao not ready after $initial_timeout; checking for Released synology-iscsi PVs with stale claimRefs ..." >&2
|
||||
recycle_released_prole_iscsi_pv_for_pvc "$wait_ns" "data-openbao-0" || true
|
||||
fi
|
||||
kubectl rollout status statefulset/$OPENBAO_NAME -n "$wait_ns" --timeout=${ROLLOUT_TIMEOUT:-300s}
|
||||
else
|
||||
if ! kubectl rollout status deploy/$OPENBAO_NAME -n "$wait_ns" --timeout="$initial_timeout"; then
|
||||
echo "WARN: OpenBao not ready after $initial_timeout; checking for Released prole-iscsi PVs with stale claimRefs ..." >&2
|
||||
echo "WARN: OpenBao not ready after $initial_timeout; checking for Released synology-iscsi PVs with stale claimRefs ..." >&2
|
||||
recycle_released_prole_iscsi_pv_for_pvc "$wait_ns" "data-openbao-0" || true
|
||||
fi
|
||||
kubectl rollout status deploy/$OPENBAO_NAME -n "$wait_ns" --timeout=${ROLLOUT_TIMEOUT:-300s}
|
||||
|
||||
@ -246,7 +246,7 @@ deploy_service_layer() {
|
||||
SERVICE_NAMESPACE="$ns" PROLE_KDC_NAMESPACE="$ns" \
|
||||
"$SCRIPT_DIR/init_kdc.sh" "$kdc_action" || rc=$?
|
||||
else
|
||||
log "[INFO] Kerberos enabled: skipping standalone KDC deploy (KDC runs as `kdc` sidecar in `prole-auth`)."
|
||||
log "[INFO] Kerberos enabled: skipping standalone KDC deploy (KDC runs as 'kdc' sidecar in 'prole-auth')."
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
@ -42,8 +42,17 @@ common_core_preparse_config() {
|
||||
fi
|
||||
local cfg_dir
|
||||
cfg_dir=$(cd "$(dirname "$COMMON_CORE_CONFIG_PATH")" && pwd)
|
||||
PROLE_CONF="$cfg_dir"
|
||||
export PROLE_CONF
|
||||
# Preserve an already-set PROLE_CONF when it is a more-specific env subdir of
|
||||
# cfg_dir (e.g. conf/service/ vs the injected-default conf/). This allows the
|
||||
# parent shell / Python milestone to pass the correct env-specific conf dir and
|
||||
# have it survive even when init scripts inject a generic fallback -c path.
|
||||
local _current_conf="${PROLE_CONF:-}"
|
||||
if [[ -n "$_current_conf" && "$_current_conf" == "${cfg_dir}/"* && -f "$_current_conf/prole.cfg" ]]; then
|
||||
: # keep inherited PROLE_CONF — it is already more specific than cfg_dir
|
||||
else
|
||||
PROLE_CONF="$cfg_dir"
|
||||
export PROLE_CONF
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
@ -518,7 +518,7 @@ fi
|
||||
|
||||
# Safety: prole.cfg must override any pre-set PROLE_MODE from the environment.
|
||||
# Otherwise a leaked PROLE_MODE=k3d can trigger k3d-only manifest stripping (e.g., removing
|
||||
# `storageClassName: prole-iscsi`) while targeting a k3s cluster.
|
||||
# `storageClassName: synology-iscsi`) while targeting a k3s cluster.
|
||||
_prole_cfg_mode_hint=""
|
||||
if [[ -n "${prole_mode:-}" ]]; then
|
||||
_prole_cfg_mode_hint=$(prole_normalize_mode "$prole_mode")
|
||||
|
||||
@ -65,7 +65,7 @@ def _strip_blocks(text: str) -> str:
|
||||
break
|
||||
block_lines.append(next_line)
|
||||
j += 1
|
||||
if any("prole.storage/" in bl for bl in block_lines):
|
||||
if any("synology.storage/" in bl for bl in block_lines):
|
||||
i = j
|
||||
continue
|
||||
out.extend(block_lines)
|
||||
@ -78,7 +78,7 @@ def _strip_blocks(text: str) -> str:
|
||||
i += 1
|
||||
continue
|
||||
|
||||
if stripped.startswith("storageClassName:") and "prole-iscsi" in stripped:
|
||||
if stripped.startswith("storageClassName:") and "synology-iscsi" in stripped:
|
||||
i += 1
|
||||
continue
|
||||
|
||||
|
||||
@ -71,8 +71,8 @@ spec:
|
||||
resources:
|
||||
requests:
|
||||
storage: 29Gi
|
||||
storageClassName: prole-iscsi
|
||||
storageClassName: synology-iscsi
|
||||
selector:
|
||||
matchLabels:
|
||||
prole.storage/role: garage
|
||||
prole.storage/volume: d001
|
||||
synology.storage/role: garage
|
||||
synology.storage/volume: d001
|
||||
|
||||
@ -1,17 +1,17 @@
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: prole-iscsi-d001-data
|
||||
name: synology-iscsi-d001-data
|
||||
labels:
|
||||
prole.storage/role: data
|
||||
prole.storage/volume: d001
|
||||
synology.storage/role: data
|
||||
synology.storage/volume: d001
|
||||
spec:
|
||||
capacity:
|
||||
storage: 29Gi
|
||||
volumeMode: Filesystem
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
storageClassName: prole-iscsi
|
||||
storageClassName: synology-iscsi
|
||||
persistentVolumeReclaimPolicy: Retain
|
||||
local:
|
||||
path: /synology/d001/data
|
||||
@ -27,17 +27,17 @@ spec:
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: prole-iscsi-d001-wal
|
||||
name: synology-iscsi-d001-wal
|
||||
labels:
|
||||
prole.storage/role: wal
|
||||
prole.storage/volume: d001
|
||||
synology.storage/role: wal
|
||||
synology.storage/volume: d001
|
||||
spec:
|
||||
capacity:
|
||||
storage: 29Gi
|
||||
volumeMode: Filesystem
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
storageClassName: prole-iscsi
|
||||
storageClassName: synology-iscsi
|
||||
persistentVolumeReclaimPolicy: Retain
|
||||
local:
|
||||
path: /synology/d001/wal
|
||||
@ -53,17 +53,17 @@ spec:
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: prole-iscsi-d001-garage
|
||||
name: synology-iscsi-d001-garage
|
||||
labels:
|
||||
prole.storage/role: garage
|
||||
prole.storage/volume: d001
|
||||
synology.storage/role: garage
|
||||
synology.storage/volume: d001
|
||||
spec:
|
||||
capacity:
|
||||
storage: 29Gi
|
||||
volumeMode: Filesystem
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
storageClassName: prole-iscsi
|
||||
storageClassName: synology-iscsi
|
||||
persistentVolumeReclaimPolicy: Retain
|
||||
local:
|
||||
path: /synology/d001/garage
|
||||
@ -79,17 +79,17 @@ spec:
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: prole-iscsi-d002-data
|
||||
name: synology-iscsi-d002-data
|
||||
labels:
|
||||
prole.storage/role: data
|
||||
prole.storage/volume: d002
|
||||
synology.storage/role: data
|
||||
synology.storage/volume: d002
|
||||
spec:
|
||||
capacity:
|
||||
storage: 29Gi
|
||||
volumeMode: Filesystem
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
storageClassName: prole-iscsi
|
||||
storageClassName: synology-iscsi
|
||||
persistentVolumeReclaimPolicy: Retain
|
||||
local:
|
||||
path: /synology/d002/data
|
||||
@ -105,17 +105,17 @@ spec:
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: prole-iscsi-d002-wal
|
||||
name: synology-iscsi-d002-wal
|
||||
labels:
|
||||
prole.storage/role: wal
|
||||
prole.storage/volume: d002
|
||||
synology.storage/role: wal
|
||||
synology.storage/volume: d002
|
||||
spec:
|
||||
capacity:
|
||||
storage: 29Gi
|
||||
volumeMode: Filesystem
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
storageClassName: prole-iscsi
|
||||
storageClassName: synology-iscsi
|
||||
persistentVolumeReclaimPolicy: Retain
|
||||
local:
|
||||
path: /synology/d002/wal
|
||||
@ -131,17 +131,17 @@ spec:
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: prole-iscsi-d003-data
|
||||
name: synology-iscsi-d003-data
|
||||
labels:
|
||||
prole.storage/role: data
|
||||
prole.storage/volume: d003
|
||||
synology.storage/role: data
|
||||
synology.storage/volume: d003
|
||||
spec:
|
||||
capacity:
|
||||
storage: 29Gi
|
||||
volumeMode: Filesystem
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
storageClassName: prole-iscsi
|
||||
storageClassName: synology-iscsi
|
||||
persistentVolumeReclaimPolicy: Retain
|
||||
local:
|
||||
path: /synology/d003/data
|
||||
@ -157,17 +157,17 @@ spec:
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: prole-iscsi-d003-wal
|
||||
name: synology-iscsi-d003-wal
|
||||
labels:
|
||||
prole.storage/role: wal
|
||||
prole.storage/volume: d003
|
||||
synology.storage/role: wal
|
||||
synology.storage/volume: d003
|
||||
spec:
|
||||
capacity:
|
||||
storage: 29Gi
|
||||
volumeMode: Filesystem
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
storageClassName: prole-iscsi
|
||||
storageClassName: synology-iscsi
|
||||
persistentVolumeReclaimPolicy: Retain
|
||||
local:
|
||||
path: /synology/d003/wal
|
||||
@ -183,17 +183,17 @@ spec:
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: prole-iscsi-d003-grafana
|
||||
name: synology-iscsi-d003-grafana
|
||||
labels:
|
||||
prole.storage/role: grafana
|
||||
prole.storage/volume: d003
|
||||
synology.storage/role: grafana
|
||||
synology.storage/volume: d003
|
||||
spec:
|
||||
capacity:
|
||||
storage: 5Gi
|
||||
volumeMode: Filesystem
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
storageClassName: prole-iscsi
|
||||
storageClassName: synology-iscsi
|
||||
persistentVolumeReclaimPolicy: Retain
|
||||
local:
|
||||
path: /synology/d003/grafana
|
||||
@ -209,17 +209,17 @@ spec:
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: prole-iscsi-d002-prometheus
|
||||
name: synology-iscsi-d002-prometheus
|
||||
labels:
|
||||
prole.storage/role: prometheus
|
||||
prole.storage/volume: d002
|
||||
synology.storage/role: prometheus
|
||||
synology.storage/volume: d002
|
||||
spec:
|
||||
capacity:
|
||||
storage: 20Gi
|
||||
volumeMode: Filesystem
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
storageClassName: prole-iscsi
|
||||
storageClassName: synology-iscsi
|
||||
persistentVolumeReclaimPolicy: Retain
|
||||
local:
|
||||
path: /synology/d002/prometheus
|
||||
@ -235,17 +235,17 @@ spec:
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: prole-iscsi-d001-openbao
|
||||
name: synology-iscsi-d001-openbao
|
||||
labels:
|
||||
prole.storage/role: openbao
|
||||
prole.storage/volume: d001
|
||||
synology.storage/role: openbao
|
||||
synology.storage/volume: d001
|
||||
spec:
|
||||
capacity:
|
||||
storage: 5Gi
|
||||
volumeMode: Filesystem
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
storageClassName: prole-iscsi
|
||||
storageClassName: synology-iscsi
|
||||
persistentVolumeReclaimPolicy: Retain
|
||||
local:
|
||||
path: /synology/d001/openbao
|
||||
|
||||
@ -3,8 +3,8 @@ kind: PersistentVolume
|
||||
metadata:
|
||||
name: prole-monitoring-d004-prometheus
|
||||
labels:
|
||||
prole.storage/role: prometheus
|
||||
prole.storage/volume: d004
|
||||
synology.storage/role: prometheus
|
||||
synology.storage/volume: d004
|
||||
spec:
|
||||
capacity:
|
||||
storage: 30Gi
|
||||
@ -29,8 +29,8 @@ kind: PersistentVolume
|
||||
metadata:
|
||||
name: prole-monitoring-d004-alertmanager
|
||||
labels:
|
||||
prole.storage/role: alertmanager
|
||||
prole.storage/volume: d004
|
||||
synology.storage/role: alertmanager
|
||||
synology.storage/volume: d004
|
||||
spec:
|
||||
capacity:
|
||||
storage: 5Gi
|
||||
@ -55,8 +55,8 @@ kind: PersistentVolume
|
||||
metadata:
|
||||
name: prole-monitoring-d004-grafana
|
||||
labels:
|
||||
prole.storage/role: grafana
|
||||
prole.storage/volume: d004
|
||||
synology.storage/role: grafana
|
||||
synology.storage/volume: d004
|
||||
spec:
|
||||
capacity:
|
||||
storage: 10Gi
|
||||
|
||||
@ -51,7 +51,7 @@ spec:
|
||||
resources:
|
||||
requests:
|
||||
storage: 1Gi
|
||||
storageClassName: prole-iscsi
|
||||
storageClassName: synology-iscsi
|
||||
selector:
|
||||
matchLabels:
|
||||
prole.storage/role: openbao
|
||||
synology.storage/role: openbao
|
||||
|
||||
@ -5,7 +5,7 @@ metadata:
|
||||
name: prole-db
|
||||
spec:
|
||||
instances: 3
|
||||
imageName: k3d-prole-registry:5000/knoe-db:18-138
|
||||
imageName: example.invalid:5000/knoe-db:0.0.0
|
||||
postgresUID: 100
|
||||
postgresGID: 101
|
||||
maxSyncReplicas: 1
|
||||
@ -61,10 +61,10 @@ spec:
|
||||
resources:
|
||||
requests:
|
||||
storage: 1Gi
|
||||
storageClassName: prole-iscsi
|
||||
storageClassName: synology-iscsi
|
||||
selector:
|
||||
matchLabels:
|
||||
prole.storage/role: data
|
||||
synology.storage/role: data
|
||||
walStorage:
|
||||
size: 1Gi
|
||||
pvcTemplate:
|
||||
@ -73,10 +73,10 @@ spec:
|
||||
resources:
|
||||
requests:
|
||||
storage: 1Gi
|
||||
storageClassName: prole-iscsi
|
||||
storageClassName: synology-iscsi
|
||||
selector:
|
||||
matchLabels:
|
||||
prole.storage/role: wal
|
||||
synology.storage/role: wal
|
||||
|
||||
monitoring:
|
||||
enablePodMonitor: false
|
||||
|
||||
@ -4,23 +4,23 @@ metadata:
|
||||
name: prole-db
|
||||
spec:
|
||||
instances: 3
|
||||
imageName: myrddin.prole.org:5000/knoe-db:18-125
|
||||
imageName: myrddin.prole.org:5000/knoe-db:18-140
|
||||
postgresUID: 100
|
||||
postgresGID: 101
|
||||
maxSyncReplicas: 1
|
||||
affinity:
|
||||
# CloudNativePG uses its own affinity schema (not corev1.Affinity). See: `kubectl explain cluster.spec.affinity`
|
||||
enablePodAntiAffinity: true
|
||||
podAntiAffinityType: required
|
||||
podAntiAffinityType: preferred
|
||||
topologyKey: kubernetes.io/hostname
|
||||
nodeAffinity:
|
||||
requiredDuringSchedulingIgnoredDuringExecution:
|
||||
nodeSelectorTerms:
|
||||
- matchExpressions:
|
||||
- key: prole.org/node-role
|
||||
- key: node.kubernetes.io/instance-type
|
||||
operator: In
|
||||
values:
|
||||
- db
|
||||
- k3s
|
||||
|
||||
postgresql:
|
||||
parameters:
|
||||
@ -88,10 +88,10 @@ spec:
|
||||
resources:
|
||||
requests:
|
||||
storage: 1Gi
|
||||
storageClassName: prole-iscsi
|
||||
storageClassName: synology-iscsi
|
||||
selector:
|
||||
matchLabels:
|
||||
prole.storage/role: data
|
||||
synology.storage/role: data
|
||||
walStorage:
|
||||
size: 1Gi
|
||||
pvcTemplate:
|
||||
@ -100,9 +100,9 @@ spec:
|
||||
resources:
|
||||
requests:
|
||||
storage: 1Gi
|
||||
storageClassName: prole-iscsi
|
||||
storageClassName: synology-iscsi
|
||||
selector:
|
||||
matchLabels:
|
||||
prole.storage/role: wal
|
||||
synology.storage/role: wal
|
||||
monitoring:
|
||||
enablePodMonitor: false
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
apiVersion: storage.k8s.io/v1
|
||||
kind: StorageClass
|
||||
metadata:
|
||||
name: prole-iscsi
|
||||
name: synology-iscsi
|
||||
provisioner: kubernetes.io/no-provisioner
|
||||
reclaimPolicy: Retain
|
||||
volumeBindingMode: WaitForFirstConsumer
|
||||
@ -856,6 +856,64 @@ class ProleInstaller:
|
||||
return self._ensure_namespace_prefix(ns)
|
||||
return self._ensure_namespace_prefix(self._generate_namespace_name())
|
||||
|
||||
def _initial_db_namespace(self) -> str:
|
||||
"""Initial namespace suggestion for CNPG/Postgres.
|
||||
|
||||
Unlike `_initial_namespace()`, this default is version-aware to encourage
|
||||
parallel installs (e.g. `knoe-db-18-142`).
|
||||
"""
|
||||
|
||||
# Explicit overrides must win.
|
||||
base = (
|
||||
os.environ.get("PROLE_DB_NAMESPACE")
|
||||
or os.environ.get("DB_NAMESPACE")
|
||||
or os.environ.get("PROLE_NAMESPACE")
|
||||
or os.environ.get("NAMESPACE")
|
||||
or ""
|
||||
).strip()
|
||||
|
||||
if not base:
|
||||
try:
|
||||
existing = self._read_existing_env()
|
||||
base = (
|
||||
(existing.get("NAMESPACE") or "")
|
||||
or (existing.get("PROLE_NAMESPACE") or "")
|
||||
).strip()
|
||||
except Exception:
|
||||
base = ""
|
||||
|
||||
if not base:
|
||||
base = (self._read_existing_cfg_namespace() or "").strip() or "knoe-db"
|
||||
|
||||
base = self._sanitize_namespace(self._ensure_namespace_prefix(base))
|
||||
|
||||
version = ""
|
||||
try:
|
||||
controller = getattr(self, "controller", None)
|
||||
if controller is not None:
|
||||
version = (controller.get_prole_db_version() or "").strip()
|
||||
except Exception:
|
||||
version = ""
|
||||
|
||||
if not version:
|
||||
return base
|
||||
|
||||
version_ns = self._sanitize_namespace(version.replace(".", "-"))
|
||||
|
||||
if base.endswith(f"-{version_ns}"):
|
||||
return base
|
||||
|
||||
combined = f"{base}-{version_ns}"
|
||||
if len(combined) > 63:
|
||||
# Keep the version suffix intact and trim the base to fit.
|
||||
max_base_len = 63 - len(version_ns) - 1
|
||||
if max_base_len < 1:
|
||||
return self._sanitize_namespace(f"knoe-db-{version_ns}")
|
||||
base_trim = base[:max_base_len].rstrip("-")
|
||||
combined = f"{base_trim}-{version_ns}"
|
||||
|
||||
return self._sanitize_namespace(combined)
|
||||
|
||||
def _is_valid_namespace(self, name: str) -> bool:
|
||||
if not name or len(name) > 63:
|
||||
return False
|
||||
@ -5613,8 +5671,8 @@ class ProleConsoleInstaller(ProleInstaller):
|
||||
NetworkScanMilestone(),
|
||||
EnvSetupMilestone(),
|
||||
SecretManagementMilestone(),
|
||||
DatabaseCreationMilestone(),
|
||||
DockerBuildMilestone(),
|
||||
DatabaseCreationMilestone(),
|
||||
ClusterLifecycleMilestone(),
|
||||
InitializationScriptsMilestone(),
|
||||
KerberosMilestone(),
|
||||
@ -5768,8 +5826,8 @@ def _prepare_k3s_pipeline(
|
||||
_log(f" k3s_token: {'detected' if k3s_token else '(not detected)'}\n\n")
|
||||
|
||||
# Load config to resolve namespace and secrets for pipeline tfvars
|
||||
_log("==> Loading installer config...\n")
|
||||
installer = ProleConsoleInstaller(controller, str(cfg_path))
|
||||
_log("==> Loading knoe config...\n")
|
||||
knoe = ProleConsoleInstaller(controller, str(cfg_path))
|
||||
try:
|
||||
existing_inputs = knoe._load_inputs_from_cfg()
|
||||
except Exception:
|
||||
|
||||
@ -85,10 +85,26 @@ class Milestone(ABC):
|
||||
namespace = (state.inputs.get("init_password.db_namespace", "") or "").strip()
|
||||
env["NAMESPACE"] = namespace or "default"
|
||||
|
||||
# Paths
|
||||
env["PROLE_CONF"] = state.inputs.get(
|
||||
"env_setup.PROLE_CONF", str(project_root / "conf")
|
||||
# Paths — prefer the env-specific conf subdir (e.g. conf/service/) so that
|
||||
# init scripts source the correct prole.cfg and don't fall back to the
|
||||
# conf/prole.cfg symlink which may point to a different cluster env.
|
||||
# Priority: (1) inherited PROLE_CONF from parent shell when it points to a
|
||||
# valid env-specific subdir, (2) cluster_env-derived subdir, (3) stored value.
|
||||
_inherited_conf = os.environ.get("PROLE_CONF", "")
|
||||
_cluster_env_for_conf = state.inputs.get("init_cluster.cluster_env", "")
|
||||
_env_conf_dir = (
|
||||
Path(project_root) / "conf" / _cluster_env_for_conf
|
||||
if _cluster_env_for_conf
|
||||
else None
|
||||
)
|
||||
if _inherited_conf and (Path(_inherited_conf) / "prole.cfg").exists():
|
||||
env["PROLE_CONF"] = _inherited_conf
|
||||
elif _env_conf_dir and _env_conf_dir.is_dir():
|
||||
env["PROLE_CONF"] = str(_env_conf_dir)
|
||||
else:
|
||||
env["PROLE_CONF"] = state.inputs.get(
|
||||
"env_setup.PROLE_CONF", str(project_root / "conf")
|
||||
)
|
||||
env["PROLE_DATA"] = state.inputs.get(
|
||||
"env_setup.PROLE_DATA", str(project_root / "prole-db" / "data")
|
||||
)
|
||||
|
||||
@ -348,10 +348,10 @@ class ProleInstaller(
|
||||
("Dependencies", "deps_summary"),
|
||||
("Network", "network_scan"),
|
||||
("System Environment", "env_setup"),
|
||||
("Cluster Environment", "init_cluster"),
|
||||
("Cluster Nodes", "cluster_nodes"),
|
||||
("Database Options", "database_options"),
|
||||
("Docker Build", "init_db_build"),
|
||||
("Cluster Environment", "init_cluster"),
|
||||
("Cluster Nodes", "cluster_nodes"),
|
||||
("Database Creation", "init_password"),
|
||||
("Initialization Scripts", "init_scripts"),
|
||||
("Kerberos Authentication", "kerberos_config"),
|
||||
@ -655,7 +655,7 @@ class ProleInstaller(
|
||||
self.db_password = tk.StringVar()
|
||||
self.db_password_confirm = tk.StringVar()
|
||||
self.namespace_owner = self._get_local_owner()
|
||||
self.db_namespace = tk.StringVar(value=self._initial_namespace())
|
||||
self.db_namespace = tk.StringVar(value=self._initial_db_namespace())
|
||||
try:
|
||||
_ns_from_cfg = (
|
||||
(self.prole_cfg_data.get("Global", {}) or {})
|
||||
@ -663,7 +663,21 @@ class ProleInstaller(
|
||||
.strip()
|
||||
)
|
||||
if _ns_from_cfg:
|
||||
self.db_namespace.set(self._ensure_namespace_prefix(_ns_from_cfg))
|
||||
base = self._ensure_namespace_prefix(_ns_from_cfg)
|
||||
ver = ""
|
||||
try:
|
||||
ver = (self.controller.get_prole_db_version() or "").strip()
|
||||
except Exception:
|
||||
ver = ""
|
||||
if ver:
|
||||
ver_ns = self._sanitize_namespace(ver.replace(".", "-"))
|
||||
base_ns = self._sanitize_namespace(base)
|
||||
if base_ns.endswith(f"-{ver_ns}"):
|
||||
self.db_namespace.set(base_ns)
|
||||
else:
|
||||
self.db_namespace.set(self._sanitize_namespace(f"{base_ns}-{ver_ns}"))
|
||||
else:
|
||||
self.db_namespace.set(self._sanitize_namespace(base))
|
||||
except Exception:
|
||||
pass
|
||||
self.db_host_port = tk.StringVar(value="5432")
|
||||
|
||||
@ -1420,6 +1420,7 @@ class DatabaseScreenMixin:
|
||||
# Use $PROLE_HOME/build for Docker build context
|
||||
# This avoids issues with PyInstaller's temporary _MEIPASS directory
|
||||
prole_home = resolve_prole_home()
|
||||
env_key = self._cluster_env_key()
|
||||
mode_key = _deployment_mode_from_env(env_key) or "default"
|
||||
build_dir = prole_home / "build" / mode_key / "knoe-db"
|
||||
build_dir.mkdir(parents=True, exist_ok=True)
|
||||
@ -1442,7 +1443,6 @@ class DatabaseScreenMixin:
|
||||
pub_key = pub_key_path.read_text().strip()
|
||||
|
||||
username = self.db_username.get()
|
||||
env_key = self._cluster_env_key()
|
||||
cmd = ["docker", "build", "--progress=plain"]
|
||||
cmd.extend(get_docker_build_platform_args(env_key))
|
||||
cmd += [
|
||||
|
||||
@ -615,22 +615,48 @@ class DockerScreenMixin:
|
||||
raise Exception(f"Unknown environment: {env}")
|
||||
|
||||
def create_or_recreate_k3d_dev_cluster(self, cluster_name="knoe-dev-cluster"):
|
||||
"""Create or restart local k3d cluster and wire it to the chosen registry."""
|
||||
"""Create or restart local k3d cluster and wire it to the local k3d registry."""
|
||||
result = subprocess.run(
|
||||
["k3d", "cluster", "list"], capture_output=True, text=True
|
||||
)
|
||||
if cluster_name in (result.stdout or ""):
|
||||
subprocess.run(["k3d", "cluster", "delete", cluster_name], check=True)
|
||||
|
||||
# Determine registry integration args
|
||||
reg_args = []
|
||||
if getattr(self, "registry_url", None):
|
||||
# If using the local k3d registry, we want to create or use it
|
||||
if self.registry_url.startswith("localhost:5000"):
|
||||
# Creating with --registry-create ensures it's available and integrated
|
||||
reg_args = ["--registry-create", f"prole-registry:0.0.0.0:5000"]
|
||||
else:
|
||||
reg_args = ["--registry-use", self.registry_url]
|
||||
# Always ensure the local k3d registry exists before creating the cluster so
|
||||
# that we can wire it via --registry-use. Using --registry-use (rather than
|
||||
# --registry-create) is required when the registry container already exists,
|
||||
# which is the common case after the first install run.
|
||||
reg_name = "prole-registry"
|
||||
registry_container = f"k3d-{reg_name}"
|
||||
lst = subprocess.run(
|
||||
["k3d", "registry", "list"], capture_output=True, text=True
|
||||
)
|
||||
if registry_container not in (lst.stdout or "") and reg_name not in (
|
||||
lst.stdout or ""
|
||||
):
|
||||
subprocess.run(
|
||||
["k3d", "registry", "create", reg_name, "--port", "0.0.0.0:5000"],
|
||||
check=True,
|
||||
)
|
||||
# Ensure the registry container is actually running
|
||||
running = subprocess.run(
|
||||
[
|
||||
"docker",
|
||||
"ps",
|
||||
"--filter",
|
||||
f"name={registry_container}",
|
||||
"--format",
|
||||
"{{.Names}}",
|
||||
],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
if not (running.stdout or "").strip():
|
||||
subprocess.run(["docker", "start", registry_container], check=True)
|
||||
|
||||
# Wire the cluster to the registry so containerd inside each node resolves
|
||||
# k3d-prole-registry.localhost:5000 correctly.
|
||||
reg_args = ["--registry-use", f"{registry_container}:5000"]
|
||||
|
||||
prole_data = str(self._resolve_env_dir("PROLE_DATA", "data"))
|
||||
volume_args = _k3d_prole_data_volume_args(prole_data)
|
||||
|
||||
@ -61,9 +61,9 @@ CERT_MANAGER_MANIFEST_URL=${CERT_MANAGER_MANIFEST_URL:-}
|
||||
CERT_MANAGER_FALLBACK_VERSION=${CERT_MANAGER_FALLBACK_VERSION:-1.19.3}
|
||||
|
||||
# Protected storage requirements (k3s only)
|
||||
PROLE_CNPG_STORAGE_CLASS=${PROLE_CNPG_STORAGE_CLASS:-prole-iscsi}
|
||||
PROLE_PROTECTED_DATA_PATH=${PROLE_PROTECTED_DATA_PATH:-/prole/d001/data}
|
||||
PROLE_PROTECTED_WAL_PATH=${PROLE_PROTECTED_WAL_PATH:-/prole/d001/wal}
|
||||
PROLE_CNPG_STORAGE_CLASS=${PROLE_CNPG_STORAGE_CLASS:-synology-iscsi}
|
||||
PROLE_PROTECTED_DATA_PATH=${PROLE_PROTECTED_DATA_PATH:-/synology/d001/data}
|
||||
PROLE_PROTECTED_WAL_PATH=${PROLE_PROTECTED_WAL_PATH:-/synology/d001/wal}
|
||||
|
||||
if [[ "$ACTION" != "deploy" && "$ACTION" != "rollout" && "$ACTION" != "force-rollout" ]]; then
|
||||
if [[ -n "${2:-}" ]]; then
|
||||
@ -225,9 +225,9 @@ validate_cnpg_manifest_storage() {
|
||||
wal_sc="$v"
|
||||
fi
|
||||
fi
|
||||
if [[ -n "$block" && "$line" =~ prole\.storage/role: ]]; then
|
||||
if [[ -n "$block" && "$line" =~ synology\.storage/role: ]]; then
|
||||
local r
|
||||
r=$(printf '%s' "$line" | sed -E 's/^.*prole\.storage\/role:[[:space:]]*//; s/[[:space:]]+$//')
|
||||
r=$(printf '%s' "$line" | sed -E 's/^.*synology\.storage\/role:[[:space:]]*//; s/[[:space:]]+$//')
|
||||
if [[ "$block" == "storage" && -z "$data_role" ]]; then
|
||||
data_role="$r"
|
||||
elif [[ "$block" == "wal" && -z "$wal_role" ]]; then
|
||||
@ -243,7 +243,7 @@ validate_cnpg_manifest_storage() {
|
||||
fi
|
||||
|
||||
if [[ "$data_role" != "data" || "$wal_role" != "wal" ]]; then
|
||||
echo "ERROR: CNPG Cluster manifest must include explicit PV selectors for Prole storage (prole.storage/role=data and prole.storage/role=wal)." >&2
|
||||
echo "ERROR: CNPG Cluster manifest must include explicit PV selectors for Prole storage (synology.storage/role=data and synology.storage/role=wal)." >&2
|
||||
echo "Got selector roles: data='${data_role:-<missing>}', wal='${wal_role:-<missing>}'" >&2
|
||||
return 1
|
||||
fi
|
||||
@ -267,8 +267,8 @@ validate_cnpg_runtime_storage() {
|
||||
local data_sc wal_sc data_role wal_role
|
||||
data_sc=$(printf '%s' "$cluster_json" | jq -r '.spec.storage.pvcTemplate.storageClassName // empty')
|
||||
wal_sc=$(printf '%s' "$cluster_json" | jq -r '.spec.walStorage.pvcTemplate.storageClassName // empty')
|
||||
data_role=$(printf '%s' "$cluster_json" | jq -r '.spec.storage.pvcTemplate.selector.matchLabels["prole.storage/role"] // empty')
|
||||
wal_role=$(printf '%s' "$cluster_json" | jq -r '.spec.walStorage.pvcTemplate.selector.matchLabels["prole.storage/role"] // empty')
|
||||
data_role=$(printf '%s' "$cluster_json" | jq -r '.spec.storage.pvcTemplate.selector.matchLabels["synology.storage/role"] // empty')
|
||||
wal_role=$(printf '%s' "$cluster_json" | jq -r '.spec.walStorage.pvcTemplate.selector.matchLabels["synology.storage/role"] // empty')
|
||||
|
||||
if [[ "$data_sc" != "$sc" || "$wal_sc" != "$sc" ]]; then
|
||||
echo "ERROR: Live CNPG Cluster storageClassName must be '${sc}' for both data and walStorage (got data='${data_sc:-<missing>}', wal='${wal_sc:-<missing>}')." >&2
|
||||
@ -326,9 +326,9 @@ validate_cnpg_runtime_storage() {
|
||||
return 1
|
||||
fi
|
||||
case "$pv_path" in
|
||||
/prole/*) ;;
|
||||
/synology/*) ;;
|
||||
*)
|
||||
echo "ERROR: Bound PV '${pv}' path '${pv_path}' is not under /prole/. Refusing deployment." >&2
|
||||
echo "ERROR: Bound PV '${pv}' path '${pv_path}' is not under /synology/. Refusing deployment." >&2
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
@ -1168,6 +1168,81 @@ apply_prole_manifest_file() {
|
||||
return 1
|
||||
}
|
||||
|
||||
_prole_k3s_registry_host_for_cache() {
|
||||
# Best-effort host:port for the k3s registry, used as an optional cache source in k3d mode.
|
||||
# Intentionally avoids k3d registry names and localhost-ish endpoints.
|
||||
local r="${PROLE_K3S_REGISTRY:-${K3S_REGISTRY_HOST:-${LOCAL_REGISTRY_INTERNAL:-${LOCAL_REGISTRY:-}}}}"
|
||||
|
||||
r="${r#http://}"
|
||||
r="${r#https://}"
|
||||
|
||||
case "${r}" in
|
||||
"")
|
||||
r="myrddin.prole.org:5000"
|
||||
;;
|
||||
localhost:5000|127.0.0.1:5000|*.localhost|*.localhost:5000)
|
||||
r="myrddin.prole.org:5000"
|
||||
;;
|
||||
k3d-*|*/k3d-*)
|
||||
r="myrddin.prole.org:5000"
|
||||
;;
|
||||
esac
|
||||
|
||||
printf '%s' "$r"
|
||||
}
|
||||
|
||||
_docker_build_knoe_db_image() {
|
||||
# Build the knoe-db image with BuildKit and optional cache source.
|
||||
# Args: <tag> <context_dir> [cache_ref]
|
||||
local tag="$1"
|
||||
local context_dir="$2"
|
||||
local cache_ref="${3:-}"
|
||||
|
||||
local ssh_args=()
|
||||
if [[ -n "${SSH_AUTH_SOCK:-}" ]]; then
|
||||
ssh_args+=(--ssh default)
|
||||
fi
|
||||
|
||||
if docker buildx version >/dev/null 2>&1; then
|
||||
# Prefer an isolated docker-container builder to avoid host snapshot/cache corruption.
|
||||
local builder_name="${PROLE_BUILDX_BUILDER:-prole-buildkit}"
|
||||
if ! docker buildx inspect "$builder_name" >/dev/null 2>&1; then
|
||||
docker buildx create --name "$builder_name" --driver docker-container --use >/dev/null 2>&1 || true
|
||||
else
|
||||
docker buildx use "$builder_name" >/dev/null 2>&1 || true
|
||||
fi
|
||||
|
||||
local cache_args=()
|
||||
if [[ -n "$cache_ref" ]]; then
|
||||
cache_args+=(--cache-from "type=registry,ref=${cache_ref}")
|
||||
fi
|
||||
|
||||
if docker buildx build \
|
||||
--pull \
|
||||
--tag "$tag" \
|
||||
--load \
|
||||
"${ssh_args[@]}" \
|
||||
"${cache_args[@]}" \
|
||||
"$context_dir"; then
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# Fallback to docker build (still BuildKit-enabled); cache-from here only works if the cache image is present locally.
|
||||
local cache_from_args=()
|
||||
if [[ -n "$cache_ref" ]]; then
|
||||
docker pull "$cache_ref" >/dev/null 2>&1 || true
|
||||
cache_from_args+=(--cache-from "$cache_ref")
|
||||
fi
|
||||
|
||||
DOCKER_BUILDKIT=1 docker build \
|
||||
--pull \
|
||||
"${ssh_args[@]}" \
|
||||
"${cache_from_args[@]}" \
|
||||
-t "$tag" \
|
||||
"$context_dir"
|
||||
}
|
||||
|
||||
_push_to_k3s_registry() {
|
||||
local image="$1"
|
||||
local push_host="${LOCAL_REGISTRY:-${LOCAL_REGISTRY_INTERNAL:-myrddin.prole.org:5000}}"
|
||||
@ -1310,6 +1385,7 @@ _ensure_prole_db_image() {
|
||||
image=$(resolve_cnpg_image "$image")
|
||||
local prole_db_dir="${PROLE_HOME:-$SCRIPT_DIR/..}/prole-db"
|
||||
local plain_image="${image##*/}" # e.g. knoe-db:18-088
|
||||
local k3s_cache_ref=""
|
||||
|
||||
if [[ "${PROLE_MODE:-}" == "k3s" ]]; then
|
||||
echo "Pre-flight: ensuring image '$image' is available in k3s registry/import path ..."
|
||||
@ -1321,6 +1397,13 @@ _ensure_prole_db_image() {
|
||||
fi
|
||||
cluster_name="${cluster_name:-knoe-dev-cluster}"
|
||||
|
||||
# In k3d mode, optionally consult the k3s registry as a cache/source of truth before building.
|
||||
local k3s_host
|
||||
k3s_host=$(_prole_k3s_registry_host_for_cache)
|
||||
if [[ -n "${k3s_host:-}" ]]; then
|
||||
k3s_cache_ref="${k3s_host}/${plain_image}"
|
||||
fi
|
||||
|
||||
echo "Pre-flight: verifying image '$image' is available in k3d cluster '$cluster_name' ..."
|
||||
|
||||
# Step 1: check if already present in k3d containerd with matching digest
|
||||
@ -1393,6 +1476,17 @@ _ensure_prole_db_image() {
|
||||
return $?
|
||||
fi
|
||||
|
||||
# Step 3b (k3d only): try to reuse a previously-built image from the k3s registry.
|
||||
if [[ "${PROLE_MODE:-}" == "k3d" && -n "${k3s_cache_ref:-}" && "${k3s_cache_ref}" != "${image}" ]]; then
|
||||
if docker image inspect "$k3s_cache_ref" >/dev/null 2>&1 || docker pull "$k3s_cache_ref" >/dev/null 2>&1; then
|
||||
echo " ✓ Found '$plain_image' in k3s registry (${k3s_cache_ref}); re-tagging for k3d as '$image' ..."
|
||||
docker tag "$k3s_cache_ref" "$image" 2>/dev/null || true
|
||||
_push_to_k3d_registry "$image" "$cluster_name"
|
||||
return $?
|
||||
fi
|
||||
echo " (cache) '$plain_image' not present in k3s registry (${k3s_cache_ref}); building locally ..."
|
||||
fi
|
||||
|
||||
# Step 4: image not found anywhere — build from source then push + import
|
||||
if [[ ! -f "$prole_db_dir/Dockerfile" ]]; then
|
||||
echo "ERROR: Dockerfile not found in '$prole_db_dir'; cannot build knoe-db image." >&2
|
||||
@ -1404,7 +1498,7 @@ _ensure_prole_db_image() {
|
||||
echo " Image '$image' not found in k3d, Docker daemon, or docker-import dir."
|
||||
fi
|
||||
echo " Building knoe-db image from '$prole_db_dir' ..."
|
||||
if ! docker build -t "$plain_image" "$prole_db_dir"; then
|
||||
if ! _docker_build_knoe_db_image "$plain_image" "$prole_db_dir" "${k3s_cache_ref:-}"; then
|
||||
echo "ERROR: docker build failed for image '$plain_image'." >&2
|
||||
return 1
|
||||
fi
|
||||
@ -2148,14 +2242,14 @@ reset_and_reinit() {
|
||||
}
|
||||
|
||||
recycle_released_prole_iscsi_pvs() {
|
||||
# StorageClass `prole-iscsi` uses `Retain` PV reclaim policy. After a CNPG reset, PVs can remain
|
||||
# StorageClass `synology-iscsi` uses `Retain` PV reclaim policy. After a CNPG reset, PVs can remain
|
||||
# in `Released` with a stale `claimRef`, which prevents new PVCs (same names) from binding.
|
||||
# In that case, CNPG init jobs remain `Pending` with "didn't find available persistent volumes".
|
||||
echo "Recycling Released prole-iscsi PVs (clearing stale claimRefs) for namespace '$NAMESPACE' ..."
|
||||
echo "Recycling Released synology-iscsi PVs (clearing stale claimRefs) for namespace '$NAMESPACE' ..."
|
||||
local pvs
|
||||
pvs=$(kubectl get pv -o json \
|
||||
| jq -r --arg ns "$NAMESPACE" '.items[]
|
||||
| select(.spec.storageClassName == "prole-iscsi")
|
||||
| select(.spec.storageClassName == "synology-iscsi")
|
||||
| select(.status.phase == "Released")
|
||||
| select((.spec.claimRef.namespace // "") == $ns)
|
||||
| .metadata.name' 2>/dev/null || true)
|
||||
|
||||
@ -60,7 +60,7 @@ else
|
||||
fi
|
||||
|
||||
GARAGE_FILES=(
|
||||
"$GARAGE_MANIFEST_DIR/storageclass-prole-iscsi.yaml"
|
||||
"$GARAGE_MANIFEST_DIR/storageclass-synology-iscsi.yaml"
|
||||
"$GARAGE_MANIFEST_DIR/iscsi-pvs.yaml"
|
||||
"$GARAGE_MANIFEST_DIR/garage-configmap.yaml"
|
||||
"$GARAGE_MANIFEST_DIR/garage-statefulset.yaml"
|
||||
@ -133,7 +133,7 @@ k3d_cleanup_pending_pvc() {
|
||||
return 0
|
||||
fi
|
||||
selector=$(kubectl get pvc data-garage-0 -n "$NAMESPACE" -o jsonpath='{.spec.selector}' 2>/dev/null || true)
|
||||
if printf '%s' "$selector" | grep -q "prole.storage/"; then
|
||||
if printf '%s' "$selector" | grep -q "synology.storage/"; then
|
||||
echo "Removing pending Garage PVC with selector for k3d local-path ..."
|
||||
kubectl delete statefulset "$GARAGE_NAME" -n "$NAMESPACE" --ignore-not-found >/dev/null 2>&1 || true
|
||||
kubectl delete pvc data-garage-0 -n "$NAMESPACE" --ignore-not-found >/dev/null 2>&1 || true
|
||||
@ -283,7 +283,7 @@ dump_debug() {
|
||||
}
|
||||
|
||||
recycle_released_prole_iscsi_pv_for_pvc() {
|
||||
# StorageClass `prole-iscsi` uses `Retain` PV reclaim policy. On restart, PVs can remain
|
||||
# StorageClass `synology-iscsi` uses `Retain` PV reclaim policy. On restart, PVs can remain
|
||||
# in `Released` with a stale `claimRef`, which prevents a same-named PVC from binding.
|
||||
local ns="$1"
|
||||
local pvc="$2"
|
||||
@ -301,7 +301,7 @@ recycle_released_prole_iscsi_pv_for_pvc() {
|
||||
|
||||
local pv sc rp phase claim_ns claim_name claim_uid
|
||||
while IFS=$'\t' read -r pv sc rp phase claim_ns claim_name claim_uid; do
|
||||
[[ "$sc" == "prole-iscsi" ]] || continue
|
||||
[[ "$sc" == "synology-iscsi" ]] || continue
|
||||
[[ "$rp" == "Retain" ]] || continue
|
||||
[[ "$phase" == "Released" ]] || continue
|
||||
[[ "$claim_ns" == "$ns" ]] || continue
|
||||
@ -322,7 +322,7 @@ wait_ready() {
|
||||
|
||||
local initial_timeout="${PVC_REPAIR_WAIT_TIMEOUT:-30s}"
|
||||
if ! kubectl rollout status statefulset/$GARAGE_NAME -n "$NAMESPACE" --timeout="$initial_timeout"; then
|
||||
echo "WARN: Garage not ready after $initial_timeout; checking for Released prole-iscsi PVs with stale claimRefs ..." >&2
|
||||
echo "WARN: Garage not ready after $initial_timeout; checking for Released synology-iscsi PVs with stale claimRefs ..." >&2
|
||||
recycle_released_prole_iscsi_pv_for_pvc "$NAMESPACE" "data-garage-0" || true
|
||||
fi
|
||||
|
||||
|
||||
@ -313,8 +313,8 @@ kind: PersistentVolume
|
||||
metadata:
|
||||
name: merlin-local-iscsi-${volume_id}-prometheus
|
||||
labels:
|
||||
prole.storage/role: prometheus
|
||||
prole.storage/volume: ${volume_id}
|
||||
synology.storage/role: prometheus
|
||||
synology.storage/volume: ${volume_id}
|
||||
spec:
|
||||
capacity:
|
||||
storage: 30Gi
|
||||
@ -339,8 +339,8 @@ kind: PersistentVolume
|
||||
metadata:
|
||||
name: merlin-local-iscsi-${volume_id}-alertmanager
|
||||
labels:
|
||||
prole.storage/role: alertmanager
|
||||
prole.storage/volume: ${volume_id}
|
||||
synology.storage/role: alertmanager
|
||||
synology.storage/volume: ${volume_id}
|
||||
spec:
|
||||
capacity:
|
||||
storage: 5Gi
|
||||
@ -365,8 +365,8 @@ kind: PersistentVolume
|
||||
metadata:
|
||||
name: merlin-local-iscsi-${volume_id}-grafana
|
||||
labels:
|
||||
prole.storage/role: grafana
|
||||
prole.storage/volume: ${volume_id}
|
||||
synology.storage/role: grafana
|
||||
synology.storage/volume: ${volume_id}
|
||||
spec:
|
||||
capacity:
|
||||
storage: 10Gi
|
||||
|
||||
@ -424,9 +424,9 @@ apply_k8s() {
|
||||
fi
|
||||
if [[ "$use_statefulset" == "1" ]]; then
|
||||
# Ensure storage class and PVs exist for k3s
|
||||
if [[ -f "$SCRIPT_DIR/../k8s/prole/storageclass-prole-iscsi.yaml" ]]; then
|
||||
echo "Applying StorageClass 'prole-iscsi' ..."
|
||||
kubectl apply -f "$SCRIPT_DIR/../k8s/prole/storageclass-prole-iscsi.yaml"
|
||||
if [[ -f "$SCRIPT_DIR/../k8s/prole/storageclass-synology-iscsi.yaml" ]]; then
|
||||
echo "Applying StorageClass 'synology-iscsi' ..."
|
||||
kubectl apply -f "$SCRIPT_DIR/../k8s/prole/storageclass-synology-iscsi.yaml"
|
||||
fi
|
||||
if [[ -f "$SCRIPT_DIR/../k8s/prole/iscsi-pvs.yaml" ]]; then
|
||||
echo "Applying iSCSI PersistentVolumes ..."
|
||||
@ -476,7 +476,7 @@ k3d_cleanup_pending_openbao_pvc() {
|
||||
return 0
|
||||
fi
|
||||
selector=$(kubectl get pvc data-openbao-0 -n "$OPENBAO_RESOURCE_NAMESPACE" -o jsonpath='{.spec.selector}' 2>/dev/null || true)
|
||||
if printf '%s' "$selector" | grep -q "prole.storage/"; then
|
||||
if printf '%s' "$selector" | grep -q "synology.storage/"; then
|
||||
echo "Removing pending OpenBao PVC with selector for k3d local-path ..."
|
||||
kubectl delete statefulset "$OPENBAO_NAME" -n "$OPENBAO_RESOURCE_NAMESPACE" --ignore-not-found >/dev/null 2>&1 || true
|
||||
kubectl delete pvc data-openbao-0 -n "$OPENBAO_RESOURCE_NAMESPACE" --ignore-not-found >/dev/null 2>&1 || true
|
||||
@ -484,7 +484,7 @@ k3d_cleanup_pending_openbao_pvc() {
|
||||
}
|
||||
|
||||
recycle_released_prole_iscsi_pv_for_pvc() {
|
||||
# StorageClass `prole-iscsi` uses `Retain` PV reclaim policy. On restart, PVs can remain
|
||||
# StorageClass `synology-iscsi` uses `Retain` PV reclaim policy. On restart, PVs can remain
|
||||
# in `Released` with a stale `claimRef`, which prevents a same-named PVC from binding.
|
||||
local ns="$1"
|
||||
local pvc="$2"
|
||||
@ -502,7 +502,7 @@ recycle_released_prole_iscsi_pv_for_pvc() {
|
||||
|
||||
local pv sc rp phase claim_ns claim_name claim_uid
|
||||
while IFS=$'\t' read -r pv sc rp phase claim_ns claim_name claim_uid; do
|
||||
[[ "$sc" == "prole-iscsi" ]] || continue
|
||||
[[ "$sc" == "synology-iscsi" ]] || continue
|
||||
[[ "$rp" == "Retain" ]] || continue
|
||||
[[ "$phase" == "Released" ]] || continue
|
||||
[[ "$claim_ns" == "$ns" ]] || continue
|
||||
@ -543,13 +543,13 @@ wait_for_openbao() {
|
||||
echo "Waiting for OpenBao to become ready in namespace '$wait_ns' ..."
|
||||
if kubectl get statefulset/$OPENBAO_NAME -n "$wait_ns" >/dev/null 2>&1; then
|
||||
if ! kubectl rollout status statefulset/$OPENBAO_NAME -n "$wait_ns" --timeout="$initial_timeout"; then
|
||||
echo "WARN: OpenBao not ready after $initial_timeout; checking for Released prole-iscsi PVs with stale claimRefs ..." >&2
|
||||
echo "WARN: OpenBao not ready after $initial_timeout; checking for Released synology-iscsi PVs with stale claimRefs ..." >&2
|
||||
recycle_released_prole_iscsi_pv_for_pvc "$wait_ns" "data-openbao-0" || true
|
||||
fi
|
||||
kubectl rollout status statefulset/$OPENBAO_NAME -n "$wait_ns" --timeout=${ROLLOUT_TIMEOUT:-300s}
|
||||
else
|
||||
if ! kubectl rollout status deploy/$OPENBAO_NAME -n "$wait_ns" --timeout="$initial_timeout"; then
|
||||
echo "WARN: OpenBao not ready after $initial_timeout; checking for Released prole-iscsi PVs with stale claimRefs ..." >&2
|
||||
echo "WARN: OpenBao not ready after $initial_timeout; checking for Released synology-iscsi PVs with stale claimRefs ..." >&2
|
||||
recycle_released_prole_iscsi_pv_for_pvc "$wait_ns" "data-openbao-0" || true
|
||||
fi
|
||||
kubectl rollout status deploy/$OPENBAO_NAME -n "$wait_ns" --timeout=${ROLLOUT_TIMEOUT:-300s}
|
||||
|
||||
@ -488,7 +488,7 @@ fi
|
||||
|
||||
# Safety: prole.cfg must override any pre-set PROLE_MODE from the environment.
|
||||
# Otherwise a leaked PROLE_MODE=k3d can trigger k3d-only manifest stripping (e.g., removing
|
||||
# `storageClassName: prole-iscsi`) while targeting a k3s cluster.
|
||||
# `storageClassName: synology-iscsi`) while targeting a k3s cluster.
|
||||
_prole_cfg_mode_hint=""
|
||||
if [[ -n "${prole_mode:-}" ]]; then
|
||||
_prole_cfg_mode_hint=$(prole_normalize_mode "$prole_mode")
|
||||
|
||||
@ -65,7 +65,7 @@ def _strip_blocks(text: str) -> str:
|
||||
break
|
||||
block_lines.append(next_line)
|
||||
j += 1
|
||||
if any("prole.storage/" in bl for bl in block_lines):
|
||||
if any("synology.storage/" in bl for bl in block_lines):
|
||||
i = j
|
||||
continue
|
||||
out.extend(block_lines)
|
||||
@ -78,7 +78,7 @@ def _strip_blocks(text: str) -> str:
|
||||
i += 1
|
||||
continue
|
||||
|
||||
if stripped.startswith("storageClassName:") and "prole-iscsi" in stripped:
|
||||
if stripped.startswith("storageClassName:") and "synology-iscsi" in stripped:
|
||||
i += 1
|
||||
continue
|
||||
|
||||
|
||||
1
modes/k3d/conf/postgresql/.version
Normal file
1
modes/k3d/conf/postgresql/.version
Normal file
@ -0,0 +1 @@
|
||||
18
|
||||
1
modes/k3d/prole-db/.version
Normal file
1
modes/k3d/prole-db/.version
Normal file
@ -0,0 +1 @@
|
||||
3
|
||||
@ -1 +1 @@
|
||||
138
|
||||
140
|
||||
17
prole.sh
17
prole.sh
@ -145,15 +145,19 @@ err_msg() {
|
||||
|
||||
load_prole_cfg() {
|
||||
local cfg="${1:-$PROLE_CFG_DEFAULT}"
|
||||
# Set PROLE_CONF before sourcing prole_cfg.sh so it is preserved (prole_cfg.sh
|
||||
# honours a pre-set PROLE_CONF) and the correct config file is auto-detected.
|
||||
if [[ -f "$cfg" ]]; then
|
||||
PROLE_CONF="$(cd "$(dirname "$cfg")" && pwd)"
|
||||
export PROLE_CONF
|
||||
PROLE_CFG_FILE="$cfg"
|
||||
export PROLE_CFG_FILE
|
||||
fi
|
||||
if [[ -f "${ROOT_DIR}/etc/prole_cfg.sh" ]]; then
|
||||
# shellcheck disable=SC1090
|
||||
source "${ROOT_DIR}/etc/prole_cfg.sh"
|
||||
fi
|
||||
if [[ -f "$cfg" ]]; then
|
||||
export PROLE_CONF
|
||||
PROLE_CONF="$(cd "$(dirname "$cfg")" && pwd)"
|
||||
fi
|
||||
export PROLE_CFG_FILE="$cfg"
|
||||
export PROLE_CFG_FILE="${cfg}"
|
||||
}
|
||||
|
||||
resolve_prole_mode() {
|
||||
@ -594,7 +598,8 @@ case "${CMD}" in
|
||||
CMD_ARGS=("${_INSTALL_PASSTHRU[@]}")
|
||||
|
||||
# Ensure OpenBao URL is set appropriately for the active mode before running install.py.
|
||||
_cfg_for_env="${PROLE_CFG_DEFAULT}"
|
||||
# Honour top-level -c / --config if provided (CONFIG_PATH), falling back to default.
|
||||
_cfg_for_env="${CONFIG_PATH:-${PROLE_CFG_DEFAULT}}"
|
||||
for ((i=0; i<${#CMD_ARGS[@]}; i++)); do
|
||||
if [[ "${CMD_ARGS[$i]}" == "-c" || "${CMD_ARGS[$i]}" == "--config" ]]; then
|
||||
if [[ $((i+1)) -lt ${#CMD_ARGS[@]} ]]; then
|
||||
|
||||
7
scan/ansible_inventory_flat.txt
Normal file
7
scan/ansible_inventory_flat.txt
Normal file
@ -0,0 +1,7 @@
|
||||
host,ip,roles
|
||||
merlin,10.0.0.36,merlin_bootstrap
|
||||
merlin.prole.org,,iscsi,k3s_agents,k3s_hosts,linux_hosts,mariadb,mariadb_primary
|
||||
myrddin.prole.org,,ad_dc,iscsi,k3s_hosts,k3s_servers,linux_hosts,ssl_hosts
|
||||
pi.prole.org,,iscsi,k3s_agents,k3s_hosts,linux_hosts,pihole
|
||||
raspberry.prole.org,,iscsi,linux_hosts,mariadb,mariadb_replica,pihole
|
||||
retropie.prole.org,,iscsi,linux_hosts
|
||||
65
scan/network_description.txt
Normal file
65
scan/network_description.txt
Normal file
@ -0,0 +1,65 @@
|
||||
Network Discovery Summary:
|
||||
Primary Router: 10.0.0.1 (eero_5d:50:f2)
|
||||
DNS Servers: 10.0.0.4, 100.100.100.100, 10.0.0.5
|
||||
Detected Devices:
|
||||
- 10.0.0.38 [7e:19:9a:fe:9f:ed] (7e:19:9a:fe:9f:ed): Ports [22, 445, 5900, 11434, 88], Services: ['SSH', 'VNC', 'SMB/CIFS (Possible Windows/AD)', 'Ollama', 'Active Directory Related']
|
||||
- 10.0.0.22 [2c:cf:67:45:8d:97] (RaspberryPi_45:8d:97): Ports [22, 80, 443], Services: ['SSH', 'Web Server']
|
||||
- 10.0.0.4 [b8:27:eb:b3:6f:2b] (RaspberryPiF_b3:6f:2b): Ports [22, 53, 443, 2049], Services: ['DNS', 'SSH', 'NFS', 'Web Server']
|
||||
- 10.0.0.1 [9c:57:bc:5d:50:f2] (eero_5d:50:f2): Ports [53], Services: ['DNS']
|
||||
- 10.0.0.3 [2c:cf:67:8c:2b:47] (RaspberryPi_8c:2b:47): Ports [22, 53, 80, 443, 2049, 445, 5900, 88, 389, 636], Services: ['DNS', 'SSH', 'NFS', 'VNC', 'Web Server', 'SMB/CIFS (Possible Windows/AD)', 'Active Directory Related']
|
||||
- 10.0.0.2 [dc:a4:ca:ea:1a:2f] (Apple_ea:1a:2f): Ports [], Services: []
|
||||
- 10.0.0.6 [2c:cf:67:45:8d:97] (RaspberryPi_45:8d:97): Ports [22, 80, 443], Services: ['SSH', 'Web Server']
|
||||
- 10.0.0.5 [b8:27:eb:88:3a:41] (RaspberryPiF_88:3a:41): Ports [22, 53, 443, 2049, 5900], Services: ['DNS', 'SSH', 'NFS', 'VNC', 'Web Server']
|
||||
- 10.0.0.26 [c8:db:26:08:52:f8] (Logitech_08:52:f8): Ports [], Services: []
|
||||
- 10.0.0.33 [ec:b5:fa:b0:76:e4] (PhilipsLight_b0:76:e4): Ports [80, 443], Services: ['Web Server']
|
||||
- 10.0.0.73 [4c:a9:19:b3:12:f8] (TuyaSmart_b3:12:f8): Ports [], Services: []
|
||||
- 10.0.0.37 [54:07:7d:22:c0:b2] (Netgear_22:c0:b2): Ports [80], Services: ['Web Server']
|
||||
- 10.0.0.45 [f8:b4:6a:30:a4:1f] (HewlettPacka_30:a4:1f): Ports [80, 443], Services: ['Web Server']
|
||||
- 10.0.0.46 [d4:f7:d5:40:ab:17] (SonyInteract_40:ab:17): Ports [], Services: []
|
||||
- 10.0.0.48 [0c:fe:45:53:f4:3c] (SonyInteract_53:f4:3c): Ports [], Services: []
|
||||
- 10.0.0.55 [48:a6:b8:a7:50:60] (Sonos_a7:50:60): Ports [], Services: []
|
||||
- 10.0.0.58 [7e:46:74:2a:b0:b2] (7e:46:74:2a:b0:b2): Ports [], Services: []
|
||||
- 10.0.0.41 [b8:27:eb:57:10:d9] (RaspberryPiF_57:10:d9): Ports [22], Services: ['SSH']
|
||||
- 10.0.0.203 [00:11:32:3b:2f:08] (Synology_3b:2f:08): Ports [22, 80, 443, 2049, 445], Services: ['SSH', 'NFS', 'Web Server', 'SMB/CIFS (Possible Windows/AD)']
|
||||
- 10.0.0.100 [24:fc:e5:51:cf:74] (SamsungElect_51:cf:74): Ports [], Services: []
|
||||
- 10.0.0.99 [20:28:bc:f1:dc:ba] (Visionscape_f1:dc:ba): Ports [], Services: []
|
||||
- 10.0.0.95 [b8:27:eb:88:3a:41] (RaspberryPiF_88:3a:41): Ports [22, 53, 443, 2049, 5900], Services: ['DNS', 'SSH', 'NFS', 'VNC', 'Web Server']
|
||||
- 10.0.0.204 [50:eb:f6:56:f3:26] (ASUSTekCOMPU_56:f3:26): Ports [22, 3389, 445, 5900, 11434], Services: ['SSH', 'VNC', 'SMB/CIFS (Possible Windows/AD)', 'RDP (Windows)', 'Ollama']
|
||||
- 10.0.0.1\ [9c:57:bc:5d:50:f2] (eero_5d:50:f2): Ports [], Services: []
|
||||
- 10.0.0.123 [3c:ef:8c:96:e3:3c] (ZhejiangDahu_96:e3:3c): Ports [80], Services: ['Web Server']
|
||||
- 10.0.0.124 [9c:8e:cd:02:73:c4] (AmcrestTechn_02:73:c4): Ports [80], Services: ['Web Server']
|
||||
- 10.0.0.111 [ca:0b:6c:5d:0a:e5] (ca:0b:6c:5d:0a:e5): Ports [], Services: []
|
||||
- 10.0.0.127 [58:55:ca:4a:60:6e] (Apple_4a:60:6e): Ports [22], Services: ['SSH']
|
||||
- 10.0.0.117 [40:f5:20:1e:5e:91] (Espressif_1e:5e:91): Ports [80], Services: ['Web Server']
|
||||
- 10.0.0.113 [60:81:10:92:02:4e] (Apple_92:02:4e): Ports [], Services: []
|
||||
- 10.0.0.107 [b8:06:0d:b7:7c:56] (TuyaSmart_b7:7c:56): Ports [], Services: []
|
||||
- 10.0.0.112 [f8:33:31:40:58:c0] (TexasInstrum_40:58:c0): Ports [80, 443], Services: ['Web Server']
|
||||
- 10.0.0.130 [f8:bb:bf:a3:84:eb] (eero_a3:84:eb): Ports [53], Services: ['DNS']
|
||||
- 10.0.0.125 [a0:60:32:04:73:ba] (AmcrestTechn_04:73:ba): Ports [80], Services: ['Web Server']
|
||||
- 10.0.0.205 [a8:20:66:28:12:e7] (Apple_28:12:e7): Ports [22, 445, 5900, 88], Services: ['SSH', 'VNC', 'SMB/CIFS (Possible Windows/AD)', 'Active Directory Related']
|
||||
- 10.0.0.143 [60:5f:8d:7a:aa:32] (eero_7a:aa:32): Ports [53], Services: ['DNS']
|
||||
- 10.0.0.145 [7c:a6:b0:04:db:1c] (7c:a6:b0:04:db:1c): Ports [], Services: []
|
||||
- 10.0.0.128 [20:c9:d0:94:30:dd] (Apple_94:30:dd): Ports [], Services: []
|
||||
- 10.0.0.155 [62:17:97:b3:06:a1] (62:17:97:b3:06:a1): Ports [], Services: []
|
||||
- 10.0.0.170 [b0:ee:7b:ca:73:99] (Roku_ca:73:99): Ports [], Services: []
|
||||
- 10.0.0.179 [48:a6:b8:a4:8e:cc] (Sonos_a4:8e:cc): Ports [], Services: []
|
||||
- 10.0.0.180 [4c:e1:73:42:1a:be] (HuizhouDehon_2:1a:be): Ports [445], Services: ['SMB/CIFS (Possible Windows/AD)']
|
||||
- 10.0.0.189 [00:17:88:a3:2f:cc] (PhilipsLight_a3:2f:cc): Ports [80, 443], Services: ['Web Server']
|
||||
- 10.0.0.188 [00:16:6c:c5:1f:54] (SamsungElect_c5:1f:54): Ports [80, 443], Services: ['Web Server']
|
||||
- 10.0.0.196 [60:5f:8d:88:08:f2] (eero_88:08:f2): Ports [53], Services: ['DNS']
|
||||
- 10.0.0.175 [28:80:88:e4:10:1a] (Netgear_e4:10:1a): Ports [80], Services: ['Web Server']
|
||||
- 10.0.0.199 [7c:a6:b0:01:a7:33] (7c:a6:b0:01:a7:33): Ports [], Services: []
|
||||
- 10.0.0.206 [00:a0:de:a2:0b:ef] (Yamaha_a2:0b:ef): Ports [80], Services: ['Web Server']
|
||||
- 10.0.0.208 [a0:ad:9f:30:84:5f] (ASUSTekCOMPU_30:84:5f): Ports [], Services: []
|
||||
Ollama Instances found at: 10.0.0.38, 10.0.0.204
|
||||
|
||||
Ansible Inventory Summary:
|
||||
Inventory directory: /Users/chrisfu/dev/prole/infrastructure
|
||||
Hosts detected: 6
|
||||
- merlin (10.0.0.36): roles [merlin_bootstrap]
|
||||
- merlin.prole.org (unknown): roles [iscsi, k3s_agents, k3s_hosts, linux_hosts, mariadb, mariadb_primary]
|
||||
- myrddin.prole.org (unknown): roles [ad_dc, iscsi, k3s_hosts, k3s_servers, linux_hosts, ssl_hosts]
|
||||
- pi.prole.org (unknown): roles [iscsi, k3s_agents, k3s_hosts, linux_hosts, pihole]
|
||||
- raspberry.prole.org (unknown): roles [iscsi, linux_hosts, mariadb, mariadb_replica, pihole]
|
||||
- retropie.prole.org (unknown): roles [iscsi, linux_hosts]
|
||||
Flat inventory file: /Users/chrisfu/dev/prole/scan/ansible_inventory_flat.txt
|
||||
@ -1219,7 +1219,7 @@ ensure_k8s_supabase_static_pvs() {
|
||||
if [[ "${MODE:-}" != "k8s" ]]; then
|
||||
return 0
|
||||
fi
|
||||
if [[ -z "${storage_class:-}" || "$storage_class" != "prole-iscsi" ]]; then
|
||||
if [[ -z "${storage_class:-}" || "$storage_class" != "synology-iscsi" ]]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
@ -1227,7 +1227,7 @@ ensure_k8s_supabase_static_pvs() {
|
||||
|
||||
local node base parent base_name
|
||||
node="${SUPABASE_PV_NODE:-myrddin.prole.org}"
|
||||
base="${SUPABASE_PV_BASE_DIR:-/prole/d002/supabase}"
|
||||
base="${SUPABASE_PV_BASE_DIR:-/synology/d002/supabase}"
|
||||
base="${base%/}"
|
||||
parent="$(dirname "$base")"
|
||||
base_name="$(basename "$base")"
|
||||
@ -1298,12 +1298,12 @@ EOF
|
||||
# Static local PVs with Retain reclaimPolicy can get stuck in Released after a namespace reset.
|
||||
# Delete Released PV objects so they can be recreated and rebound to the new PVCs.
|
||||
local pvs=(
|
||||
prole-supabase-db
|
||||
prole-supabase-deno
|
||||
prole-supabase-functions
|
||||
prole-supabase-imgproxy
|
||||
prole-supabase-snippets
|
||||
prole-supabase-storage
|
||||
synology-supabase-db
|
||||
synology-supabase-deno
|
||||
synology-supabase-functions
|
||||
synology-supabase-imgproxy
|
||||
synology-supabase-snippets
|
||||
synology-supabase-storage
|
||||
)
|
||||
local pv
|
||||
for pv in "${pvs[@]}"; do
|
||||
@ -1320,9 +1320,9 @@ EOF
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: prole-supabase-db
|
||||
name: synology-supabase-db
|
||||
labels:
|
||||
prole.storage/pvc: supabase-db
|
||||
synology.storage/pvc: supabase-db
|
||||
spec:
|
||||
capacity:
|
||||
storage: 5Gi
|
||||
@ -1345,9 +1345,9 @@ spec:
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: prole-supabase-deno
|
||||
name: synology-supabase-deno
|
||||
labels:
|
||||
prole.storage/pvc: supabase-deno
|
||||
synology.storage/pvc: supabase-deno
|
||||
spec:
|
||||
capacity:
|
||||
storage: 1Gi
|
||||
@ -1370,9 +1370,9 @@ spec:
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: prole-supabase-functions
|
||||
name: synology-supabase-functions
|
||||
labels:
|
||||
prole.storage/pvc: supabase-functions
|
||||
synology.storage/pvc: supabase-functions
|
||||
spec:
|
||||
capacity:
|
||||
storage: 1Gi
|
||||
@ -1395,9 +1395,9 @@ spec:
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: prole-supabase-imgproxy
|
||||
name: synology-supabase-imgproxy
|
||||
labels:
|
||||
prole.storage/pvc: supabase-imgproxy
|
||||
synology.storage/pvc: supabase-imgproxy
|
||||
spec:
|
||||
capacity:
|
||||
storage: 1Gi
|
||||
@ -1420,9 +1420,9 @@ spec:
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: prole-supabase-snippets
|
||||
name: synology-supabase-snippets
|
||||
labels:
|
||||
prole.storage/pvc: supabase-snippets
|
||||
synology.storage/pvc: supabase-snippets
|
||||
spec:
|
||||
capacity:
|
||||
storage: 1Gi
|
||||
@ -1445,9 +1445,9 @@ spec:
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: prole-supabase-storage
|
||||
name: synology-supabase-storage
|
||||
labels:
|
||||
prole.storage/pvc: supabase-storage
|
||||
synology.storage/pvc: supabase-storage
|
||||
spec:
|
||||
capacity:
|
||||
storage: 1Gi
|
||||
@ -1513,7 +1513,7 @@ PY
|
||||
local storage_class
|
||||
storage_class="${SUPABASE_STORAGE_CLASS:-}"
|
||||
if [[ -z "$storage_class" && "$MODE" == "k8s" ]]; then
|
||||
storage_class="prole-iscsi"
|
||||
storage_class="synology-iscsi"
|
||||
fi
|
||||
|
||||
ensure_k8s_supabase_static_pvs "$storage_class"
|
||||
|
||||
@ -34,7 +34,7 @@ metadata:
|
||||
name: {{ $pvcName }}
|
||||
labels:
|
||||
{{- include "supabase.labels" $root | nindent 4 }}
|
||||
prole.storage/pvc: {{ $pvcName | quote }}
|
||||
synology.storage/pvc: {{ $pvcName | quote }}
|
||||
{{- with $persistence.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
@ -43,10 +43,10 @@ spec:
|
||||
{{- if $persistence.storageClassName }}
|
||||
storageClassName: {{ $persistence.storageClassName }}
|
||||
{{- end }}
|
||||
{{- if eq ($persistence.storageClassName | default "") "prole-iscsi" }}
|
||||
{{- if eq ($persistence.storageClassName | default "") "synology-iscsi" }}
|
||||
selector:
|
||||
matchLabels:
|
||||
prole.storage/pvc: {{ $pvcName | quote }}
|
||||
synology.storage/pvc: {{ $pvcName | quote }}
|
||||
{{- end }}
|
||||
accessModes:
|
||||
{{- range $persistence.accessModes }}
|
||||
|
||||
@ -4,7 +4,7 @@ set -euo pipefail
|
||||
|
||||
# Regression tests for k3s CNPG storage guardrails in etc/init_cloudnative_pg.sh
|
||||
# - must fail if protected mounts are root-backed
|
||||
# - must fail if manifest lacks explicit prole-iscsi + selector labels (prevents local-path fallback)
|
||||
# - must fail if manifest lacks explicit synology-iscsi + selector labels (prevents local-path fallback)
|
||||
# - must succeed (with mocks) when mounts + manifest + runtime objects are correct
|
||||
|
||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||
@ -139,9 +139,13 @@ if [[ "$args" == *"get nodes"*"--no-headers"* ]]; then
|
||||
fi
|
||||
|
||||
# Runtime validation calls
|
||||
if [[ "$args" == *" get cluster prole-db -o jsonpath="* ]]; then
|
||||
# Return empty imageName so _cnpg_current_image_name sees no prior image.
|
||||
exit 0
|
||||
fi
|
||||
if [[ "$args" == *" get cluster prole-db -o json"* ]]; then
|
||||
cat <<JSON
|
||||
{"apiVersion":"postgresql.cnpg.io/v1","kind":"Cluster","metadata":{"name":"prole-db"},"spec":{"storage":{"pvcTemplate":{"storageClassName":"prole-iscsi","selector":{"matchLabels":{"prole.storage/role":"data"}}}},"walStorage":{"pvcTemplate":{"storageClassName":"prole-iscsi","selector":{"matchLabels":{"prole.storage/role":"wal"}}}}}}
|
||||
{"apiVersion":"postgresql.cnpg.io/v1","kind":"Cluster","metadata":{"name":"prole-db"},"spec":{"storage":{"pvcTemplate":{"storageClassName":"synology-iscsi","selector":{"matchLabels":{"synology.storage/role":"data"}}}},"walStorage":{"pvcTemplate":{"storageClassName":"synology-iscsi","selector":{"matchLabels":{"synology.storage/role":"wal"}}}}}}
|
||||
JSON
|
||||
exit 0
|
||||
fi
|
||||
@ -149,19 +153,19 @@ fi
|
||||
if [[ "$args" == *" get pvc"*"cnpg.io/cluster=prole-db"*"-o json"* ]]; then
|
||||
cat <<JSON
|
||||
{"items":[
|
||||
{"metadata":{"name":"prole-db-1"},"spec":{"storageClassName":"prole-iscsi","volumeName":"pv-data"}},
|
||||
{"metadata":{"name":"prole-db-wal"},"spec":{"storageClassName":"prole-iscsi","volumeName":"pv-wal"}}
|
||||
{"metadata":{"name":"prole-db-1"},"spec":{"storageClassName":"synology-iscsi","volumeName":"pv-data"}},
|
||||
{"metadata":{"name":"prole-db-wal"},"spec":{"storageClassName":"synology-iscsi","volumeName":"pv-wal"}}
|
||||
]}
|
||||
JSON
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ "$args" == "get pv pv-data -o json"* ]]; then
|
||||
echo '{"spec":{"storageClassName":"prole-iscsi","local":{"path":"/prole/d001/data"}}}'
|
||||
echo '{"spec":{"storageClassName":"synology-iscsi","local":{"path":"/synology/d001/data"}}}'
|
||||
exit 0
|
||||
fi
|
||||
if [[ "$args" == "get pv pv-wal -o json"* ]]; then
|
||||
echo '{"spec":{"storageClassName":"prole-iscsi","local":{"path":"/prole/d001/wal"}}}'
|
||||
echo '{"spec":{"storageClassName":"synology-iscsi","local":{"path":"/synology/d001/wal"}}}'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
@ -248,16 +252,16 @@ metadata:
|
||||
spec:
|
||||
storage:
|
||||
pvcTemplate:
|
||||
storageClassName: prole-iscsi
|
||||
storageClassName: synology-iscsi
|
||||
selector:
|
||||
matchLabels:
|
||||
prole.storage/role: data
|
||||
synology.storage/role: data
|
||||
walStorage:
|
||||
pvcTemplate:
|
||||
storageClassName: prole-iscsi
|
||||
storageClassName: synology-iscsi
|
||||
selector:
|
||||
matchLabels:
|
||||
prole.storage/role: wal
|
||||
synology.storage/role: wal
|
||||
EOF
|
||||
|
||||
export PROLE_TEST_FINDMNT_DATA_SRC="/dev/root"
|
||||
@ -300,19 +304,19 @@ spec:
|
||||
instances: 1
|
||||
storage:
|
||||
pvcTemplate:
|
||||
storageClassName: prole-iscsi
|
||||
storageClassName: synology-iscsi
|
||||
selector:
|
||||
matchLabels:
|
||||
prole.storage/role: data
|
||||
synology.storage/role: data
|
||||
resources:
|
||||
requests:
|
||||
storage: 29Gi
|
||||
walStorage:
|
||||
pvcTemplate:
|
||||
storageClassName: prole-iscsi
|
||||
storageClassName: synology-iscsi
|
||||
selector:
|
||||
matchLabels:
|
||||
prole.storage/role: wal
|
||||
synology.storage/role: wal
|
||||
resources:
|
||||
requests:
|
||||
storage: 29Gi
|
||||
|
||||
266
tests/etc/test_init_cloudnative_pg_image_policy.sh
Normal file
266
tests/etc/test_init_cloudnative_pg_image_policy.sh
Normal file
@ -0,0 +1,266 @@
|
||||
#!/usr/bin/env bash
|
||||
# Unit tests for etc/init_cloudnative_pg.sh image policy behavior:
|
||||
# - no-op when desired image already deployed
|
||||
# - fail early on version mismatch without --upgrade (before namespace creation)
|
||||
# - on --upgrade + mismatch, trigger a rollout/restart hook
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||
REPO_ROOT=$(cd "$SCRIPT_DIR/../.." && pwd)
|
||||
SCRIPT_UNDER_TEST="$REPO_ROOT/etc/init_cloudnative_pg.sh"
|
||||
|
||||
TMP_DIR=$(mktemp -d)
|
||||
trap 'rm -rf "$TMP_DIR"' EXIT
|
||||
|
||||
BIN_DIR="$TMP_DIR/bin"
|
||||
mkdir -p "$BIN_DIR"
|
||||
|
||||
MOCK_LOG="$TMP_DIR/mock_calls.log"
|
||||
|
||||
cat <<'K_EOF' > "$BIN_DIR/kubectl"
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
echo "Mocked kubectl called with $@" >> "${MOCK_LOG:-/tmp/mock_calls.log}"
|
||||
|
||||
args="$*"
|
||||
|
||||
if [[ "$args" == *"get --raw=/readyz"* || "$args" == *"get --raw='/readyz'"* || "$args" == *"get --raw=\"/readyz\""* ]]; then
|
||||
echo "ok"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ "$args" == *"version --short"* ]]; then
|
||||
echo "Client Version: v0.0.0"
|
||||
echo "Server Version: v0.0.0"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# CNPG webhook wait: return an endpoint IP so the wait loop passes.
|
||||
if [[ "$args" == *"get endpoints"*"cnpg-webhook-service"* ]]; then
|
||||
echo "10.42.0.10"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ "$args" == *"get endpoints barman-cloud"* ]]; then
|
||||
echo "10.42.0.11"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Barman plugin service registration: return a service name for label-based lookups.
|
||||
if [[ "$args" == *"get svc"*"-l cnpg.io/pluginName=barman-cloud.cloudnative-pg.io"*"-o jsonpath="* ]]; then
|
||||
echo "barman-cloud"
|
||||
exit 0
|
||||
fi
|
||||
if [[ "$args" == *"get svc barman-cloud"*"-o jsonpath="*".metadata.name"* ]]; then
|
||||
echo "barman-cloud"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ "$args" == *"get svc barman-cloud"*"-o jsonpath="*"pluginClientSecret"* ]]; then
|
||||
echo "barman-cloud-client-tls"
|
||||
exit 0
|
||||
fi
|
||||
if [[ "$args" == *"get svc barman-cloud"*"-o jsonpath="*"pluginServerSecret"* ]]; then
|
||||
echo "barman-cloud-server-tls"
|
||||
exit 0
|
||||
fi
|
||||
if [[ "$args" == *"get svc barman-cloud"*"-o jsonpath="*"pluginPort"* ]]; then
|
||||
echo "443"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ "$args" == *"get namespace"* ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ "$args" == *"create namespace"* ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ "$args" == *"get cluster"*"-o jsonpath="*".spec.imageName"* ]]; then
|
||||
echo "${MOCK_CLUSTER_IMAGE:-}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ "$args" == *"get cluster"* ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ "$args" == *"patch cluster"* ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ "$args" == *"cnpg version"* ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ "$args" == *"cnpg restart"* ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ "$args" == *"apply"* ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ "$args" == *"get secret"* ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
exit 0
|
||||
K_EOF
|
||||
chmod +x "$BIN_DIR/kubectl"
|
||||
|
||||
mock_ok_tool() {
|
||||
cat <<M_EOF > "$BIN_DIR/$1"
|
||||
#!/usr/bin/env bash
|
||||
echo "Mocked $1 called with \$@" >> "${MOCK_LOG:-/tmp/mock_calls.log}"
|
||||
exit 0
|
||||
M_EOF
|
||||
chmod +x "$BIN_DIR/$1"
|
||||
}
|
||||
|
||||
# Prevent accidental real calls during tests.
|
||||
mock_ok_tool docker
|
||||
mock_ok_tool k3d
|
||||
mock_ok_tool curl
|
||||
mock_ok_tool jq
|
||||
mock_ok_tool skopeo
|
||||
|
||||
export PATH="$BIN_DIR:$PATH"
|
||||
export MOCK_LOG
|
||||
|
||||
CONF_DIR="$TMP_DIR/conf"
|
||||
mkdir -p "$CONF_DIR"
|
||||
|
||||
SERVICE_DIR="$TMP_DIR/service"
|
||||
mkdir -p "$SERVICE_DIR/secrets"
|
||||
printf '%s' "dummy-private-key" > "$SERVICE_DIR/secrets/admin.key"
|
||||
printf '%s' "dummy-public-key" > "$SERVICE_DIR/secrets/admin.pub"
|
||||
|
||||
write_cfg() {
|
||||
local prole_home_val="$1"
|
||||
cat <<C_EOF > "$CONF_DIR/prole.cfg"
|
||||
[User]
|
||||
NAMESPACE = test-ns
|
||||
SERVICE_NAMESPACE = test-system
|
||||
PROLE_HOME = ${prole_home_val}
|
||||
PROLE_SERVICE = ${SERVICE_DIR}
|
||||
|
||||
[Global]
|
||||
DEPLOYMENT_MODE = k3d
|
||||
|
||||
[Docker Build]
|
||||
LOCAL_REGISTRY = localhost:5000
|
||||
LOCAL_REGISTRY_INTERNAL = k3d-prole-registry:5000
|
||||
C_EOF
|
||||
}
|
||||
|
||||
reset_log() {
|
||||
: > "$MOCK_LOG"
|
||||
}
|
||||
|
||||
assert_not_called() {
|
||||
local needle="$1"
|
||||
if grep -q "$needle" "$MOCK_LOG"; then
|
||||
echo "FAILURE: expected not to see '$needle' in mock log"
|
||||
sed -n '1,200p' "$MOCK_LOG" || true
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
assert_called() {
|
||||
local needle="$1"
|
||||
if ! grep -q "$needle" "$MOCK_LOG"; then
|
||||
echo "FAILURE: expected to see '$needle' in mock log"
|
||||
sed -n '1,200p' "$MOCK_LOG" || true
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
run_case() {
|
||||
local name="$1"; shift
|
||||
local expected_rc="$1"; shift
|
||||
|
||||
reset_log
|
||||
local out="$TMP_DIR/${name}.out"
|
||||
local err="$TMP_DIR/${name}.err"
|
||||
|
||||
set +e
|
||||
"$@" >"$out" 2>"$err"
|
||||
local rc=$?
|
||||
set -e
|
||||
|
||||
if [[ "$rc" != "$expected_rc" ]]; then
|
||||
echo "FAILURE: $name expected RC=$expected_rc got RC=$rc"
|
||||
echo "--- stdout ---"
|
||||
sed -n '1,200p' "$out" || true
|
||||
echo "--- stderr ---"
|
||||
sed -n '1,200p' "$err" || true
|
||||
echo "--- mock log ---"
|
||||
sed -n '1,200p' "$MOCK_LOG" || true
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
###############################################
|
||||
# Case 1: no-op on same image (initialize)
|
||||
###############################################
|
||||
|
||||
export PROLE_CONF="$CONF_DIR"
|
||||
export PROLE_SERVICE="$SERVICE_DIR"
|
||||
|
||||
write_cfg "$REPO_ROOT"
|
||||
|
||||
export MOCK_CLUSTER_IMAGE="k3d-prole-registry:5000/knoe-db:18-140"
|
||||
|
||||
run_case "noop_initialize" 0 \
|
||||
bash "$SCRIPT_UNDER_TEST" --mode k3d --namespace test-ns initialize prole-db 18-140
|
||||
|
||||
assert_not_called "create namespace"
|
||||
|
||||
###############################################
|
||||
# Case 2: mismatch without --upgrade fails early
|
||||
###############################################
|
||||
|
||||
export MOCK_CLUSTER_IMAGE="k3d-prole-registry:5000/knoe-db:18-138"
|
||||
|
||||
run_case "mismatch_initialize" 1 \
|
||||
bash "$SCRIPT_UNDER_TEST" --mode k3d --namespace test-ns initialize prole-db 18-140
|
||||
|
||||
assert_not_called "create namespace"
|
||||
|
||||
###############################################
|
||||
# Case 3: mismatch with --upgrade triggers restart hook (deploy)
|
||||
###############################################
|
||||
|
||||
PROLE_HOME_UPGRADE="$TMP_DIR/prole_home"
|
||||
mkdir -p "$PROLE_HOME_UPGRADE/deploy/opentofu/k3s/manifests/prole"
|
||||
cat <<'Y_EOF' > "$PROLE_HOME_UPGRADE/deploy/opentofu/k3s/manifests/prole/prole-db.yaml"
|
||||
apiVersion: postgresql.cnpg.io/v1
|
||||
kind: Cluster
|
||||
metadata:
|
||||
name: prole-db
|
||||
spec:
|
||||
instances: 1
|
||||
imageName: knoe-db:dummy
|
||||
Y_EOF
|
||||
cat <<'Y_EOF' > "$PROLE_HOME_UPGRADE/deploy/opentofu/k3s/manifests/prole/prole-db-barman-objectstore.yaml"
|
||||
apiVersion: postgresql.cnpg.io/v1
|
||||
kind: ObjectStore
|
||||
metadata:
|
||||
name: prole-db
|
||||
spec: {}
|
||||
Y_EOF
|
||||
|
||||
write_cfg "$PROLE_HOME_UPGRADE"
|
||||
|
||||
export MOCK_CLUSTER_IMAGE="k3d-prole-registry:5000/knoe-db:18-138"
|
||||
|
||||
run_case "upgrade_deploy" 0 \
|
||||
bash "$SCRIPT_UNDER_TEST" --mode k3d --namespace test-ns --upgrade deploy 18-140
|
||||
|
||||
assert_called "cnpg restart"
|
||||
|
||||
echo "SUCCESS"
|
||||
@ -136,25 +136,25 @@ fi
|
||||
# Runtime storage validation (k3s) expects live Cluster + PVC/PV objects.
|
||||
if [[ "${args}" == *"-n test-ns"*"get cluster"*"prole-db"*"-o json"* ]]; then
|
||||
cat <<'JSON'
|
||||
{"apiVersion":"postgresql.cnpg.io/v1","kind":"Cluster","metadata":{"name":"prole-db"},"spec":{"storage":{"pvcTemplate":{"storageClassName":"prole-iscsi","selector":{"matchLabels":{"prole.storage/role":"data"}}}},"walStorage":{"pvcTemplate":{"storageClassName":"prole-iscsi","selector":{"matchLabels":{"prole.storage/role":"wal"}}}}}}
|
||||
{"apiVersion":"postgresql.cnpg.io/v1","kind":"Cluster","metadata":{"name":"prole-db"},"spec":{"storage":{"pvcTemplate":{"storageClassName":"synology-iscsi","selector":{"matchLabels":{"synology.storage/role":"data"}}}},"walStorage":{"pvcTemplate":{"storageClassName":"synology-iscsi","selector":{"matchLabels":{"synology.storage/role":"wal"}}}}}}
|
||||
JSON
|
||||
exit 0
|
||||
fi
|
||||
if [[ "${args}" == *"-n test-ns"*"get pvc"*"cnpg.io/cluster=prole-db"*"-o json"* ]]; then
|
||||
cat <<'JSON'
|
||||
{"items":[
|
||||
{"metadata":{"name":"prole-db-1"},"spec":{"storageClassName":"prole-iscsi","volumeName":"pv-data"}},
|
||||
{"metadata":{"name":"prole-db-1-wal"},"spec":{"storageClassName":"prole-iscsi","volumeName":"pv-wal"}}
|
||||
{"metadata":{"name":"prole-db-1"},"spec":{"storageClassName":"synology-iscsi","volumeName":"pv-data"}},
|
||||
{"metadata":{"name":"prole-db-1-wal"},"spec":{"storageClassName":"synology-iscsi","volumeName":"pv-wal"}}
|
||||
]}
|
||||
JSON
|
||||
exit 0
|
||||
fi
|
||||
if [[ "${args}" == "get pv pv-data -o json"* ]]; then
|
||||
echo '{"spec":{"storageClassName":"prole-iscsi","local":{"path":"/prole/d001/data"}}}'
|
||||
echo '{"spec":{"storageClassName":"synology-iscsi","local":{"path":"/synology/d001/data"}}}'
|
||||
exit 0
|
||||
fi
|
||||
if [[ "${args}" == "get pv pv-wal -o json"* ]]; then
|
||||
echo '{"spec":{"storageClassName":"prole-iscsi","local":{"path":"/prole/d001/wal"}}}'
|
||||
echo '{"spec":{"storageClassName":"synology-iscsi","local":{"path":"/synology/d001/wal"}}}'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
@ -279,13 +279,18 @@ if grep -qE '^\s*- key:\s*kubernetes\\.io/hostname\s*$|myrddin\\.prole\\.org' "$
|
||||
sed -n '1,160p' "$TMP_DIR/applied.yaml" || true
|
||||
exit 1
|
||||
fi
|
||||
if ! grep -qE '^\s*- key:\s*prole\.org/node-role\s*$' "$TMP_DIR/applied.yaml"; then
|
||||
echo "FAILURE: expected node-role label affinity in applied manifest (default)"
|
||||
if ! grep -qE '^\s*- key:\s*node\.kubernetes\.io/instance-type\s*$' "$TMP_DIR/applied.yaml"; then
|
||||
echo "FAILURE: expected k3s instance-type node affinity in applied manifest (default)"
|
||||
sed -n '1,160p' "$TMP_DIR/applied.yaml" || true
|
||||
exit 1
|
||||
fi
|
||||
if ! grep -qE '^\s*podAntiAffinityType:\s*required\s*$' "$TMP_DIR/applied.yaml"; then
|
||||
echo "FAILURE: expected podAntiAffinityType=required in applied manifest (default)"
|
||||
if ! grep -qE '^\s*- k3s\s*$' "$TMP_DIR/applied.yaml"; then
|
||||
echo "FAILURE: expected node affinity value k3s in applied manifest (default)"
|
||||
sed -n '1,160p' "$TMP_DIR/applied.yaml" || true
|
||||
exit 1
|
||||
fi
|
||||
if ! grep -qE '^\s*podAntiAffinityType:\s*preferred\s*$' "$TMP_DIR/applied.yaml"; then
|
||||
echo "FAILURE: expected podAntiAffinityType=preferred in applied manifest (default)"
|
||||
sed -n '1,160p' "$TMP_DIR/applied.yaml" || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
155
tests/etc/test_init_cloudnative_pg_k3d_k3s_registry_cache.sh
Normal file
155
tests/etc/test_init_cloudnative_pg_k3d_k3s_registry_cache.sh
Normal file
@ -0,0 +1,155 @@
|
||||
#!/usr/bin/env bash
|
||||
# Regression test: in k3d mode, init_cloudnative_pg.sh should consult the k3s registry
|
||||
# as an optional cache/source before falling back to a local build.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||
REPO_ROOT=$(cd "$SCRIPT_DIR/../.." && pwd)
|
||||
ETC_DIR="$REPO_ROOT/etc"
|
||||
SCRIPT_UNDER_TEST="$ETC_DIR/init_cloudnative_pg.sh"
|
||||
|
||||
TMP_DIR=$(mktemp -d)
|
||||
trap 'rm -rf "$TMP_DIR"' EXIT
|
||||
|
||||
BIN_DIR="$TMP_DIR/bin"
|
||||
mkdir -p "$BIN_DIR"
|
||||
|
||||
_log_file="$TMP_DIR/mock_calls.log"
|
||||
export MOCK_LOG_FILE="$_log_file"
|
||||
|
||||
# Minimal kubectl mock so preflight-image path doesn't hang.
|
||||
cat <<'K_EOF' > "$BIN_DIR/kubectl"
|
||||
#!/usr/bin/env bash
|
||||
echo "Mocked kubectl called with $*" >> "${MOCK_LOG_FILE}"
|
||||
args="$*"
|
||||
if [[ "${args}" == *"get --raw=/readyz"* || "${args}" == *"get --raw='/readyz'"* || "${args}" == *"get --raw=\"/readyz\""* ]]; then
|
||||
echo "ok"
|
||||
exit 0
|
||||
fi
|
||||
if [[ "${args}" == *"version --short"* ]]; then
|
||||
echo "Client Version: v0.0.0"
|
||||
echo "Server Version: v0.0.0"
|
||||
exit 0
|
||||
fi
|
||||
exit 0
|
||||
K_EOF
|
||||
chmod +x "$BIN_DIR/kubectl"
|
||||
|
||||
# docker mock: pretend local images are missing, but the k3s registry has the image.
|
||||
cat <<'D_EOF' > "$BIN_DIR/docker"
|
||||
#!/usr/bin/env bash
|
||||
echo "Mocked docker called with $*" >> "${MOCK_LOG_FILE}"
|
||||
|
||||
cmd1="${1:-}"
|
||||
cmd2="${2:-}"
|
||||
cmd3="${3:-}"
|
||||
|
||||
if [[ "$cmd1" == "image" && "$cmd2" == "inspect" ]]; then
|
||||
# Force local inspect misses so the script tries the k3s registry.
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$cmd1" == "pull" ]]; then
|
||||
# Succeed only for the expected k3s registry ref.
|
||||
if [[ "$cmd2" == myrddin.prole.org:5000/knoe-db:* ]]; then
|
||||
exit 0
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$cmd1" == "build" || ( "$cmd1" == "buildx" && "$cmd2" == "build" ) ]]; then
|
||||
echo "FAILURE: docker build should not be invoked when k3s registry contains the image" >&2
|
||||
exit 99
|
||||
fi
|
||||
|
||||
exit 0
|
||||
D_EOF
|
||||
chmod +x "$BIN_DIR/docker"
|
||||
|
||||
# k3d mock: allow cluster list without failing; we assert we don't need image import when push succeeds.
|
||||
cat <<'K3D_EOF' > "$BIN_DIR/k3d"
|
||||
#!/usr/bin/env bash
|
||||
echo "Mocked k3d called with $*" >> "${MOCK_LOG_FILE}"
|
||||
if [[ "${1:-}" == "cluster" && "${2:-}" == "list" ]]; then
|
||||
echo "knoe-dev-cluster"
|
||||
exit 0
|
||||
fi
|
||||
exit 0
|
||||
K3D_EOF
|
||||
chmod +x "$BIN_DIR/k3d"
|
||||
|
||||
# Other mocks used by the script in various branches.
|
||||
for t in curl skopeo ansible-playbook tofu terraform ollama jq; do
|
||||
cat <<M_EOF > "$BIN_DIR/$t"
|
||||
#!/usr/bin/env bash
|
||||
echo "Mocked $t called with \$@" >> "${_log_file}"
|
||||
exit 0
|
||||
M_EOF
|
||||
chmod +x "$BIN_DIR/$t"
|
||||
done
|
||||
|
||||
# Mock prole.cfg for k3d mode.
|
||||
mkdir -p "$TMP_DIR/conf"
|
||||
cat <<C_EOF > "$TMP_DIR/conf/prole.cfg"
|
||||
[User]
|
||||
NAMESPACE = test-ns
|
||||
SERVICE_NAMESPACE = test-system
|
||||
PROLE_HOME = $REPO_ROOT
|
||||
PROLE_SERVICE = $TMP_DIR/service
|
||||
|
||||
[Global]
|
||||
DEPLOYMENT_MODE = k3d
|
||||
|
||||
[Docker Build]
|
||||
LOCAL_REGISTRY = localhost:5000
|
||||
LOCAL_REGISTRY_INTERNAL = k3d-prole-registry.localhost:5000
|
||||
C_EOF
|
||||
|
||||
mkdir -p "$TMP_DIR/service/secrets"
|
||||
printf '%s' "dummy-private-key" > "$TMP_DIR/service/secrets/admin.key"
|
||||
printf '%s' "dummy-public-key" > "$TMP_DIR/service/secrets/admin.pub"
|
||||
|
||||
export PATH="$BIN_DIR:$PATH"
|
||||
export PROLE_HOME="$REPO_ROOT"
|
||||
export PROLE_CONF="$TMP_DIR/conf"
|
||||
export PROLE_PASSWD="test-password"
|
||||
export PROLE_SERVICE="$TMP_DIR/service"
|
||||
|
||||
# Run a path that triggers image preflight.
|
||||
bash "$SCRIPT_UNDER_TEST" --mode k3d preflight-image > "$TMP_DIR/stdout" 2> "$TMP_DIR/stderr"
|
||||
RC=$?
|
||||
|
||||
# Assertions
|
||||
if ! grep -q "Mocked docker called with pull myrddin.prole.org:5000/knoe-db:" "${_log_file}"; then
|
||||
echo "FAILURE: expected a k3s-registry pull attempt in k3d mode" >&2
|
||||
echo "--- mock calls ---" >&2
|
||||
sed -n '1,200p' "${_log_file}" >&2 || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if grep -q "Mocked docker called with build" "${_log_file}"; then
|
||||
echo "FAILURE: did not expect docker build to run when cache image is present" >&2
|
||||
echo "--- mock calls ---" >&2
|
||||
sed -n '1,200p' "${_log_file}" >&2 || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if grep -q "Mocked k3d called with image import" "${_log_file}"; then
|
||||
echo "FAILURE: expected registry push path, not k3d image import fallback" >&2
|
||||
echo "--- mock calls ---" >&2
|
||||
sed -n '1,200p' "${_log_file}" >&2 || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ $RC -eq 0 || $RC -eq 1 || $RC -eq 2 ]]; then
|
||||
echo "SUCCESS (RC=$RC)"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "FAILURE with RC $RC" >&2
|
||||
echo "--- stdout ---" >&2
|
||||
sed -n '1,200p' "$TMP_DIR/stdout" >&2 || true
|
||||
echo "--- stderr ---" >&2
|
||||
sed -n '1,200p' "$TMP_DIR/stderr" >&2 || true
|
||||
exit 1
|
||||
@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
# Regression test: Garage startup should auto-recycle a Released prole-iscsi PV with a stale
|
||||
# Regression test: Garage startup should auto-recycle a Released synology-iscsi PV with a stale
|
||||
# claimRef when the PVC is Pending and rollout is stuck beyond the initial timeout.
|
||||
|
||||
set -euo pipefail
|
||||
@ -23,7 +23,7 @@ cp "$SOURCE_ETC_DIR/prole_cfg.sh" "$WORK_DIR/etc/prole_cfg.sh"
|
||||
chmod +x "$WORK_DIR/etc/init_garage_store.sh"
|
||||
|
||||
# Dummy manifests required by init_garage_store.sh
|
||||
for f in storageclass-prole-iscsi.yaml iscsi-pvs.yaml garage-configmap.yaml garage-statefulset.yaml garage-service.yaml; do
|
||||
for f in storageclass-synology-iscsi.yaml iscsi-pvs.yaml garage-configmap.yaml garage-statefulset.yaml garage-service.yaml; do
|
||||
printf '%s\n' "apiVersion: v1" > "$WORK_DIR/k8s/prole/$f"
|
||||
done
|
||||
|
||||
@ -86,7 +86,7 @@ case "$sub" in
|
||||
# PV list for recycle helper
|
||||
if [[ "$*" == *"get pv"*"-o jsonpath="* ]]; then
|
||||
printf '%s\t%s\t%s\t%s\t%s\t%s\t%s\n' \
|
||||
"prole-iscsi-d001-garage" "prole-iscsi" "Retain" "Released" "test-ns" "data-garage-0" "olduid"
|
||||
"synology-iscsi-d001-garage" "synology-iscsi" "Retain" "Released" "test-ns" "data-garage-0" "olduid"
|
||||
exit 0
|
||||
fi
|
||||
# Pod lookup for init_layout
|
||||
@ -148,7 +148,7 @@ else
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! grep -q "patch pv prole-iscsi-d001-garage" "$KUBECTL_LOG"; then
|
||||
if ! grep -q "patch pv synology-iscsi-d001-garage" "$KUBECTL_LOG"; then
|
||||
echo "FAILURE: expected PV claimRef recycle (kubectl patch pv) was not invoked" >&2
|
||||
echo "--- kubectl log ---" >&2
|
||||
sed -n '1,200p' "$KUBECTL_LOG" >&2 || true
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
# Regression test: OpenBao restart should auto-recycle a Released prole-iscsi PV with a stale
|
||||
# Regression test: OpenBao restart should auto-recycle a Released synology-iscsi PV with a stale
|
||||
# claimRef when the PVC is Pending and rollout is stuck beyond the initial timeout.
|
||||
|
||||
set -euo pipefail
|
||||
@ -77,7 +77,7 @@ case "$sub" in
|
||||
# PV list for recycle helper
|
||||
if [[ "$*" == *"get pv"*"-o jsonpath="* ]]; then
|
||||
printf '%s\t%s\t%s\t%s\t%s\t%s\t%s\n' \
|
||||
"prole-iscsi-d001-openbao" "prole-iscsi" "Retain" "Released" "knoe-system" "data-openbao-0" "olduid"
|
||||
"synology-iscsi-d001-openbao" "synology-iscsi" "Retain" "Released" "knoe-system" "data-openbao-0" "olduid"
|
||||
exit 0
|
||||
fi
|
||||
exit 0
|
||||
@ -116,7 +116,7 @@ else
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! grep -q "patch pv prole-iscsi-d001-openbao" "$KUBECTL_LOG"; then
|
||||
if ! grep -q "patch pv synology-iscsi-d001-openbao" "$KUBECTL_LOG"; then
|
||||
echo "FAILURE: expected PV claimRef recycle (kubectl patch pv) was not invoked" >&2
|
||||
echo "--- kubectl log ---" >&2
|
||||
sed -n '1,200p' "$KUBECTL_LOG" >&2 || true
|
||||
|
||||
@ -53,7 +53,7 @@ def test_repair_flow_classifies_blockers_attempts_reclaim_and_avoids_blind_healt
|
||||
"uid": "new-garage-uid",
|
||||
},
|
||||
"spec": {
|
||||
"storageClassName": "prole-iscsi",
|
||||
"storageClassName": "synology-iscsi",
|
||||
"accessModes": ["ReadWriteOnce"],
|
||||
"resources": {"requests": {"storage": "20Gi"}},
|
||||
},
|
||||
@ -66,7 +66,7 @@ def test_repair_flow_classifies_blockers_attempts_reclaim_and_avoids_blind_healt
|
||||
"uid": "new-bao-uid",
|
||||
},
|
||||
"spec": {
|
||||
"storageClassName": "prole-iscsi",
|
||||
"storageClassName": "synology-iscsi",
|
||||
"accessModes": ["ReadWriteOnce"],
|
||||
"resources": {"requests": {"storage": "20Gi"}},
|
||||
},
|
||||
@ -78,9 +78,9 @@ def test_repair_flow_classifies_blockers_attempts_reclaim_and_avoids_blind_healt
|
||||
return {
|
||||
"items": [
|
||||
{
|
||||
"metadata": {"name": "prole-iscsi-d001-garage"},
|
||||
"metadata": {"name": "synology-iscsi-d001-garage"},
|
||||
"spec": {
|
||||
"storageClassName": "prole-iscsi",
|
||||
"storageClassName": "synology-iscsi",
|
||||
"capacity": {"storage": "20Gi"},
|
||||
"accessModes": ["ReadWriteOnce"],
|
||||
"claimRef": {
|
||||
@ -92,9 +92,9 @@ def test_repair_flow_classifies_blockers_attempts_reclaim_and_avoids_blind_healt
|
||||
"status": {"phase": "Released"},
|
||||
},
|
||||
{
|
||||
"metadata": {"name": "prole-iscsi-d001-openbao"},
|
||||
"metadata": {"name": "synology-iscsi-d001-openbao"},
|
||||
"spec": {
|
||||
"storageClassName": "prole-iscsi",
|
||||
"storageClassName": "synology-iscsi",
|
||||
"capacity": {"storage": "20Gi"},
|
||||
"accessModes": ["ReadWriteOnce"],
|
||||
"claimRef": {
|
||||
@ -184,8 +184,8 @@ def test_repair_flow_classifies_blockers_attempts_reclaim_and_avoids_blind_healt
|
||||
|
||||
# Reclaim was attempted for matching stale Released PVs.
|
||||
patched = [c for c in calls if c[:3] == ["kubectl", "patch", "pv"]]
|
||||
assert any("prole-iscsi-d001-garage" in c for c in patched)
|
||||
assert any("prole-iscsi-d001-openbao" in c for c in patched)
|
||||
assert any("synology-iscsi-d001-garage" in c for c in patched)
|
||||
assert any("synology-iscsi-d001-openbao" in c for c in patched)
|
||||
|
||||
# Explicit scheduling/storage classification is surfaced.
|
||||
assert "Storage blockers" in msg
|
||||
|
||||
@ -155,7 +155,7 @@ def test_reset_reclaim_stale_released_pvs_patches_concrete_garage_and_openbao(
|
||||
"uid": "new-garage-uid",
|
||||
},
|
||||
"spec": {
|
||||
"storageClassName": "prole-iscsi",
|
||||
"storageClassName": "synology-iscsi",
|
||||
"accessModes": ["ReadWriteOnce"],
|
||||
"resources": {"requests": {"storage": "10Gi"}},
|
||||
},
|
||||
@ -168,7 +168,7 @@ def test_reset_reclaim_stale_released_pvs_patches_concrete_garage_and_openbao(
|
||||
"uid": "new-bao-uid",
|
||||
},
|
||||
"spec": {
|
||||
"storageClassName": "prole-iscsi",
|
||||
"storageClassName": "synology-iscsi",
|
||||
"accessModes": ["ReadWriteOnce"],
|
||||
"resources": {"requests": {"storage": "10Gi"}},
|
||||
},
|
||||
@ -178,9 +178,9 @@ def test_reset_reclaim_stale_released_pvs_patches_concrete_garage_and_openbao(
|
||||
|
||||
released_pvs = [
|
||||
{
|
||||
"metadata": {"name": "prole-iscsi-d001-garage"},
|
||||
"metadata": {"name": "synology-iscsi-d001-garage"},
|
||||
"spec": {
|
||||
"storageClassName": "prole-iscsi",
|
||||
"storageClassName": "synology-iscsi",
|
||||
"capacity": {"storage": "20Gi"},
|
||||
"accessModes": ["ReadWriteOnce"],
|
||||
"claimRef": {
|
||||
@ -192,9 +192,9 @@ def test_reset_reclaim_stale_released_pvs_patches_concrete_garage_and_openbao(
|
||||
"status": {"phase": "Released"},
|
||||
},
|
||||
{
|
||||
"metadata": {"name": "prole-iscsi-d001-openbao"},
|
||||
"metadata": {"name": "synology-iscsi-d001-openbao"},
|
||||
"spec": {
|
||||
"storageClassName": "prole-iscsi",
|
||||
"storageClassName": "synology-iscsi",
|
||||
"capacity": {"storage": "20Gi"},
|
||||
"accessModes": ["ReadWriteOnce"],
|
||||
"claimRef": {
|
||||
@ -237,8 +237,8 @@ def test_reset_reclaim_stale_released_pvs_patches_concrete_garage_and_openbao(
|
||||
assert changed is True
|
||||
|
||||
patched = [c for c in calls if c[:3] == ["kubectl", "patch", "pv"]]
|
||||
assert any("prole-iscsi-d001-garage" in c for c in patched)
|
||||
assert any("prole-iscsi-d001-openbao" in c for c in patched)
|
||||
assert any("synology-iscsi-d001-garage" in c for c in patched)
|
||||
assert any("synology-iscsi-d001-openbao" in c for c in patched)
|
||||
assert all('{"spec":{"claimRef":null}}' in c for c in patched)
|
||||
|
||||
# Reset policy: never delete PVs.
|
||||
|
||||
Loading…
Reference in New Issue
Block a user