diff --git a/ansible.sh b/ansible.sh index 2669443..eccb08a 100755 --- a/ansible.sh +++ b/ansible.sh @@ -74,6 +74,13 @@ while [[ $# -gt 0 ]]; do esac done +# Default to k3s hosts for the main site run (avoid touching non-k3s Linux/Pi hosts unless explicitly requested) +if [[ -z "${LIMIT}" ]]; then + if [[ "${PLAYBOOK}" =~ (^|/)infrastructure/playbooks/site\.yml$ ]]; then + LIMIT="k3s_hosts" + fi +fi + mkdir -p "${LOG_DIR}" ts="$(date +%Y%m%d-%H%M%S)" diff --git a/conf/prod/prole.cfg b/conf/prod/prole.cfg index 7db5443..8fcce1d 100644 --- a/conf/prod/prole.cfg +++ b/conf/prod/prole.cfg @@ -1,5 +1,5 @@ ; Prole Master Configuration File -; Generated by install.py on 2026-03-20 16:11:36 +; Generated by install.py on 2026-03-20 16:59:08 ; 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 = prod init_cluster.deployment_target = prole-prod-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:byngYfgT7BPkndc5:TukgM2QvPylhorfIm0t-tPysEPq-Lvc8lqbv594nzDsJxc6Kj6J9walkiVQS6o18ZJYNU7xpuYsRWV1yyZW8RBxvPi-glfs7C-sdj6Q3mwia2A9jLcxyJMck3_8z4L-mc7utmo8PIxw0MnjeF8P_Ixzoyi4cM3WoKtZiyA==} +init_cluster.kerberos_enabled = true init_cluster.mode = k8s init_cluster.start_cluster = true init_cluster.supabase_enabled = false @@ -65,15 +65,15 @@ init_password.db_password_confirm = 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:3vn_jWdWyDkkLs4m:k5wERNl46EUEa4QReopiBD6daCtPdE8Mkcp2zYyaMu7OMr2d} -kerberos_config.realm = +kerberos_config.enabled = true +kerberos_config.kdc = 10.0.0.3 +kerberos_config.password = ${PROLE_SECRET:v1:A6qvhIB8BlPEcQjO:0tFeTyOFqqkn13rROLkgcJ9NgYmVYRD1ZjJzCAeFwfrgSxQx} +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] @@ -87,8 +87,9 @@ DOCKER_PRELOAD = false NAMESPACE = prole-db OPTIONAL_WORKLOADS_MIN_READY_SCHEDULABLE_NODES = 2 PROLE_DB_USER = root -PROLE_K3S_SERVER = -PROLE_K3S_TOKEN = +PROLE_HOME = $HOME/dev/prole +PROLE_K3S_SERVER = https://myrddin.prole.org:6443 +PROLE_K3S_TOKEN = ${PROLE_SECRET:v1:dQZZFvDfN_I8bFPY:yr9laHz55aM5lL_QTnBim1m0xBpX5SgfOPOVp-2HwLdii-2TNnT0gSAuWqSjgwI9JSoMT3QfD2lavVF2qMoWh9SFN8idZ3-VIYRsiZ7SM2BOiS_sbOG3_QDucvciuIxy5MXNyFEmxOGTtXwyzC1cnQjlsiEnKy0XbFF7dA==} PROLE_OPENTOFU_URL = http://127.0.0.1:8080 SERVICE_NAMESPACE = knoe-system @@ -107,12 +108,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,7 +128,10 @@ 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] ; No configuration values captured yet for this section. @@ -144,13 +154,13 @@ 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:_iFv8sZdDHQxTxd4:a3RRUkKtO9ctIm_393LrEg9Lq9tN1Sfl7B3TZLnSwEXEKgpNnp9VAeicvFy8kV4unSX99yXZPhTf3RbTQ7qaTt4Oj8vU9aFK905qa5BVPOzmAZo_10mTcfXYTOeNXALl4sprStWambtJ4CEYol3XsIXFywzGq1jkldPyLw==} 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-26/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 diff --git a/conf/service/prole.cfg b/conf/service/prole.cfg index 80573e2..4a3632a 100644 --- a/conf/service/prole.cfg +++ b/conf/service/prole.cfg @@ -1,5 +1,5 @@ ; Prole Master Configuration File -; Generated by install.py on 2026-03-20 16:10:22 +; Generated by install.py on 2026-03-20 17:05:22 ; 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 = service init_cluster.deployment_target = prole-service-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:s4MdUcnQRJBPdAss:irg5n342LjxLeLV8kGtoAAO_Od3QcmWtTXLQbPw2o2mUJrRnNEBOhN-z4Q6J3UZylEKp6ZhmD_TdRGqdpfpC79j1kFtaTPWCvl_cdHHiG9580AQ87V4XmtAwEh-_ICm4GS35szQHELlXkJH4j7CvfAngW8RW_1nvtLHQyQ==} +init_cluster.kerberos_enabled = true init_cluster.mode = k3s init_cluster.start_cluster = true init_cluster.supabase_enabled = false @@ -60,37 +60,37 @@ 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 = ${OPENBAO:kv/prole/knoe-db/db#password} -init_password.db_password_confirm = ${OPENBAO:kv/prole/knoe-db/db#password} +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 = false -kerberos_config.kdc = -kerberos_config.password = ${OPENBAO:kv/prole/knoe-db/kerberos#password} -kerberos_config.realm = +kerberos_config.enabled = true +kerberos_config.kdc = 10.0.0.3 +kerberos_config.password = ${PROLE_SECRET:v1:1zuEATgIOtkCPTIi:w2eKBUzce6mq6BJAlefU9cl6K05A9EDT81AQ1uSVzgI1NbUY} +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 -ARGOCD_NAMESPACE = argocd CLUSTER_ENV = service DB_HOST_PORT = 5432 -DB_PASSWORD = ${OPENBAO:kv/prole/knoe-db/db#password} +DB_PASSWORD = DEPLOYMENT_MODE = k3s DEPLOYMENT_TARGET = prole-service-cluster -DOCKER_IMPORT_DIR = DOCKER_PRELOAD = false -NAMESPACE = knoe-db +KUBECONTEXT = prole-k3s +NAMESPACE = prole-db OPTIONAL_WORKLOADS_MIN_READY_SCHEDULABLE_NODES = 2 PROLE_DB_USER = root -PROLE_K3S_SERVER = -PROLE_K3S_TOKEN = +PROLE_HOME = $HOME/dev/prole +PROLE_K3S_SERVER = https://myrddin.prole.org:6443 +PROLE_K3S_TOKEN = ${PROLE_SECRET:v1:SNcp3N71DMccQw5G:UXmhfoiN8PKqw3jaarQxhhv5rtPjjUQTRSVo4pS6FkmHqLDt1xghL4RfgBdcaR5HA9lnlDc5jFpLruIrC1ivxk5HssTn1prde0lKvhioO7SkIOSl6HsA4XXosf6KveNASpxCdeZ6RkZlg2i7jpHxvxX3zbIrSKNISN5gEQ==} PROLE_OPENTOFU_URL = http://127.0.0.1:8080 SERVICE_NAMESPACE = knoe-system @@ -109,12 +109,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. @@ -123,10 +129,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. @@ -135,24 +147,26 @@ GITOPS_ENABLED = False ; No configuration values captured yet for this section. [Initialize Cluster] -; No configuration values captured yet for this section. +ENVIRONMENT = service +K3S_SERVER_URL = https://myrddin.prole.org:6443 +K3S_TOKEN = ${PROLE_SECRET:v1:570CIZjbSCH131v_:pDQwbH9nKYsCl5z0f-iAb-cilZlo1KLpI16c6Hgj0Ic81Jk1I7CSjEFo5UJ1ezV_pdat-7kxhaWE_TxCXG6ZnuOA8SBh3xCCi1LsgYFluPwm47b4IaS5ftvMOe5TVWbQfnzsXuU4SdO_3O9mgagKHdDIzu8kufYfpeDyqA==} [Dev Cluster (k3d)] CLUSTER_ENV = dev DISPLAY_NAME = knoe-dev-cluster -KUBECTL_CONTEXT = +KUBECTL_CONTEXT = prole-k3s 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:_r5tIPt5VZcr0SrV:e2_sHY49gG2i-vhQZr-42M1kekln4D4ZHq6tJrDRCn8f4KOVSn59rndLt4PuHmsebPSPP4tGHZV0MaVtdBMm4RJmk9IXbqV7BjSNruK2SXi62NOXIIUWZGNcVIOFjmv7EovfOifo3nye8142zKDspTeyo5Y2KY6qGLtS2g==} 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-25/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 diff --git a/deploy/opentofu/k3s/manifests/prole/iscsi-pvs.yaml b/deploy/opentofu/k3s/manifests/prole/iscsi-pvs.yaml index 6a2a1d7..aaa9bb9 100644 --- a/deploy/opentofu/k3s/manifests/prole/iscsi-pvs.yaml +++ b/deploy/opentofu/k3s/manifests/prole/iscsi-pvs.yaml @@ -14,7 +14,7 @@ spec: storageClassName: prole-iscsi persistentVolumeReclaimPolicy: Retain local: - path: /prole/d001/data + path: /synology/d001/data nodeAffinity: required: nodeSelectorTerms: @@ -40,7 +40,7 @@ spec: storageClassName: prole-iscsi persistentVolumeReclaimPolicy: Retain local: - path: /prole/d001/wal + path: /synology/d001/wal nodeAffinity: required: nodeSelectorTerms: @@ -66,7 +66,7 @@ spec: storageClassName: prole-iscsi persistentVolumeReclaimPolicy: Retain local: - path: /prole/d001/garage + path: /synology/d001/garage nodeAffinity: required: nodeSelectorTerms: @@ -92,7 +92,7 @@ spec: storageClassName: prole-iscsi persistentVolumeReclaimPolicy: Retain local: - path: /prole/d002/data + path: /synology/d002/data nodeAffinity: required: nodeSelectorTerms: @@ -100,7 +100,7 @@ spec: - key: kubernetes.io/hostname operator: In values: - - myrddin.prole.org + - merlin.prole.org --- apiVersion: v1 kind: PersistentVolume @@ -118,7 +118,7 @@ spec: storageClassName: prole-iscsi persistentVolumeReclaimPolicy: Retain local: - path: /prole/d002/wal + path: /synology/d002/wal nodeAffinity: required: nodeSelectorTerms: @@ -126,7 +126,7 @@ spec: - key: kubernetes.io/hostname operator: In values: - - myrddin.prole.org + - merlin.prole.org --- apiVersion: v1 kind: PersistentVolume @@ -144,7 +144,7 @@ spec: storageClassName: prole-iscsi persistentVolumeReclaimPolicy: Retain local: - path: /prole/d003/data + path: /synology/d003/data nodeAffinity: required: nodeSelectorTerms: @@ -152,7 +152,7 @@ spec: - key: kubernetes.io/hostname operator: In values: - - myrddin.prole.org + - pi.prole.org --- apiVersion: v1 kind: PersistentVolume @@ -170,7 +170,7 @@ spec: storageClassName: prole-iscsi persistentVolumeReclaimPolicy: Retain local: - path: /prole/d003/wal + path: /synology/d003/wal nodeAffinity: required: nodeSelectorTerms: @@ -178,7 +178,7 @@ spec: - key: kubernetes.io/hostname operator: In values: - - myrddin.prole.org + - pi.prole.org --- apiVersion: v1 kind: PersistentVolume @@ -196,7 +196,7 @@ spec: storageClassName: prole-iscsi persistentVolumeReclaimPolicy: Retain local: - path: /prole/d003/grafana + path: /synology/d003/grafana nodeAffinity: required: nodeSelectorTerms: @@ -204,7 +204,7 @@ spec: - key: kubernetes.io/hostname operator: In values: - - myrddin.prole.org + - pi.prole.org --- apiVersion: v1 kind: PersistentVolume @@ -222,7 +222,7 @@ spec: storageClassName: prole-iscsi persistentVolumeReclaimPolicy: Retain local: - path: /prole/d002/prometheus + path: /synology/d002/prometheus nodeAffinity: required: nodeSelectorTerms: @@ -230,7 +230,7 @@ spec: - key: kubernetes.io/hostname operator: In values: - - myrddin.prole.org + - merlin.prole.org --- apiVersion: v1 kind: PersistentVolume @@ -248,7 +248,7 @@ spec: storageClassName: prole-iscsi persistentVolumeReclaimPolicy: Retain local: - path: /prole/d001/openbao + path: /synology/d001/openbao nodeAffinity: required: nodeSelectorTerms: diff --git a/deploy/opentofu/k3s/manifests/prole/prole-db.yaml b/deploy/opentofu/k3s/manifests/prole/prole-db.yaml index 4fd8c35..48d23de 100644 --- a/deploy/opentofu/k3s/manifests/prole/prole-db.yaml +++ b/deploy/opentofu/k3s/manifests/prole/prole-db.yaml @@ -4,7 +4,7 @@ metadata: name: prole-db spec: instances: 3 - imageName: myrddin.prole.org:5000/prole-db:18-129 + imageName: myrddin.prole.org:5000/prole-db:0.0.0 postgresUID: 100 postgresGID: 101 maxSyncReplicas: 1 diff --git a/etc/init_cloudnative_pg.sh b/etc/init_cloudnative_pg.sh index 345c04a..b0f433e 100755 --- a/etc/init_cloudnative_pg.sh +++ b/etc/init_cloudnative_pg.sh @@ -49,6 +49,25 @@ CNPG_MANIFEST_OVERRIDE=${CNPG_MANIFEST_OVERRIDE:-} PROLE_HOME=${PROLE_HOME:-$(cd "$SCRIPT_DIR/.." && pwd)} BACKUP_DIR=${BACKUP_DIR:-$PROLE_HOME/prole/backup} BACKUP_WAIT_TIMEOUT=${BACKUP_WAIT_TIMEOUT:-1800} + +# CNPG staged topology controls +# - CNPG_TOPOLOGY=auto (default): use stage-1 pinning if CNPG_STAGE1_NODE exists, otherwise label-based +# - CNPG_TOPOLOGY=stage1: pin CNPG pods to CNPG_STAGE1_NODE and relax anti-affinity to preferred +# - CNPG_TOPOLOGY=label: keep manifest label-based and keep anti-affinity as-is +CNPG_TOPOLOGY=${CNPG_TOPOLOGY:-auto} +CNPG_STAGE1_NODE=${CNPG_STAGE1_NODE:-myrddin.prole.org} +CNPG_DB_NODE_SELECTOR=${CNPG_DB_NODE_SELECTOR:-} +CNPG_ALLOW_COLOCATED_INSTANCES=${CNPG_ALLOW_COLOCATED_INSTANCES:-} +CNPG_POD_ANTI_AFFINITY_TYPE=${CNPG_POD_ANTI_AFFINITY_TYPE:-} + +# Barman plugin identity (used for readiness checks) +BARMAN_PLUGIN_NAME=${BARMAN_PLUGIN_NAME:-barman-cloud.cloudnative-pg.io} + +# Barman readiness timeouts (seconds). Keep them overridable for testability. +BARMAN_CRD_TIMEOUT=${BARMAN_CRD_TIMEOUT:-120} +BARMAN_TLS_TIMEOUT=${BARMAN_TLS_TIMEOUT:-180} +BARMAN_DEPLOY_TIMEOUT=${BARMAN_DEPLOY_TIMEOUT:-180} +BARMAN_SERVICE_TIMEOUT=${BARMAN_SERVICE_TIMEOUT:-180} if [[ "${PROLE_MODE:-}" == "k3s" ]]; then CNPG_WAIT_TIMEOUT=${CNPG_WAIT_TIMEOUT:-900} else @@ -919,12 +938,8 @@ wait_for_barman_tls_secrets() { start_time=$(date +%s) echo "Waiting for Barman Cloud TLS secrets (timeout: ${timeout}s)..." while true; do - local client_crt client_key server_crt server_key - client_crt=$(kubectl -n cnpg-system get secret barman-cloud-client-tls -o jsonpath='{.data.tls\.crt}' 2>/dev/null || true) - client_key=$(kubectl -n cnpg-system get secret barman-cloud-client-tls -o jsonpath='{.data.tls\.key}' 2>/dev/null || true) - server_crt=$(kubectl -n cnpg-system get secret barman-cloud-server-tls -o jsonpath='{.data.tls\.crt}' 2>/dev/null || true) - server_key=$(kubectl -n cnpg-system get secret barman-cloud-server-tls -o jsonpath='{.data.tls\.key}' 2>/dev/null || true) - if [[ -n "$client_crt" && -n "$client_key" && -n "$server_crt" && -n "$server_key" ]]; then + if kubectl -n cnpg-system get secret barman-cloud-client-tls >/dev/null 2>&1 \ + && kubectl -n cnpg-system get secret barman-cloud-server-tls >/dev/null 2>&1; then echo "Barman Cloud TLS secrets are available." return 0 fi @@ -940,6 +955,46 @@ wait_for_barman_tls_secrets() { done } +wait_for_barman_plugin_service_registration() { + local timeout=${1:-180} + local start_time + start_time=$(date +%s) + + echo "Waiting for Barman plugin service registration (timeout: ${timeout}s)..." + while true; do + local svc_name client_secret server_secret plugin_port endpoints + svc_name=$(kubectl -n cnpg-system get svc -l "cnpg.io/pluginName=$BARMAN_PLUGIN_NAME" -o jsonpath='{.items[0].metadata.name}' 2>/dev/null || true) + if [[ -z "$svc_name" ]]; then + svc_name=$(kubectl -n cnpg-system get svc barman-cloud -o jsonpath='{.metadata.name}' 2>/dev/null || true) + fi + + if [[ -n "$svc_name" ]]; then + client_secret=$(kubectl -n cnpg-system get svc "$svc_name" -o jsonpath='{.metadata.annotations.cnpg\.io/pluginClientSecret}' 2>/dev/null || true) + server_secret=$(kubectl -n cnpg-system get svc "$svc_name" -o jsonpath='{.metadata.annotations.cnpg\.io/pluginServerSecret}' 2>/dev/null || true) + plugin_port=$(kubectl -n cnpg-system get svc "$svc_name" -o jsonpath='{.metadata.annotations.cnpg\.io/pluginPort}' 2>/dev/null || true) + endpoints=$(kubectl -n cnpg-system get endpoints "$svc_name" -o jsonpath='{.subsets[*].addresses[*].ip}' 2>/dev/null || true) + + if [[ -n "$client_secret" && -n "$server_secret" && -n "$plugin_port" && -n "$endpoints" ]]; then + if kubectl -n cnpg-system get secret "$client_secret" >/dev/null 2>&1 && kubectl -n cnpg-system get secret "$server_secret" >/dev/null 2>&1; then + echo "Barman plugin service registration is ready (service=${svc_name}, port=${plugin_port})." + return 0 + fi + fi + fi + + local elapsed=$(( $(date +%s) - start_time )) + if (( elapsed > timeout )); then + echo "Barman plugin service registration not ready after ${elapsed}s." >&2 + kubectl -n cnpg-system get svc,ep 2>/dev/null >&2 || true + return 1 + fi + if (( elapsed % 30 < 6 && elapsed > 5 )); then + echo " [${elapsed}s/${timeout}s] Still waiting for barman plugin service registration..." + fi + sleep 5 + done +} + ensure_barman_plugin() { ensure_cert_manager @@ -955,25 +1010,28 @@ ensure_barman_plugin() { kubectl -n cert-manager rollout status deploy/cert-manager-webhook --timeout=180s >/dev/null 2>&1 || true kubectl -n cert-manager rollout status deploy/cert-manager --timeout=180s >/dev/null 2>&1 || true kubectl -n cert-manager rollout status deploy/cert-manager-cainjector --timeout=180s >/dev/null 2>&1 || true - kubectl apply -f "$plugin_url" || true + if ! kubectl apply -f "$plugin_url" >/dev/null 2>&1; then + echo "ERROR: Failed to apply Barman Cloud plugin manifest after cert-manager restart." >&2 + return 1 + fi + else + echo "ERROR: Failed to apply Barman Cloud plugin manifest." >&2 + return 1 fi else printf '%s\n' "$apply_out" fi - if ! wait_for_barman_crd 120; then - echo "WARN: Barman Cloud ObjectStore CRD not ready after install." >&2 - fi - - if ! wait_for_barman_tls_secrets 180; then - echo "WARN: Barman Cloud TLS secrets not ready after install." >&2 - fi + wait_for_barman_crd "$BARMAN_CRD_TIMEOUT" + wait_for_barman_tls_secrets "$BARMAN_TLS_TIMEOUT" pin_barman_cloud if kubectl -n cnpg-system get deploy barman-cloud >/dev/null 2>&1; then - kubectl -n cnpg-system rollout status deploy/barman-cloud --timeout=180s || true + kubectl -n cnpg-system rollout status deploy/barman-cloud --timeout="${BARMAN_DEPLOY_TIMEOUT}s" fi + + wait_for_barman_plugin_service_registration "$BARMAN_SERVICE_TIMEOUT" } pin_cnpg_controller() { @@ -1415,8 +1473,8 @@ ensure_prole_stack_resources() { done prole_render_manifest "$dir/ingress.yaml" | kubectl_apply_retry "" || true fi - apply_barman_objectstore_if_present apply_cnpg_cluster_manifest "$CNPG_MANIFEST_OVERRIDE" + ensure_cnpg_cluster_scheduling || true validate_cnpg_runtime_storage reconcile_cnpg_instances else @@ -1456,8 +1514,8 @@ ensure_prole_stack_resources() { done prole_render_manifest "$dir/ingress.yaml" | kubectl_apply_retry "" || true fi - apply_barman_objectstore_if_present apply_cnpg_cluster_manifest "$CNPG_MANIFEST" + ensure_cnpg_cluster_scheduling || true validate_cnpg_runtime_storage reconcile_cnpg_instances fi @@ -1492,15 +1550,125 @@ _coerce_uint() { fi } +_cnpg_node_exists() { + local node_name="${1:-}" + [[ -n "$node_name" ]] || return 1 + local out + out=$(kubectl get node "$node_name" -o jsonpath='{.metadata.name}' 2>/dev/null || true) + [[ "$out" == "$node_name" ]] +} + +_cnpg_effective_topology() { + local t="${CNPG_TOPOLOGY:-auto}" + case "$t" in + stage1|stage-1|stage1-single-node|single-node) + echo "stage1" + return 0 + ;; + label|labels|label-db) + echo "label" + return 0 + ;; + auto|'') + if _cnpg_node_exists "${CNPG_STAGE1_NODE:-myrddin.prole.org}"; then + echo "stage1" + else + echo "label" + fi + return 0 + ;; + *) + echo "label" + return 0 + ;; + esac +} + +_cnpg_effective_node_selector() { + if [[ -n "${CNPG_DB_NODE_SELECTOR:-}" ]]; then + echo "$CNPG_DB_NODE_SELECTOR" + return 0 + fi + + if [[ "$(_cnpg_effective_topology)" == "stage1" ]]; then + echo "kubernetes.io/hostname=${CNPG_STAGE1_NODE:-myrddin.prole.org}" + return 0 + fi + + echo "${CNPG_NODE_ROLE_LABEL_KEY:-prole.org/node-role}=${CNPG_NODE_ROLE_LABEL_VALUE:-db}" +} + +_cnpg_allow_colocated_instances() { + local v="${CNPG_ALLOW_COLOCATED_INSTANCES:-}" + if [[ -n "$v" ]]; then + local v_lc + v_lc=$(printf '%s' "$v" | tr '[:upper:]' '[:lower:]') + case "$v_lc" in + 1|true|yes|y) return 0 ;; + 0|false|no|n) return 1 ;; + esac + fi + + [[ "$(_cnpg_effective_topology)" == "stage1" ]] +} + +patch_cnpg_manifest_for_topology() { + # Best-effort patch for stage-1 (single-node) scheduling: pin to CNPG_STAGE1_NODE and + # relax anti-affinity so all instances can schedule on one node. + local manifest_file="$1" + [[ -f "$manifest_file" ]] || return 0 + + if [[ "$(_cnpg_effective_topology)" != "stage1" ]]; then + return 0 + fi + + local host anti + host="${CNPG_STAGE1_NODE:-myrddin.prole.org}" + anti="${CNPG_POD_ANTI_AFFINITY_TYPE:-preferred}" + + local tmp + tmp=$(mktemp -t prole-cnpg-topo.XXXXXX) + sed -E \ + -e "s/^([[:space:]]*podAntiAffinityType:)[[:space:]]*required[[:space:]]*$/\\1 ${anti}/" \ + -e 's/^([[:space:]]*-[[:space:]]*key:)[[:space:]]*prole\.org\/node-role[[:space:]]*$/\1 kubernetes.io\/hostname/' \ + -e "s/^([[:space:]]*-[[:space:]]*)db[[:space:]]*$/\\1${host}/" \ + "$manifest_file" >"$tmp" + mv "$tmp" "$manifest_file" +} + +ensure_cnpg_cluster_scheduling() { + # Enforce the effective topology on the live Cluster object. + if ! kubectl -n "$NAMESPACE" get cluster "$CNPG_CLUSTER_NAME" >/dev/null 2>&1; then + return 0 + fi + + local selector key val topo anti + topo="$(_cnpg_effective_topology)" + selector="$(_cnpg_effective_node_selector)" + key="${selector%%=*}" + val="${selector#*=}" + + anti="${CNPG_POD_ANTI_AFFINITY_TYPE:-}" + if [[ -z "$anti" ]]; then + if [[ "$topo" == "stage1" || "$(_cnpg_allow_colocated_instances && echo 1 || echo 0)" == "1" ]]; then + anti="preferred" + else + anti="required" + fi + fi + + kubectl -n "$NAMESPACE" patch cluster "$CNPG_CLUSTER_NAME" --type merge -p "{\"spec\":{\"affinity\":{\"enablePodAntiAffinity\":true,\"podAntiAffinityType\":\"${anti}\",\"topologyKey\":\"kubernetes.io/hostname\",\"nodeAffinity\":{\"requiredDuringSchedulingIgnoredDuringExecution\":{\"nodeSelectorTerms\":[{\"matchExpressions\":[{\"key\":\"${key}\",\"operator\":\"In\",\"values\":[\"${val}\"]}]}]}}}}}}" >/dev/null 2>&1 || true +} + _ready_schedulable_nodes_count() { kubectl get nodes --no-headers 2>/dev/null \ | awk '$2 ~ /^Ready/ && $2 !~ /SchedulingDisabled/ {c++} END {print c+0}' } _ready_schedulable_db_nodes_count() { - local key="${CNPG_NODE_ROLE_LABEL_KEY:-prole.org/node-role}" - local val="${CNPG_NODE_ROLE_LABEL_VALUE:-db}" - kubectl get nodes -l "${key}=${val}" --no-headers 2>/dev/null \ + local selector + selector=$(_cnpg_effective_node_selector) + kubectl get nodes -l "$selector" --no-headers 2>/dev/null \ | awk '$2 ~ /^Ready/ && $2 !~ /SchedulingDisabled/ {c++} END {print c+0}' } @@ -1515,17 +1683,28 @@ reconcile_cnpg_instances() { [[ -z "$current" ]] && return 0 current=$(_coerce_uint "$current" 0) + local allow_colocated=0 + if _cnpg_allow_colocated_instances; then + allow_colocated=1 + fi + local min_required min_required=$(_coerce_uint "${OPTIONAL_WORKLOADS_MIN_READY_SCHEDULABLE_NODES:-2}" 2) if (( min_required < 1 )); then min_required=1 fi + # Stage-1 single-node evaluation is an explicit mode; do not force scale-down + # solely due to node-count heuristics. + if (( allow_colocated == 1 )); then + min_required=1 + fi - local ready_nodes eligible_db_nodes + local ready_nodes eligible_nodes selector + selector=$(_cnpg_effective_node_selector) ready_nodes=$(_coerce_uint "$(_ready_schedulable_nodes_count)" 0) - eligible_db_nodes=$(_coerce_uint "$(_ready_schedulable_db_nodes_count)" 0) - if (( eligible_db_nodes < 1 )); then - echo "ERROR: No Ready, schedulable CNPG DB nodes found (label ${CNPG_NODE_ROLE_LABEL_KEY:-prole.org/node-role}=${CNPG_NODE_ROLE_LABEL_VALUE:-db})." >&2 + eligible_nodes=$(_coerce_uint "$(_ready_schedulable_db_nodes_count)" 0) + if (( eligible_nodes < 1 )); then + echo "ERROR: No Ready, schedulable CNPG eligible nodes found (selector ${selector})." >&2 echo "Refusing to force CNPG pods onto an arbitrary node during bootstrap." >&2 return 1 fi @@ -1535,13 +1714,17 @@ reconcile_cnpg_instances() { if (( desired < 1 )); then desired=1 fi - if (( desired > eligible_db_nodes )); then - desired=$eligible_db_nodes + if (( allow_colocated == 0 )); then + if (( desired > eligible_nodes )); then + desired=$eligible_nodes + fi fi # Degraded cluster: keep instances at 1 until enough nodes are Ready+schedulable. - if (( ready_nodes < min_required )); then - desired=1 + if (( allow_colocated == 0 )); then + if (( ready_nodes < min_required )); then + desired=1 + fi fi if (( desired < 1 )); then @@ -1569,7 +1752,7 @@ reconcile_cnpg_instances() { return 0 fi - echo "Reconciling CNPG cluster '$CNPG_CLUSTER_NAME' instances=${desired} (was ${current}; ready_nodes=${ready_nodes}; eligible_db_nodes=${eligible_db_nodes}) ..." + echo "Reconciling CNPG cluster '$CNPG_CLUSTER_NAME' instances=${desired} (was ${current}; ready_nodes=${ready_nodes}; eligible_nodes=${eligible_nodes}; allow_colocated=${allow_colocated}) ..." # CloudNativePG validates `maxSyncReplicas < instances`. When we temporarily # scale down to a single instance during degraded startup, we must also @@ -1619,6 +1802,9 @@ apply_cnpg_cluster_manifest() { local tmp tmp=$(mktemp -t prole-cnpg.XXXXXX) prole_render_manifest "$manifest" >"$tmp" + + patch_cnpg_manifest_for_topology "$tmp" || true + if ! validate_cnpg_manifest_storage "$tmp"; then rm -f "$tmp" return 1 @@ -2109,6 +2295,100 @@ reset_and_reinit() { wait_for_cnpg_pods "${CNPG_WAIT_TIMEOUT}" } +destroy_cnpg_cluster() { + # Destroy only CNPG + backup resources (not the entire prole stack). + # This is intended to support repeatable destroy/recreate/restore storage evaluation. + local delete_pvcs + delete_pvcs=$(_coerce_uint "${CNPG_DESTROY_DELETE_PVCS:-1}" 1) + + # IMPORTANT: The recovery template uses `bootstrap.recovery.backup.name`, which requires the + # Backup CR to exist at restore time. By default we keep Backup/ObjectStore CRs. + local delete_backup_crs delete_objectstore_crs + delete_backup_crs=$(_coerce_uint "${CNPG_DESTROY_DELETE_BACKUP_CRS:-0}" 0) + delete_objectstore_crs=$(_coerce_uint "${CNPG_DESTROY_DELETE_OBJECTSTORE_CRS:-0}" 0) + + echo "Destroying CNPG cluster '$CNPG_CLUSTER_NAME' in namespace '$NAMESPACE' ..." + kubectl -n "$NAMESPACE" delete scheduledbackup --all --ignore-not-found 2>/dev/null || true + if (( delete_backup_crs == 1 )); then + kubectl -n "$NAMESPACE" delete backup --all --ignore-not-found 2>/dev/null || true + fi + if (( delete_objectstore_crs == 1 )); then + kubectl -n "$NAMESPACE" delete objectstore --all --ignore-not-found 2>/dev/null || true + fi + + kubectl -n "$NAMESPACE" delete cluster "$CNPG_CLUSTER_NAME" --ignore-not-found + kubectl -n "$NAMESPACE" wait --for=delete pod -l "cnpg.io/cluster=$CNPG_CLUSTER_NAME" --timeout=180s >/dev/null 2>&1 || true + + if (( delete_pvcs == 1 )); then + echo "Deleting PVCs for CNPG cluster '$CNPG_CLUSTER_NAME' (label cnpg.io/cluster=$CNPG_CLUSTER_NAME) ..." + kubectl -n "$NAMESPACE" delete pvc -l "cnpg.io/cluster=$CNPG_CLUSTER_NAME" --ignore-not-found 2>/dev/null || true + else + echo "Leaving PVCs intact (CNPG_DESTROY_DELETE_PVCS=0)." + fi + + recycle_released_prole_iscsi_pvs || true +} + +restore_cnpg_cluster() { + ensure_tools + ensure_namespace + ensure_cnpg_operator + pin_cnpg_controller + ensure_barman_plugin + ensure_prole_protected_storage + + if kubectl -n "$NAMESPACE" get cluster "$CNPG_CLUSTER_NAME" >/dev/null 2>&1; then + echo "ERROR: CNPG cluster '$CNPG_CLUSTER_NAME' already exists in namespace '$NAMESPACE'." >&2 + echo "Run '$0 destroy' first (or delete the cluster) before restoring." >&2 + return 1 + fi + + local backup_name + backup_name="${BACKUP_NAME:-}" + if [[ -z "$backup_name" ]]; then + backup_name=$(latest_completed_backup_name) + fi + if [[ -z "$backup_name" ]]; then + echo "ERROR: No completed backups found for restore (set BACKUP_NAME explicitly if needed)." >&2 + return 1 + fi + if [[ ! -f "$RECOVERY_TEMPLATE" ]]; then + echo "ERROR: Recovery template not found: $RECOVERY_TEMPLATE" >&2 + return 1 + fi + + local image + if [[ "$VERSION" == "latest" || -z "$VERSION" ]]; then + image=$(get_latest_image) + else + image="prole-db:$VERSION" + fi + image=$(resolve_cnpg_image "$image") + + local tmp_manifest + tmp_manifest=$(mktemp -t prole-cnpg-restore.XXXXXX) + sed \ + -e "s/{{BACKUP_NAME}}/${backup_name}/g" \ + -e "s|^ imageName:.*| imageName: ${image}|" \ + "$RECOVERY_TEMPLATE" >"$tmp_manifest" + + echo "Restoring CNPG cluster '$CNPG_CLUSTER_NAME' from backup '$backup_name' using image '$image' ..." + apply_cnpg_cluster_manifest "$tmp_manifest" + ensure_cnpg_cluster_scheduling || true + validate_cnpg_runtime_storage + reconcile_cnpg_instances + + rm -f "$tmp_manifest" + + if ! wait_for_cnpg_pods "${CNPG_WAIT_TIMEOUT}"; then + echo "ERROR: CNPG pods did not become ready after restore." >&2 + return 1 + fi + + echo "Ensuring CNPG continuous backups after restore (ObjectStore + plugin config + ScheduledBackup + first successful backup) ..." + "$SCRIPT_DIR/init_cnpg_backup.sh" start +} + recycle_released_prole_iscsi_pvs() { # StorageClass `prole-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. @@ -2522,6 +2802,7 @@ deploy_cluster() { return 1 fi apply_cnpg_cluster_manifest "$manifest" + ensure_cnpg_cluster_scheduling || true validate_cnpg_runtime_storage reconcile_cnpg_instances @@ -2548,10 +2829,8 @@ case "$ACTION" in ;; recreate) ensure_tools - "$0" delete "$CNPG_CLUSTER_NAME" - # Clean up PVCs left behind by the CNPG operator (not in static manifests) - echo "Cleaning up PVCs in namespace '$NAMESPACE' ..." - kubectl -n "$NAMESPACE" delete pvc --all --ignore-not-found 2>/dev/null || true + ensure_namespace + destroy_cnpg_cluster # Wait briefly for pods to fully terminate before re-creating echo "Waiting for pods to terminate in namespace '$NAMESPACE' ..." _wait_term=0 @@ -2565,6 +2844,14 @@ case "$ACTION" in done "$0" create "$CNPG_CLUSTER_NAME" ;; + destroy) + ensure_tools + ensure_namespace + destroy_cnpg_cluster + ;; + restore) + restore_cnpg_cluster + ;; create) ensure_tools ensure_namespace @@ -2593,13 +2880,13 @@ case "$ACTION" in ensure_namespace ensure_cnpg_operator pin_cnpg_controller - ensure_barman_plugin if [[ ! -f "$CNPG_MANIFEST" ]]; then echo "ERROR: CNPG manifest not found at $CNPG_MANIFEST" >&2 exit 1 fi echo "Starting CloudNative-PG cluster from $CNPG_MANIFEST in namespace $NAMESPACE..." - prole_render_manifest "$CNPG_MANIFEST" | kubectl apply -n "$NAMESPACE" -f - + apply_cnpg_cluster_manifest "$CNPG_MANIFEST" + ensure_cnpg_cluster_scheduling || true reconcile_cnpg_instances ;; stop) diff --git a/etc/init_cnpg_backup.sh b/etc/init_cnpg_backup.sh index 51ae995..97f249c 100755 --- a/etc/init_cnpg_backup.sh +++ b/etc/init_cnpg_backup.sh @@ -48,6 +48,8 @@ BARMAN_OBJECT_NAME=${BARMAN_OBJECT_NAME:-prole-db-barman-objectstore} BACKUP_STATUS_TIMEOUT=${BACKUP_STATUS_TIMEOUT:-600} BACKUP_STATUS_INTERVAL=${BACKUP_STATUS_INTERVAL:-10} PLUGIN_READY_TIMEOUT=${PLUGIN_READY_TIMEOUT:-180} +OBJECTSTORE_READY_TIMEOUT=${OBJECTSTORE_READY_TIMEOUT:-180} +OBJECTSTORE_READY_INTERVAL=${OBJECTSTORE_READY_INTERVAL:-5} SCHEDULED_BACKUP_NAME=${SCHEDULED_BACKUP_NAME:-prole-db-scheduled-backup} SCHEDULED_BACKUP_CRON=${SCHEDULED_BACKUP_CRON:-"0 3 * * *"} @@ -470,6 +472,94 @@ wait_for_plugin_ready() { done } +wait_for_barman_plugin_infra_ready() { + # Ensure the plugin controller and its registration artifacts (Service annotations + TLS secrets) + # are present *before* patching the CNPG Cluster to depend on the plugin. + local start_time now + local deployment_rows ns ready replicas + local plugin_deploy_ready plugin_ns svc_ns svc_name client_secret server_secret plugin_port + start_time=$(date +%s) + + while true; do + plugin_deploy_ready=0 + plugin_ns="" + + deployment_rows=$(kubectl get deployment -A -l app.kubernetes.io/name=barman-cloud -o jsonpath='{range .items[*]}{.metadata.namespace}{"\t"}{.status.readyReplicas}{"\t"}{.status.replicas}{"\n"}{end}' 2>/dev/null || true) + if [[ -z "$deployment_rows" ]]; then + deployment_rows=$(kubectl get deployment -A -o jsonpath='{range .items[?(@.metadata.name=="barman-cloud")]}{.metadata.namespace}{"\t"}{.status.readyReplicas}{"\t"}{.status.replicas}{"\n"}{end}' 2>/dev/null || true) + fi + + while IFS=$'\t' read -r ns ready replicas; do + [[ -z "$ns" ]] && continue + ready=${ready:-0} + replicas=${replicas:-0} + if (( ready >= 1 && replicas >= 1 )); then + plugin_deploy_ready=1 + plugin_ns="$ns" + break + fi + done <<< "$deployment_rows" + + if (( plugin_deploy_ready == 1 )); then + svc_ns="${plugin_ns:-$CNPG_OPERATOR_NAMESPACE}" + svc_name=$(kubectl -n "$svc_ns" get svc -l "cnpg.io/pluginName=$BARMAN_PLUGIN_NAME" -o jsonpath='{.items[0].metadata.name}' 2>/dev/null || true) + if [[ -z "$svc_name" ]]; then + svc_name=$(kubectl -n "$svc_ns" get svc barman-cloud -o jsonpath='{.metadata.name}' 2>/dev/null || true) + fi + + if [[ -n "$svc_name" ]]; then + client_secret=$(kubectl -n "$svc_ns" get svc "$svc_name" -o jsonpath='{.metadata.annotations.cnpg\.io/pluginClientSecret}' 2>/dev/null || true) + server_secret=$(kubectl -n "$svc_ns" get svc "$svc_name" -o jsonpath='{.metadata.annotations.cnpg\.io/pluginServerSecret}' 2>/dev/null || true) + plugin_port=$(kubectl -n "$svc_ns" get svc "$svc_name" -o jsonpath='{.metadata.annotations.cnpg\.io/pluginPort}' 2>/dev/null || true) + + if [[ -n "$client_secret" && -n "$server_secret" && -n "$plugin_port" ]]; then + if kubectl -n "$svc_ns" get secret "$client_secret" >/dev/null 2>&1 && kubectl -n "$svc_ns" get secret "$server_secret" >/dev/null 2>&1; then + return 0 + fi + fi + fi + fi + + now=$(date +%s) + if (( now - start_time >= PLUGIN_READY_TIMEOUT )); then + echo "ERROR: Timed out waiting for Barman plugin infrastructure to become ready." >&2 + return 1 + fi + + echo "Waiting for Barman plugin infrastructure (deployment + service registration) ..." + sleep 5 + done +} + +wait_for_objectstore_ready() { + local timeout=${1:-$OBJECTSTORE_READY_TIMEOUT} + local start_time now elapsed + start_time=$(date +%s) + + echo "Waiting for ObjectStore '$BARMAN_OBJECT_NAME' to be Ready (timeout: ${timeout}s)..." + while true; do + local ready_cond phase + ready_cond=$(kubectl -n "$NAMESPACE" get objectstore "$BARMAN_OBJECT_NAME" \ + -o jsonpath='{range .status.conditions[?(@.type=="Ready")]}{.status}{end}' 2>/dev/null || true) + phase=$(kubectl -n "$NAMESPACE" get objectstore "$BARMAN_OBJECT_NAME" \ + -o jsonpath='{.status.phase}' 2>/dev/null || true) + + if [[ "$ready_cond" == "True" || "$ready_cond" == "true" || "$phase" == "Ready" || "$phase" == "ready" ]]; then + return 0 + fi + + now=$(date +%s) + elapsed=$((now - start_time)) + if (( elapsed >= timeout )); then + echo "ERROR: Timed out waiting for ObjectStore '$BARMAN_OBJECT_NAME' to become Ready." >&2 + kubectl -n "$NAMESPACE" get objectstore "$BARMAN_OBJECT_NAME" -o yaml 2>/dev/null >&2 || true + return 1 + fi + + sleep "$OBJECTSTORE_READY_INTERVAL" + done +} + has_successful_base_backup() { local rows name phase method backup_type phase_lc method_lc backup_type_lc rows=$(kubectl get backup -n "$NAMESPACE" -o jsonpath="{range .items[?(@.spec.cluster.name=='$CNPG_CLUSTER_NAME')]}{.metadata.name}{\"\t\"}{.status.phase}{\"\t\"}{.spec.method}{\"\t\"}{.spec.pluginConfiguration.parameters.backupType}{\"\n\"}{end}" 2>/dev/null || true) @@ -619,7 +709,9 @@ case "$ACTION" in wait_for_apiserver_ready 180 ensure_cluster ensure_garage_bucket_and_key + wait_for_barman_plugin_infra_ready apply_barman_object_store + wait_for_objectstore_ready ensure_barman_plugin_config ensure_cluster_backup_config wait_for_plugin_ready @@ -642,7 +734,9 @@ case "$ACTION" in ensure_namespace wait_for_apiserver_ready 180 ensure_cluster + wait_for_barman_plugin_infra_ready apply_barman_object_store + wait_for_objectstore_ready ensure_barman_plugin_config ensure_cluster_backup_config wait_for_plugin_ready diff --git a/infrastructure/inventory/host_vars/merlin.prole.org.yml b/infrastructure/inventory/host_vars/merlin.prole.org.yml index 74a4c63..617c7b1 100644 --- a/infrastructure/inventory/host_vars/merlin.prole.org.yml +++ b/infrastructure/inventory/host_vars/merlin.prole.org.yml @@ -49,11 +49,26 @@ k3s_service_node_labels: - "prole.org/node-role=general" k3s_node_taints: [] +k3s_required_mounts: + - /synology/d002 + - /synology/d004 + # iSCSI # `/var/lib/rancher` is local host storage (do not manage it via iSCSI). iscsi_portal: 10.0.0.203:3260 iscsi_targets: + # PROLE-DATA-2 + - iqn: "iqn.2000-01.com.synology:synology.Target-12.292d45194a1" + chap_user: "prole" + chap_password: "{{ vault_iscsi_prole_password }}" + mounts: + - name: d002 + path: /synology/d002 + fstype: xfs + opts: "_netdev,noatime" + src: "UUID=fe087fb0-a321-4767-b838-b4385e81693e" + # PROLE-DATA-4 # Repurposed from myrddin's former `/var/lib/rancher` Synology LUN. - iqn: "iqn.2000-01.com.synology:synology.Target-15.292d45194a1" @@ -61,7 +76,7 @@ iscsi_targets: chap_password: "{{ vault_iscsi_prole_password }}" mounts: - name: d004 - path: /prole/d004 + path: /synology/d004 fstype: xfs opts: "_netdev,noatime" mkfs_if_missing: true diff --git a/infrastructure/inventory/host_vars/myrddin.prole.org.yml b/infrastructure/inventory/host_vars/myrddin.prole.org.yml index 0304812..c82a22b 100644 --- a/infrastructure/inventory/host_vars/myrddin.prole.org.yml +++ b/infrastructure/inventory/host_vars/myrddin.prole.org.yml @@ -1,36 +1,16 @@ iscsi_portal: 10.0.0.203 iscsi_targets: - # PROLE-DB-1 + # PROLE-DATA-1 - iqn: "iqn.2000-01.com.synology:synology.Target-11.292d45194a1" chap_user: "prole" chap_password: "{{ vault_iscsi_prole_password }}" mounts: - - path: /prole/d001 + - path: /synology/d001 fstype: xfs opts: "_netdev,noatime" src: "UUID=c07dc0f2-cf60-4da5-b68e-ea45e86d473e" - # PROLE-DB-2 - - iqn: "iqn.2000-01.com.synology:synology.Target-12.292d45194a1" - chap_user: "prole" - chap_password: "{{ vault_iscsi_prole_password }}" - mounts: - - path: /prole/d002 - fstype: xfs - opts: "_netdev,noatime" - src: "UUID=fe087fb0-a321-4767-b838-b4385e81693e" - - # PROLE-DB-3 - - iqn: "iqn.2000-01.com.synology:synology.Target-13.292d45194a1" - chap_user: "prole" - chap_password: "{{ vault_iscsi_prole_password }}" - mounts: - - path: /prole/d003 - fstype: xfs - opts: "_netdev,noatime" - src: "UUID=757f1ee4-dc23-414b-b595-e3058c0744f0" - # PROLE-HOME - iqn: "iqn.2000-01.com.synology:synology.Target-17.292d45194a1" chap_user: "prole" @@ -53,6 +33,18 @@ iscsi_targets: iscsi_absent_mounts: - /opt/prole/logs/chrisfu + # Migration cleanup: PROLE-DATA-2/3 are moving off myrddin + - /prole/d002 + - /prole/d003 + - /synology/d002 + - /synology/d003 + +# Migration cleanup: ensure myrddin fully logs out of LUNs that are moving to other hosts +iscsi_absent_targets: + # PROLE-DATA-2 + - "iqn.2000-01.com.synology:synology.Target-12.292d45194a1" + # PROLE-DATA-3 + - "iqn.2000-01.com.synology:synology.Target-13.292d45194a1" ad_dc_enabled: true @@ -122,6 +114,4 @@ k3s_kubeconfig_users: - pi k3s_required_mounts: - - /prole/d001 - - /prole/d002 - - /prole/d003 + - /synology/d001 diff --git a/infrastructure/inventory/host_vars/pi.prole.org.yml b/infrastructure/inventory/host_vars/pi.prole.org.yml index 8476d7f..b2f4c67 100644 --- a/infrastructure/inventory/host_vars/pi.prole.org.yml +++ b/infrastructure/inventory/host_vars/pi.prole.org.yml @@ -1,8 +1,21 @@ iscsi_portal: 10.0.0.203 +k3s_required_mounts: + - /synology/d003 + iscsi_targets: # `/var/lib/rancher` is local host storage (do not manage it via iSCSI). + # PROLE-DATA-3 + - iqn: "iqn.2000-01.com.synology:synology.Target-13.292d45194a1" + chap_user: "prole" + chap_password: "{{ vault_iscsi_prole_password }}" + mounts: + - path: /synology/d003 + fstype: xfs + opts: "_netdev,noatime" + src: "UUID=757f1ee4-dc23-414b-b595-e3058c0744f0" + # PROLE-PI-2 - iqn: "iqn.2000-01.com.synology:synology.Target-19.292d45194a1" chap_user: "prole" diff --git a/infrastructure/playbooks/site.yml b/infrastructure/playbooks/site.yml index b76d906..ac6f16c 100644 --- a/infrastructure/playbooks/site.yml +++ b/infrastructure/playbooks/site.yml @@ -23,6 +23,37 @@ roles: - cgroups +- name: Tier 1.5 - Quiesce k3s and detach migrated iSCSI LUNs (myrddin) + hosts: myrddin.prole.org + gather_facts: false + become: true + pre_tasks: + - name: Gather minimal facts + ansible.builtin.setup: + gather_subset: + - min + tasks: + - name: Check if k3s systemd unit exists + ansible.builtin.stat: + path: /etc/systemd/system/k3s.service + register: _k3s_unit + + - name: Stop k3s (quiesce before iSCSI detach) + ansible.builtin.systemd: + name: k3s + state: stopped + when: + - not ansible_check_mode + - _k3s_unit.stat.exists | default(false) + - (iscsi_absent_mounts | default([]) | length) > 0 or (iscsi_absent_targets | default([]) | length) > 0 + + - name: Detach migrated iSCSI targets/mounts (best-effort cleanup) + ansible.builtin.import_role: + name: iscsi + tasks_from: detach + when: + - (iscsi_absent_mounts | default([]) | length) > 0 or (iscsi_absent_targets | default([]) | length) > 0 + - name: Tier 2 - Storage (iSCSI auth/login) hosts: iscsi gather_facts: false diff --git a/infrastructure/playbooks/tmp_bao_dir.yml b/infrastructure/playbooks/tmp_bao_dir.yml index bac0b8f..9418d46 100644 --- a/infrastructure/playbooks/tmp_bao_dir.yml +++ b/infrastructure/playbooks/tmp_bao_dir.yml @@ -4,6 +4,6 @@ tasks: - name: Ensure OpenBao storage directory exists ansible.builtin.file: - path: /prole/d001/openbao + path: /synology/d001/openbao state: directory mode: "0777" # OpenBao pod runs as non-root usually, but k3s local-path often needs this or specific UID diff --git a/infrastructure/roles/iscsi/tasks/detach.yml b/infrastructure/roles/iscsi/tasks/detach.yml new file mode 100644 index 0000000..3c106a8 --- /dev/null +++ b/infrastructure/roles/iscsi/tasks/detach.yml @@ -0,0 +1,69 @@ +--- +- name: Require iscsi_portal when logging out absent targets + ansible.builtin.assert: + that: + - iscsi_portal is defined + - (iscsi_portal | string | length) > 0 + fail_msg: "iscsi_absent_targets is set but iscsi_portal is missing/empty." + when: (iscsi_absent_targets | default([]) | length) > 0 + +- name: Unmount absent iSCSI mountpoints + ansible.builtin.mount: + path: "{{ item.path | default(item) }}" + state: unmounted + loop: "{{ iscsi_absent_mounts | default([]) }}" + loop_control: + label: "{{ item.path | default(item) }}" + tags: + - iscsi_cleanup + +- name: Remove absent iSCSI fstab entries + ansible.builtin.lineinfile: + path: /etc/fstab + state: absent + regexp: "^\\s*\\S+\\s+{{ (item.path | default(item)) | regex_escape }}\\s+" + loop: "{{ iscsi_absent_mounts | default([]) }}" + loop_control: + label: "{{ item.path | default(item) }}" + tags: + - iscsi_cleanup + +- name: Check for active sessions for absent targets + ansible.builtin.shell: >- + iscsiadm -m session 2>/dev/null | grep -Fq -- {{ item | quote }} + register: _iscsi_absent_target_session_checks + changed_when: false + failed_when: false + loop: "{{ iscsi_absent_targets | default([]) }}" + loop_control: + label: "{{ item }}" + when: (iscsi_absent_targets | default([]) | length) > 0 + tags: + - iscsi_cleanup + +- name: Logout absent iSCSI targets (active sessions only) + ansible.builtin.command: >- + iscsiadm -m node -T {{ item.item }} -p {{ iscsi_portal }} --logout + register: _iscsi_absent_target_logout + changed_when: false + failed_when: false + loop: "{{ _iscsi_absent_target_session_checks.results | default([]) }}" + loop_control: + label: "{{ item.item }}" + when: + - (iscsi_absent_targets | default([]) | length) > 0 + - item.rc == 0 + tags: + - iscsi_cleanup + +- name: Delete node records for absent iSCSI targets (best-effort) + ansible.builtin.command: >- + iscsiadm -m node -o delete -T {{ item }} -p {{ iscsi_portal }} + changed_when: false + failed_when: false + loop: "{{ iscsi_absent_targets | default([]) }}" + loop_control: + label: "{{ item }}" + when: (iscsi_absent_targets | default([]) | length) > 0 + tags: + - iscsi_cleanup \ No newline at end of file diff --git a/infrastructure/roles/iscsi/tasks/iscsi_mount.yml b/infrastructure/roles/iscsi/tasks/iscsi_mount.yml index 7e5b771..bb9f82a 100644 --- a/infrastructure/roles/iscsi/tasks/iscsi_mount.yml +++ b/infrastructure/roles/iscsi/tasks/iscsi_mount.yml @@ -111,6 +111,7 @@ register: _iscsi_blkid_type changed_when: false failed_when: false + check_mode: no when: - _iscsi_need_blockdev | default(false) | bool - _iscsi_blockdev is defined @@ -287,6 +288,7 @@ ansible.builtin.command: "blkid -o value -s UUID {{ _iscsi_blockdev }}" register: _iscsi_blkid_uuid changed_when: false + check_mode: no when: - (_iscsi_mount_src | default('') | string | length) == 0 - _iscsi_blockdev is defined @@ -302,7 +304,9 @@ - _iscsi_blkid_uuid is defined - (_iscsi_blkid_uuid.stdout | default('') | trim) != '' fail_msg: "Unable to resolve a filesystem UUID for {{ m.path }} from {{ _iscsi_blockdev }}." - when: (_iscsi_mount_src | default('') | string | length) == 0 + when: + - (_iscsi_mount_src | default('') | string | length) == 0 + - not (ansible_check_mode and ((m.mkfs_once | default(false) | bool) or (m.mkfs_if_missing | default(false) | bool))) tags: - iscsi - iscsi_mount @@ -311,7 +315,10 @@ - name: Set mount source to UUID ansible.builtin.set_fact: _iscsi_mount_src: "UUID={{ _iscsi_blkid_uuid.stdout | trim }}" - when: (_iscsi_mount_src | default('') | string | length) == 0 + when: + - (_iscsi_mount_src | default('') | string | length) == 0 + - _iscsi_blkid_uuid is defined + - (_iscsi_blkid_uuid.stdout | default('') | trim) != '' tags: - iscsi - iscsi_mount @@ -324,6 +331,7 @@ fstype: "{{ m.fstype | default('ext4') }}" opts: "{{ m.opts | default('_netdev,noatime') }}" state: mounted + when: (_iscsi_mount_src | default('') | string | trim | length) > 0 tags: - iscsi - iscsi_mount diff --git a/infrastructure/roles/iscsi/tasks/iscsi_target.yml b/infrastructure/roles/iscsi/tasks/iscsi_target.yml index 9be4b1d..8829812 100644 --- a/infrastructure/roles/iscsi/tasks/iscsi_target.yml +++ b/infrastructure/roles/iscsi/tasks/iscsi_target.yml @@ -31,8 +31,8 @@ no_log: true - name: Check if target session is already logged in - ansible.builtin.command: > - iscsiadm -m session -T {{ t.iqn }} -p {{ iscsi_portal }} + ansible.builtin.shell: >- + iscsiadm -m session 2>/dev/null | grep -Fq -- {{ t.iqn | quote }} register: session_check changed_when: false failed_when: false @@ -46,8 +46,8 @@ when: session_check.rc != 0 - name: Re-check session after login attempt - ansible.builtin.command: > - iscsiadm -m session -T {{ t.iqn }} -p {{ iscsi_portal }} + ansible.builtin.shell: >- + iscsiadm -m session 2>/dev/null | grep -Fq -- {{ t.iqn | quote }} register: session_after_login changed_when: false failed_when: false @@ -55,7 +55,12 @@ - name: Fail if login did not establish a session ansible.builtin.fail: - msg: "iSCSI login failed for {{ t.iqn }} at {{ iscsi_portal }}" + msg: |- + iSCSI login failed for {{ t.iqn }} at {{ iscsi_portal }}. + + login.rc={{ login.rc | default('') }} + login.stdout={{ (login.stdout | default('')) | trim }} + login.stderr={{ (login.stderr | default('')) | trim }} when: - session_check.rc != 0 - session_after_login is defined diff --git a/infrastructure/roles/iscsi/tasks/mount.yml b/infrastructure/roles/iscsi/tasks/mount.yml index da08d23..a1f1bd7 100644 --- a/infrastructure/roles/iscsi/tasks/mount.yml +++ b/infrastructure/roles/iscsi/tasks/mount.yml @@ -1,4 +1,41 @@ --- +- name: Compute legacy mountpoints to clean up (/prole/d00x -> /synology/d00x) + ansible.builtin.set_fact: + _iscsi_legacy_absent_mounts: >- + {{ + (iscsi_targets | default([]) + | map(attribute='mounts') | list | flatten + | selectattr('path', 'defined') + | map(attribute='path') | list + | select('match', '^/synology/d[0-9]{3}$') + | map('regex_replace', '^/synology/', '/prole/') + | list) + }} + changed_when: false + tags: + - iscsi_cleanup + +- name: Unmount legacy iSCSI mounts (old /prole/d00x layout) + ansible.builtin.mount: + path: "{{ item }}" + state: unmounted + loop: "{{ _iscsi_legacy_absent_mounts | default([]) }}" + loop_control: + label: "{{ item }}" + tags: + - iscsi_cleanup + +- name: Remove legacy iSCSI fstab entries (old /prole/d00x layout) + ansible.builtin.lineinfile: + path: /etc/fstab + state: absent + regexp: "^\\s*\\S+\\s+{{ item | regex_escape }}\\s+" + loop: "{{ _iscsi_legacy_absent_mounts | default([]) }}" + loop_control: + label: "{{ item }}" + tags: + - iscsi_cleanup + - name: Unmount stale iSCSI mounts ansible.builtin.mount: path: "{{ item.path | default(item) }}" diff --git a/infrastructure/roles/k3s/tasks/configure.yml b/infrastructure/roles/k3s/tasks/configure.yml index 15e1a31..e7be5c4 100644 --- a/infrastructure/roles/k3s/tasks/configure.yml +++ b/infrastructure/roles/k3s/tasks/configure.yml @@ -99,28 +99,48 @@ - k3s_prestage_images | bool tags: [images] -- name: Create ArgoCD hostPath directories on myrddin.prole.org +- name: Create ArgoCD hostPath directories on myrddin.prole.org (/synology/d001) ansible.builtin.file: path: "{{ item }}" state: directory mode: "0777" loop: - - /prole/d001/argocd - - /prole/d001/argocd/home - - /prole/d001/argocd/tmp - - /prole/d002/argocd - - /prole/d002/argocd/data - - /prole/d002/argocd/tmp - - /prole/d003/argocd - - /prole/d003/argocd/gpg-keyring - - /prole/d003/argocd/tmp - - /prole/d003/argocd/helm-working-dir - - /prole/d003/argocd/var-files - - /prole/d003/argocd/plugins + - /synology/d001/argocd + - /synology/d001/argocd/home + - /synology/d001/argocd/tmp when: - k3s_state == "present" - inventory_hostname == 'myrddin.prole.org' +- name: Create ArgoCD hostPath directories on merlin.prole.org (/synology/d002) + ansible.builtin.file: + path: "{{ item }}" + state: directory + mode: "0777" + loop: + - /synology/d002/argocd + - /synology/d002/argocd/data + - /synology/d002/argocd/tmp + when: + - k3s_state == "present" + - inventory_hostname == 'merlin.prole.org' + +- name: Create ArgoCD hostPath directories on pi.prole.org (/synology/d003) + ansible.builtin.file: + path: "{{ item }}" + state: directory + mode: "0777" + loop: + - /synology/d003/argocd + - /synology/d003/argocd/gpg-keyring + - /synology/d003/argocd/tmp + - /synology/d003/argocd/helm-working-dir + - /synology/d003/argocd/var-files + - /synology/d003/argocd/plugins + when: + - k3s_state == "present" + - inventory_hostname == 'pi.prole.org' + - name: Wait for k3s Kubernetes API to become ready ansible.builtin.command: k3s kubectl get --raw='/readyz' register: _k3s_readyz diff --git a/infrastructure/roles/k3s/tasks/install.yml b/infrastructure/roles/k3s/tasks/install.yml index 3e8e1f0..90a0d2e 100644 --- a/infrastructure/roles/k3s/tasks/install.yml +++ b/infrastructure/roles/k3s/tasks/install.yml @@ -71,7 +71,7 @@ RequiresMountsFor={{ k3s_rancher_mountpoint }} [Service] - ExecStartPre=/bin/sh -ec 'rancher_src="$(findmnt -n -o SOURCE -T {{ k3s_rancher_mountpoint }})"; root_src="$(findmnt -n -o SOURCE -T /)"; if [ "${rancher_src}" = "${root_src}" ]; then echo "Refusing to start k3s: {{ k3s_rancher_mountpoint }} resolves to rootfs (${root_src}). Expected a dedicated mount." >&2; exit 1; fi' + ExecStartPre=/bin/sh -ec 'rancher_src="$(findmnt -n -o SOURCE -T {{ k3s_rancher_mountpoint }})"; root_src="$(findmnt -n -o SOURCE -T /)"; if [ "$${rancher_src}" = "$${root_src}" ]; then echo "Refusing to start k3s: {{ k3s_rancher_mountpoint }} resolves to rootfs ($${root_src}). Expected a dedicated mount." >&2; exit 1; fi' register: _k3s_rancher_mount_guard_dropin when: ansible_service_mgr | default('') == 'systemd' diff --git a/k8s/argocd/install.yaml b/k8s/argocd/install.yaml index e6f1de5..152e6dc 100644 --- a/k8s/argocd/install.yaml +++ b/k8s/argocd/install.yaml @@ -32161,11 +32161,11 @@ spec: serviceAccountName: argocd-redis volumes: - hostPath: - path: /prole/d002/argocd/data + path: /synology/d002/argocd/data type: DirectoryOrCreate name: argocd-redis-data - hostPath: - path: /prole/d002/argocd/tmp + path: /synology/d002/argocd/tmp type: DirectoryOrCreate name: argocd-redis-tmp @@ -32582,15 +32582,15 @@ spec: name: argocd-gpg-keys-cm name: gpg-keys - hostPath: - path: /prole/d003/argocd/gpg-keyring + path: /synology/d003/argocd/gpg-keyring type: DirectoryOrCreate name: gpg-keyring - hostPath: - path: /prole/d003/argocd/tmp + path: /synology/d003/argocd/tmp type: DirectoryOrCreate name: tmp - hostPath: - path: /prole/d003/argocd/helm-working-dir + path: /synology/d003/argocd/helm-working-dir type: DirectoryOrCreate name: helm-working-dir - name: argocd-repo-server-tls @@ -32605,11 +32605,11 @@ spec: optional: true secretName: argocd-repo-server-tls - hostPath: - path: /prole/d003/argocd/var-files + path: /synology/d003/argocd/var-files type: DirectoryOrCreate name: var-files - hostPath: - path: /prole/d003/argocd/plugins + path: /synology/d003/argocd/plugins type: DirectoryOrCreate name: plugins @@ -33359,11 +33359,11 @@ spec: serviceAccountName: argocd-application-controller volumes: - hostPath: - path: /prole/d001/argocd/home + path: /synology/d001/argocd/home type: DirectoryOrCreate name: argocd-home - hostPath: - path: /prole/d001/argocd/tmp + path: /synology/d001/argocd/tmp type: DirectoryOrCreate name: argocd-application-controller-tmp - name: argocd-repo-server-tls diff --git a/k8s/prole/iscsi-pvs.yaml b/k8s/prole/iscsi-pvs.yaml index 6a2a1d7..aaa9bb9 100644 --- a/k8s/prole/iscsi-pvs.yaml +++ b/k8s/prole/iscsi-pvs.yaml @@ -14,7 +14,7 @@ spec: storageClassName: prole-iscsi persistentVolumeReclaimPolicy: Retain local: - path: /prole/d001/data + path: /synology/d001/data nodeAffinity: required: nodeSelectorTerms: @@ -40,7 +40,7 @@ spec: storageClassName: prole-iscsi persistentVolumeReclaimPolicy: Retain local: - path: /prole/d001/wal + path: /synology/d001/wal nodeAffinity: required: nodeSelectorTerms: @@ -66,7 +66,7 @@ spec: storageClassName: prole-iscsi persistentVolumeReclaimPolicy: Retain local: - path: /prole/d001/garage + path: /synology/d001/garage nodeAffinity: required: nodeSelectorTerms: @@ -92,7 +92,7 @@ spec: storageClassName: prole-iscsi persistentVolumeReclaimPolicy: Retain local: - path: /prole/d002/data + path: /synology/d002/data nodeAffinity: required: nodeSelectorTerms: @@ -100,7 +100,7 @@ spec: - key: kubernetes.io/hostname operator: In values: - - myrddin.prole.org + - merlin.prole.org --- apiVersion: v1 kind: PersistentVolume @@ -118,7 +118,7 @@ spec: storageClassName: prole-iscsi persistentVolumeReclaimPolicy: Retain local: - path: /prole/d002/wal + path: /synology/d002/wal nodeAffinity: required: nodeSelectorTerms: @@ -126,7 +126,7 @@ spec: - key: kubernetes.io/hostname operator: In values: - - myrddin.prole.org + - merlin.prole.org --- apiVersion: v1 kind: PersistentVolume @@ -144,7 +144,7 @@ spec: storageClassName: prole-iscsi persistentVolumeReclaimPolicy: Retain local: - path: /prole/d003/data + path: /synology/d003/data nodeAffinity: required: nodeSelectorTerms: @@ -152,7 +152,7 @@ spec: - key: kubernetes.io/hostname operator: In values: - - myrddin.prole.org + - pi.prole.org --- apiVersion: v1 kind: PersistentVolume @@ -170,7 +170,7 @@ spec: storageClassName: prole-iscsi persistentVolumeReclaimPolicy: Retain local: - path: /prole/d003/wal + path: /synology/d003/wal nodeAffinity: required: nodeSelectorTerms: @@ -178,7 +178,7 @@ spec: - key: kubernetes.io/hostname operator: In values: - - myrddin.prole.org + - pi.prole.org --- apiVersion: v1 kind: PersistentVolume @@ -196,7 +196,7 @@ spec: storageClassName: prole-iscsi persistentVolumeReclaimPolicy: Retain local: - path: /prole/d003/grafana + path: /synology/d003/grafana nodeAffinity: required: nodeSelectorTerms: @@ -204,7 +204,7 @@ spec: - key: kubernetes.io/hostname operator: In values: - - myrddin.prole.org + - pi.prole.org --- apiVersion: v1 kind: PersistentVolume @@ -222,7 +222,7 @@ spec: storageClassName: prole-iscsi persistentVolumeReclaimPolicy: Retain local: - path: /prole/d002/prometheus + path: /synology/d002/prometheus nodeAffinity: required: nodeSelectorTerms: @@ -230,7 +230,7 @@ spec: - key: kubernetes.io/hostname operator: In values: - - myrddin.prole.org + - merlin.prole.org --- apiVersion: v1 kind: PersistentVolume @@ -248,7 +248,7 @@ spec: storageClassName: prole-iscsi persistentVolumeReclaimPolicy: Retain local: - path: /prole/d001/openbao + path: /synology/d001/openbao nodeAffinity: required: nodeSelectorTerms: diff --git a/k8s/prole/monitoring-d004-pvs.yaml b/k8s/prole/monitoring-d004-pvs.yaml index b096eba..9dba63d 100644 --- a/k8s/prole/monitoring-d004-pvs.yaml +++ b/k8s/prole/monitoring-d004-pvs.yaml @@ -14,7 +14,7 @@ spec: storageClassName: prole-monitoring-d004 persistentVolumeReclaimPolicy: Retain local: - path: /prole/d004/prometheus + path: /synology/d004/prometheus nodeAffinity: required: nodeSelectorTerms: @@ -40,7 +40,7 @@ spec: storageClassName: prole-monitoring-d004 persistentVolumeReclaimPolicy: Retain local: - path: /prole/d004/alertmanager + path: /synology/d004/alertmanager nodeAffinity: required: nodeSelectorTerms: @@ -66,7 +66,7 @@ spec: storageClassName: prole-monitoring-d004 persistentVolumeReclaimPolicy: Retain local: - path: /prole/d004/grafana + path: /synology/d004/grafana nodeAffinity: required: nodeSelectorTerms: diff --git a/k8s/prole/prole-db-recovery.yaml.tpl b/k8s/prole/prole-db-recovery.yaml.tpl index 5989175..0225f0a 100644 --- a/k8s/prole/prole-db-recovery.yaml.tpl +++ b/k8s/prole/prole-db-recovery.yaml.tpl @@ -5,7 +5,7 @@ metadata: name: prole-db spec: instances: 3 - imageName: myrddin.prole.org:5000/prole-db:18-129 + imageName: myrddin.prole.org:5000/prole-db:0.0.0 postgresUID: 100 postgresGID: 101 maxSyncReplicas: 1 diff --git a/prole-db/.version b/prole-db/.version index 6d3e9dc..8306ec1 100644 --- a/prole-db/.version +++ b/prole-db/.version @@ -1 +1 @@ -129 \ No newline at end of file +130 \ No newline at end of file diff --git a/tests/etc/test_cnpg_k3s_storage_guards.sh b/tests/etc/test_cnpg_k3s_storage_guards.sh index 9c27d36..1f46361 100644 --- a/tests/etc/test_cnpg_k3s_storage_guards.sh +++ b/tests/etc/test_cnpg_k3s_storage_guards.sh @@ -105,6 +105,32 @@ if [[ "$args" == *"-n cnpg-system get secret"*"barman-cloud-"*"-o jsonpath="* ]] exit 0 fi +# Barman plugin service registration readiness (strict gating) +if [[ "$args" == *"-n cnpg-system get svc"*"-l cnpg.io/pluginName=barman-cloud.cloudnative-pg.io"*"-o jsonpath="*"metadata.name"* ]]; then + echo "barman-cloud" + exit 0 +fi +if [[ "$args" == *"-n cnpg-system get svc barman-cloud"*"-o jsonpath="*"metadata.name"* ]]; then + echo "barman-cloud" + exit 0 +fi +if [[ "$args" == *"-n cnpg-system get svc barman-cloud"*"pluginClientSecret"* ]]; then + echo "barman-cloud-client-tls" + exit 0 +fi +if [[ "$args" == *"-n cnpg-system get svc barman-cloud"*"pluginServerSecret"* ]]; then + echo "barman-cloud-server-tls" + exit 0 +fi +if [[ "$args" == *"-n cnpg-system get svc barman-cloud"*"pluginPort"* ]]; then + echo "9090" + exit 0 +fi +if [[ "$args" == *"-n cnpg-system get endpoints barman-cloud"* ]]; then + echo "10.42.0.11" + exit 0 +fi + # DB node availability checks (bootstrap safety) if [[ "$args" == *"get nodes"*"--no-headers"* ]]; then # Name Status Roles Age Version diff --git a/tests/etc/test_init_cloudnative_pg_bootstrap_admin_keys.sh b/tests/etc/test_init_cloudnative_pg_bootstrap_admin_keys.sh index 0dc9837..0a8f65e 100644 --- a/tests/etc/test_init_cloudnative_pg_bootstrap_admin_keys.sh +++ b/tests/etc/test_init_cloudnative_pg_bootstrap_admin_keys.sh @@ -68,6 +68,47 @@ if [[ "${args}" == *"get endpoints"*"cnpg-webhook-service"* ]]; then exit 0 fi +# Avoid barman plugin waits (strict readiness now includes service registration) +if [[ "${args}" == *"get crd"*"objectstores.barmancloud.cnpg.io"* ]]; then + exit 0 +fi +if [[ "${args}" == *"-n cnpg-system"*"get secret"*"barman-cloud-client-tls"* ]]; then + exit 0 +fi +if [[ "${args}" == *"-n cnpg-system"*"get secret"*"barman-cloud-server-tls"* ]]; then + exit 0 +fi +if [[ "${args}" == *"-n cnpg-system"*"get deploy"*"barman-cloud"* ]]; then + exit 0 +fi +if [[ "${args}" == *"-n cnpg-system"*"rollout status"*"deploy/barman-cloud"* ]]; then + exit 0 +fi +if [[ "${args}" == *"-n cnpg-system"*"get svc"*"-l cnpg.io/pluginName=barman-cloud.cloudnative-pg.io"*"-o jsonpath="*"metadata.name"* ]]; then + echo "barman-cloud" + exit 0 +fi +if [[ "${args}" == *"-n cnpg-system"*"get svc barman-cloud"*"-o jsonpath="*"metadata.name"* ]]; then + echo "barman-cloud" + exit 0 +fi +if [[ "${args}" == *"-n cnpg-system"*"get svc barman-cloud"*"pluginClientSecret"* ]]; then + echo "barman-cloud-client-tls" + exit 0 +fi +if [[ "${args}" == *"-n cnpg-system"*"get svc barman-cloud"*"pluginServerSecret"* ]]; then + echo "barman-cloud-server-tls" + exit 0 +fi +if [[ "${args}" == *"-n cnpg-system"*"get svc barman-cloud"*"pluginPort"* ]]; then + echo "9090" + exit 0 +fi +if [[ "${args}" == *"-n cnpg-system"*"get endpoints barman-cloud"* ]]; then + echo "10.42.0.11" + exit 0 +fi + # CNPG pods listing and readiness queries if [[ "${args}" == *"get pods"* && "${args}" == *"cnpg.io/cluster="* ]]; then if [[ "${args}" == *"--no-headers"* ]]; then diff --git a/tests/etc/test_init_cloudnative_pg_instances.sh b/tests/etc/test_init_cloudnative_pg_instances.sh index c6e3f8e..07100d2 100644 --- a/tests/etc/test_init_cloudnative_pg_instances.sh +++ b/tests/etc/test_init_cloudnative_pg_instances.sh @@ -65,7 +65,7 @@ if [[ "${args}" == *"-n cert-manager"*"get deploy"* ]]; then fi # Avoid barman plugin waits -if [[ "${args}" == *"get crd"*"barmanobjectstores.barmancloud.cnpg.io"* ]]; then +if [[ "${args}" == *"get crd"*"objectstores.barmancloud.cnpg.io"* ]]; then exit 0 fi if [[ "${args}" == *"-n cnpg-system"*"get secret"*"barman-cloud-client-tls"* ]]; then @@ -74,19 +74,90 @@ fi if [[ "${args}" == *"-n cnpg-system"*"get secret"*"barman-cloud-server-tls"* ]]; then exit 0 fi +if [[ "${args}" == *"-n cnpg-system"*"get deploy"*"barman-cloud"* ]]; then + exit 0 +fi +if [[ "${args}" == *"-n cnpg-system"*"rollout status"*"deploy/barman-cloud"* ]]; then + exit 0 +fi +if [[ "${args}" == *"-n cnpg-system"*"get svc"*"-l cnpg.io/pluginName=barman-cloud.cloudnative-pg.io"*"-o jsonpath="*"metadata.name"* ]]; then + echo "barman-cloud" + exit 0 +fi +if [[ "${args}" == *"-n cnpg-system"*"get svc barman-cloud"*"-o jsonpath="*"metadata.name"* ]]; then + echo "barman-cloud" + exit 0 +fi +if [[ "${args}" == *"-n cnpg-system"*"get svc barman-cloud"*"pluginClientSecret"* ]]; then + echo "barman-cloud-client-tls" + exit 0 +fi +if [[ "${args}" == *"-n cnpg-system"*"get svc barman-cloud"*"pluginServerSecret"* ]]; then + echo "barman-cloud-server-tls" + exit 0 +fi +if [[ "${args}" == *"-n cnpg-system"*"get svc barman-cloud"*"pluginPort"* ]]; then + echo "9090" + exit 0 +fi +if [[ "${args}" == *"-n cnpg-system"*"get endpoints barman-cloud"* ]]; then + echo "10.42.0.11" + exit 0 +fi # Namespace check in ensure_namespace() if [[ "${args}" == "get namespace test-ns" ]]; then exit 0 fi -# Capture applied CNPG manifest -if [[ "${args}" == apply* && "${args}" == *"-n"*"test-ns"* && "${args}" == *"-f"*"-"* ]]; then - cat > "${TMP_DIR}/applied.yaml" +# Capture applied CNPG manifest (stdin or file) +if [[ "${args}" == apply* && "${args}" == *"-n"*"test-ns"* && "${args}" == *" -f "* ]]; then + f="" + if [[ "$#" -ge 2 ]]; then + for ((i=1; i<=$#; i++)); do + if [[ "${!i}" == "-f" ]]; then + j=$((i+1)) + f="${!j:-}" + break + fi + done + fi + if [[ "${f}" == "-" ]]; then + cat > "${TMP_DIR}/applied.yaml" + elif [[ -n "${f}" && -f "${f}" ]]; then + cat "${f}" > "${TMP_DIR}/applied.yaml" + else + : > "${TMP_DIR}/applied.yaml" + fi echo "cluster.postgresql.cnpg.io/prole-db configured" exit 0 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"}}}}}} +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"}} +]} +JSON + exit 0 +fi +if [[ "${args}" == "get pv pv-data -o json"* ]]; then + echo '{"spec":{"storageClassName":"prole-iscsi","local":{"path":"/prole/d001/data"}}}' + exit 0 +fi +if [[ "${args}" == "get pv pv-wal -o json"* ]]; then + echo '{"spec":{"storageClassName":"prole-iscsi","local":{"path":"/prole/d001/wal"}}}' + exit 0 +fi + # Node inventory used by reconcile_cnpg_instances if [[ "${args}" == "get nodes --no-headers" ]]; then n="${MOCK_READY_NODES:-1}" @@ -133,7 +204,6 @@ mock_tool ansible-playbook mock_tool tofu mock_tool terraform mock_tool ollama -mock_tool jq export PATH="$BIN_DIR:$PATH" export TMP_DIR @@ -178,7 +248,10 @@ E_EOF rm -f "$TMP_DIR/applied.yaml" rm -f "$TMP_DIR/mock_cluster_instances" set +e - MOCK_READY_NODES="$mock_ready_nodes" MOCK_DB_NODES="$mock_db_nodes" PROLE_HOME="$env_home" \ + MOCK_READY_NODES="$mock_ready_nodes" MOCK_DB_NODES="$mock_db_nodes" \ + BARMAN_CRD_TIMEOUT=5 BARMAN_TLS_TIMEOUT=5 BARMAN_DEPLOY_TIMEOUT=5 BARMAN_SERVICE_TIMEOUT=5 \ + CNPG_STORAGE_VALIDATE_TIMEOUT=5 \ + PROLE_HOME="$env_home" \ bash "$SCRIPT_UNDER_TEST" --mode k3s start >/dev/null 2>"$TMP_DIR/stderr-${label}" local rc=$? set -e diff --git a/tests/etc/test_init_cloudnative_pg_no_kong_in_db_namespace.sh b/tests/etc/test_init_cloudnative_pg_no_kong_in_db_namespace.sh index b2aa142..0717e87 100644 --- a/tests/etc/test_init_cloudnative_pg_no_kong_in_db_namespace.sh +++ b/tests/etc/test_init_cloudnative_pg_no_kong_in_db_namespace.sh @@ -117,6 +117,38 @@ if [[ "${args}" == *"get crd"* ]]; then exit 0 fi +# Barman plugin strict readiness checks (service registration) +if [[ "${args}" == *"-n cnpg-system"*"get deploy"*"barman-cloud"* ]]; then + exit 0 +fi +if [[ "${args}" == *"-n cnpg-system"*"rollout status"*"deploy/barman-cloud"* ]]; then + exit 0 +fi +if [[ "${args}" == *"-n cnpg-system"*"get svc"*"-l cnpg.io/pluginName=barman-cloud.cloudnative-pg.io"*"-o jsonpath="*"metadata.name"* ]]; then + echo "barman-cloud" + exit 0 +fi +if [[ "${args}" == *"-n cnpg-system"*"get svc barman-cloud"*"-o jsonpath="*"metadata.name"* ]]; then + echo "barman-cloud" + exit 0 +fi +if [[ "${args}" == *"-n cnpg-system"*"get svc barman-cloud"*"pluginClientSecret"* ]]; then + echo "barman-cloud-client-tls" + exit 0 +fi +if [[ "${args}" == *"-n cnpg-system"*"get svc barman-cloud"*"pluginServerSecret"* ]]; then + echo "barman-cloud-server-tls" + exit 0 +fi +if [[ "${args}" == *"-n cnpg-system"*"get svc barman-cloud"*"pluginPort"* ]]; then + echo "9090" + exit 0 +fi +if [[ "${args}" == *"-n cnpg-system"*"get endpoints barman-cloud"* ]]; then + echo "10.42.0.11" + exit 0 +fi + # CNPG cluster instances lookup in wait_for_cnpg_pods() if [[ "${args}" == *"-n test-ns"*"get cluster"*"-o jsonpath="*".spec.instances"* ]]; then echo "3" diff --git a/tests/etc/test_init_cnpg_backup.sh b/tests/etc/test_init_cnpg_backup.sh index f86ebba..2652b0c 100644 --- a/tests/etc/test_init_cnpg_backup.sh +++ b/tests/etc/test_init_cnpg_backup.sh @@ -64,6 +64,32 @@ if [[ "${args}" == "get deployment -A -l app.kubernetes.io/name=barman-cloud -o exit 0 fi +# Barman plugin service registration (used by wait_for_barman_plugin_infra_ready) +if [[ "${args}" == *"-n cnpg-system"*"get svc"*"-l cnpg.io/pluginName=barman-cloud.cloudnative-pg.io"*"-o jsonpath="*"metadata.name"* ]]; then + echo "barman-cloud" + exit 0 +fi +if [[ "${args}" == *"-n cnpg-system"*"get svc barman-cloud"*"-o jsonpath="*"metadata.name"* ]]; then + echo "barman-cloud" + exit 0 +fi +if [[ "${args}" == *"-n cnpg-system"*"get svc barman-cloud"*"pluginClientSecret"* ]]; then + echo "barman-cloud-client-tls" + exit 0 +fi +if [[ "${args}" == *"-n cnpg-system"*"get svc barman-cloud"*"pluginServerSecret"* ]]; then + echo "barman-cloud-server-tls" + exit 0 +fi +if [[ "${args}" == *"-n cnpg-system"*"get svc barman-cloud"*"pluginPort"* ]]; then + echo "9090" + exit 0 +fi +if [[ "${args}" == *"-n cnpg-system"*"get endpoints barman-cloud"* ]]; then + echo "10.42.0.11" + exit 0 +fi + # CNPG cluster pod selection for socket check if [[ "${args}" == *"-n test-ns"*"get pods"*"-l cnpg.io/cluster=prole-db,cnpg.io/instanceRole=primary"*"-o jsonpath={.items[0].metadata.name"* ]]; then echo "prole-db-1" @@ -102,6 +128,16 @@ if [[ "${args}" == apply*"-n"*"test-ns"*"-f"*"-"* ]]; then exit 0 fi +# ObjectStore readiness checks +if [[ "${args}" == *"-n test-ns"*"get objectstore"*"prole-db-barman-objectstore"*"-o jsonpath="*"conditions"*"Ready"* ]]; then + echo "True" + exit 0 +fi +if [[ "${args}" == *"-n test-ns"*"get objectstore"*"prole-db-barman-objectstore"*"-o jsonpath={.status.phase"* ]]; then + echo "Ready" + exit 0 +fi + exit 0 K_EOF chmod +x "$BIN_DIR/kubectl" diff --git a/tests/etc/test_init_cnpg_backup_start_waits_for_plugin_socket.sh b/tests/etc/test_init_cnpg_backup_start_waits_for_plugin_socket.sh index e055efa..40e5d80 100644 --- a/tests/etc/test_init_cnpg_backup_start_waits_for_plugin_socket.sh +++ b/tests/etc/test_init_cnpg_backup_start_waits_for_plugin_socket.sh @@ -74,6 +74,32 @@ if [[ "${args}" == "get deployment -A -l app.kubernetes.io/name=barman-cloud -o exit 0 fi +# Barman plugin service registration (used by wait_for_barman_plugin_infra_ready) +if [[ "${args}" == *"-n cnpg-system"*"get svc"*"-l cnpg.io/pluginName=barman-cloud.cloudnative-pg.io"*"-o jsonpath="*"metadata.name"* ]]; then + echo "barman-cloud" + exit 0 +fi +if [[ "${args}" == *"-n cnpg-system"*"get svc barman-cloud"*"-o jsonpath="*"metadata.name"* ]]; then + echo "barman-cloud" + exit 0 +fi +if [[ "${args}" == *"-n cnpg-system"*"get svc barman-cloud"*"pluginClientSecret"* ]]; then + echo "barman-cloud-client-tls" + exit 0 +fi +if [[ "${args}" == *"-n cnpg-system"*"get svc barman-cloud"*"pluginServerSecret"* ]]; then + echo "barman-cloud-server-tls" + exit 0 +fi +if [[ "${args}" == *"-n cnpg-system"*"get svc barman-cloud"*"pluginPort"* ]]; then + echo "9090" + exit 0 +fi +if [[ "${args}" == *"-n cnpg-system"*"get endpoints barman-cloud"* ]]; then + echo "10.42.0.11" + exit 0 +fi + # CNPG cluster pod selection for socket check if [[ "${args}" == *"-n test-ns"*"get pods"*"-l cnpg.io/cluster=prole-db,cnpg.io/instanceRole=primary"*"-o jsonpath={.items[0].metadata.name"* ]]; then echo "prole-db-1" @@ -157,6 +183,16 @@ if [[ "${args}" == "get backup -n test-ns"* ]]; then exit 0 fi +# ObjectStore readiness checks +if [[ "${args}" == *"-n test-ns"*"get objectstore"*"prole-db-barman-objectstore"*"-o jsonpath="*"conditions"*"Ready"* ]]; then + echo "True" + exit 0 +fi +if [[ "${args}" == *"-n test-ns"*"get objectstore"*"prole-db-barman-objectstore"*"-o jsonpath={.status.phase"* ]]; then + echo "Ready" + exit 0 +fi + exit 0 K_EOF chmod +x "$BIN_DIR/kubectl"