mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-06 10:59:59 +00:00
fix(swarm): ask the stack for the gate's service instead of guessing from metadata
The converge gate polls STACK_NAME_PRIMARY_SERVICE_KEY. Four roles never create that name and each was given a static `workload: node-local` to make the gate skip itself:21fe9e984web-svc-cdn ships only cdn_build, never cdn_cdn2c6c8b763web-app-matrix names its services matrix_synapse and friends76508c946svc-runner deploys node-local compose projects per nodecb52a72f2bigbluebutton phantom service, and the DR drill must still run Four hand-written claims for one observable fact. The claim is also static where the truth is not: web-app-discourse renders `services: {}` only while its sidecars are shared, and job 94965456921 of run 31864448027 polled discourse_discourse ninety times for a stack that had none. Declaring the role node-local would have blinded the gate in the variants where its sidecars are local and a stack does exist. has_swarm_service asks the deployed stack for the exact name instead. Every caller runs behind `if rc == 0`, so an absent service is the role's shape and not a broken deploy. Exact-line matching, not docker's name filter, which matches substrings. No coverage is lost: 03_wait_converge cannot pass without that service, and 05/06/07 plus the backup drill only run once it has. The four roles keep the skip they were given; discourse and every future case get it without a declaration. The teardown branch in the drill keeps its meaning - stack rm where the service exists, compose stop per node where it does not. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
18c9738efb
commit
246558a13e
7 files changed
+20
-42
No files matched your search
@@ -7,7 +7,6 @@ runner:
|
||||
swarm:
|
||||
enabled: true
|
||||
lifecycle: beta
|
||||
workload: node-local
|
||||
proxy:
|
||||
service_key: runner-1
|
||||
github_owner: infinito-nexus
|
||||
|
||||
@@ -34,7 +34,6 @@ bigbluebutton:
|
||||
bond: 1
|
||||
enabled: true
|
||||
shared: true
|
||||
workload: node-local
|
||||
repository: https://github.com/bigbluebutton/docker.git
|
||||
ref: v3.0.23
|
||||
recording:
|
||||
|
||||
@@ -113,7 +113,6 @@ matrix:
|
||||
name: matrix
|
||||
# nocheck: default-placement-manager inner docker-in-docker storage; node-local in swarm
|
||||
placement: manager
|
||||
workload: node-local
|
||||
flavor: ansible
|
||||
upstream:
|
||||
repo: https://github.com/spantaleev/matrix-docker-ansible-deploy
|
||||
|
||||
@@ -7,7 +7,6 @@ dashboard:
|
||||
cdn:
|
||||
# nocheck: default-placement-manager the one-shot npm-mirror build must write the served CDN root, a node-local host bind openresty (manager-pinned) reads
|
||||
placement: manager
|
||||
workload: node-local
|
||||
modes:
|
||||
host:
|
||||
enabled: true
|
||||
|
||||
@@ -111,10 +111,10 @@ flowchart TB
|
||||
`utils/tests/swarm/backup_repos.py` derives both the manager's inventory
|
||||
groups and the `remote-2-local` provider list from that closure; apps
|
||||
without those roles prove the chain through the nfs repository.
|
||||
- The workload form only changes step 6: stack workloads get
|
||||
`docker stack rm`, `workload: node-local` roles get their compose
|
||||
project stopped on every node. Every other step operates on volumes,
|
||||
the NFS export and the deployed backup units, independent of the
|
||||
orchestrator.
|
||||
- The workload form only changes step 6: a stack that carries services gets
|
||||
`docker stack rm`, a role whose compose renders none gets its compose
|
||||
project stopped on every node. `has_swarm_service` decides by asking the
|
||||
deployed stack. Every other step operates on volumes, the NFS export and
|
||||
the deployed backup units, independent of the orchestrator.
|
||||
- Runs once per app, in the variant-0 CI job, between the matrix's first
|
||||
deploy and its update pass.
|
||||
@@ -215,7 +215,7 @@ fi
|
||||
echo " marker present on encrypted USB"
|
||||
|
||||
echo "==> [6/9] tear the stack down completely (full disaster) before recovery"
|
||||
if [ "${HAS_SWARM_SERVICE}" = true ]; then
|
||||
if has_swarm_service; then
|
||||
docker exec "${MGR}" bash "${BKP_IN_NODE}/04_stack_rm_wait.sh" "${STACK_NAME}"
|
||||
else
|
||||
for _node in "${MGR}" "${WRK1}" "${WRK2}"; do
|
||||
|
||||
@@ -51,33 +51,6 @@ if [ -f "${ROLE_DIR}/meta/services.yml" ] &&
|
||||
DEFAULT_PLACEMENT_MANAGER=true
|
||||
fi
|
||||
|
||||
HAS_SWARM_SERVICE="$(PYTHONPATH="${_REPO_ROOT}" "${PYTHON}" -c "
|
||||
import os, yaml
|
||||
svc = os.path.join('${ROLE_DIR}', 'meta', 'services.yml')
|
||||
data = {}
|
||||
if os.path.exists(svc):
|
||||
data = yaml.safe_load(open(svc)) or {}
|
||||
if not isinstance(data, dict):
|
||||
data = {}
|
||||
entity = data.get('${ENTITY}')
|
||||
workload = entity.get('workload') if isinstance(entity, dict) else None
|
||||
if isinstance(workload, str):
|
||||
workload = workload.strip().lower()
|
||||
if workload == 'node-local':
|
||||
print('false')
|
||||
raise SystemExit
|
||||
if workload == 'stack':
|
||||
print('true')
|
||||
raise SystemExit
|
||||
try:
|
||||
from utils.roles.meta_lookup import get_role_skip
|
||||
swarm_skipped = 'swarm' in get_role_skip('${APP_ID}')
|
||||
except Exception:
|
||||
swarm_skipped = False
|
||||
has_image = any(isinstance(v, dict) and 'image' in v for v in data.values())
|
||||
has_tpl = any(os.path.exists(os.path.join('${ROLE_DIR}', 'templates', t)) for t in ('compose.yml.j2', 'service.yml.j2'))
|
||||
print('false' if (swarm_skipped or not (has_image or has_tpl)) else 'true')
|
||||
")"
|
||||
|
||||
PROBE_PORT="$(PYTHONPATH="${_REPO_ROOT}" "${PYTHON}" -c "
|
||||
import os, yaml
|
||||
@@ -121,7 +94,7 @@ PRIMARY_NFS_VOLUME="${NFS_VOLUMES%%$'\n'*}"
|
||||
|
||||
NFS_CHECK_MOUNTPOINT="/mnt/nfs-check"
|
||||
|
||||
export APP_ID ENTITY STACK_NAME SERVICE_NAME PRIMARY_SERVICE_KEY CUSTOM_IMAGE_REPO DB_DEP NFS_VOLUMES PRIMARY_NFS_VOLUME DEFAULT_PLACEMENT_MANAGER HAS_SWARM_SERVICE PROBE_PORT NFS_CHECK_MOUNTPOINT
|
||||
export APP_ID ENTITY STACK_NAME SERVICE_NAME PRIMARY_SERVICE_KEY CUSTOM_IMAGE_REPO DB_DEP NFS_VOLUMES PRIMARY_NFS_VOLUME DEFAULT_PLACEMENT_MANAGER PROBE_PORT NFS_CHECK_MOUNTPOINT
|
||||
|
||||
# Exits the calling chaos step (09/10/11) with success when the role is
|
||||
# manager-pinned (no worker task exists to drain).
|
||||
@@ -132,11 +105,21 @@ skip_chaos_if_manager_pinned() {
|
||||
fi
|
||||
}
|
||||
|
||||
# Exits the calling gate (07/09/10/11) with success when the role deploys no
|
||||
has_swarm_service() {
|
||||
local _names=""
|
||||
[ -n "${MGR:-}" ] || return 1
|
||||
if ! _names="$(docker exec "${MGR}" docker stack services \
|
||||
--format '{{.Name}}' "${STACK_NAME}" 2>/dev/null)"; then
|
||||
_names=""
|
||||
fi
|
||||
printf '%s\n' "${_names}" | grep -qxF "${SERVICE_NAME}"
|
||||
}
|
||||
|
||||
# Exits the calling gate (03/05/06/07) with success when the role deploys no
|
||||
# swarm service to converge or drain.
|
||||
skip_if_no_swarm_service() {
|
||||
if [ "${HAS_SWARM_SERVICE}" != true ]; then
|
||||
echo "SKIP: ${ENTITY} (${APP_ID}) deploys no swarm service — converge/chaos gate does not apply"
|
||||
if ! has_swarm_service; then
|
||||
echo "SKIP: ${ENTITY} (${APP_ID}) deployed no swarm service — converge/chaos gate does not apply"
|
||||
exit 0
|
||||
fi
|
||||
}
|
||||
@@ -158,6 +141,5 @@ if [ "${SWARM_NFS_PILOT_VERBOSE:-0}" = "1" ]; then
|
||||
echo " DB_DEP=${DB_DEP}"
|
||||
echo " PRIMARY_NFS_VOLUME=${PRIMARY_NFS_VOLUME}"
|
||||
echo " DEFAULT_PLACEMENT_MANAGER=${DEFAULT_PLACEMENT_MANAGER}"
|
||||
echo " HAS_SWARM_SERVICE=${HAS_SWARM_SERVICE}"
|
||||
echo " PROBE_PORT=${PROBE_PORT}"
|
||||
fi
|
||||
Reference in new issue
Block a user