Deploy-time placeholders were spread across four independent
implementations: sed in the Gitea deploy script, ansible.builtin.replace
in two playbooks, a hardcoded suffix in bin/sls_hla_launch_gui.sh, and
another in agebd/pv.py. Each defined its own values, so nothing kept them
in sync and a missed substitution failed silently.
Step 1 -- one source of truth:
* config/environments.yml declares every deploy-time token, its value
per environment, and where tokens are allowed to live. An environment
that is missing a token, or defines an undeclared one, is a load-time
error.
* agebd.subs loads it and renders. Rendering is a strict regex over
declared token names rather than a template engine: the rendered
files are EPICS db/substitution files and Qt XML, and an unknown
token must raise rather than survive into the output.
* scripts/ci/check_subs.py enforces the contract in CI: tokens in a
rendered path are declared, declared tokens only appear where they
are rendered or generated, and no pre-migration delimiters survive.
Step 2 -- separate the two substitution stages by delimiter:
* Creation-time (copier, once per new service) keeps {{ token }}.
Deploy-time (every deploy, per environment) becomes @@token@@.
* This drops the {{ '{{ token }}' }} escaping from templates/, which
existed only because one Jinja pass had to emit syntax for a second.
* Angle brackets were tried first and rejected: << >> is not
well-formed XML, and cli parses qt/*.ui with ElementTree.
* The existing sed and ansible consumers are repointed at the new
delimiters so this stays behaviour-preserving. Routing them through
agebd.subs is step 3.
Also fixes, as a side effect of having one implementation:
* The sed pattern '{{ *agebd_env_suffix_upper* }}' quantified 'r'
rather than the space, so it only matched one exact spacing.
* agebd.subs.read_ioc_port compares service names case-insensitively;
ansible/tasks/utils/get-ioc-port.yml still compares CamelCase
registry names against a lowercase input and never matches.
qt/*.ui is declared as a render path but nothing renders it yet -- the
Qt deploy step is still a plain rsync. Wiring that up is step 4.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
80 lines
2.8 KiB
YAML
80 lines
2.8 KiB
YAML
# Single source of truth for every deploy-time substitution in this repo.
|
|
#
|
|
# There are two substitution stages, and they use different delimiters on
|
|
# purpose:
|
|
#
|
|
# {{ token }} creation-time. Resolved once by copier when a new service is
|
|
# created (cli/src/core/service_creator.py). Never survives
|
|
# into a committed file.
|
|
#
|
|
# @@token@@ deploy-time. Resolved on every deploy, per environment, by
|
|
# agebd.subs. Lives in committed files.
|
|
#
|
|
# This file declares the deploy-time stage only. scripts/ci/check_subs.py
|
|
# enforces that every @@token@@ in the repo is declared here, and that it
|
|
# only appears in a path that actually gets rendered.
|
|
#
|
|
# 'local' is deliberately absent: it is a runtime mode for tests without EPICS
|
|
# access (see agebd.enums.AGEBD_ENV), not a deploy target.
|
|
|
|
environments:
|
|
prod:
|
|
agebd_env: prod
|
|
agebd_env_suffix_upper: ""
|
|
agebd_env_suffix_lower: ""
|
|
dev:
|
|
agebd_env: dev
|
|
agebd_env_suffix_upper: "-DEV"
|
|
agebd_env_suffix_lower: "-dev"
|
|
|
|
# Every deploy-time token. Each environment above must define exactly the
|
|
# tokens with source 'environment' -- adding one here without adding it to
|
|
# every environment is a load-time error.
|
|
tokens:
|
|
agebd_env:
|
|
source: environment
|
|
description: >-
|
|
Deployment environment name. Used in deploy paths and systemd units,
|
|
e.g. /sls/bd/hla/dev/bin/start_service.sh.
|
|
agebd_env_suffix_upper:
|
|
source: environment
|
|
description: >-
|
|
Uppercase suffix appended to EPICS device names, e.g. AGEBD-TUNE-DEV.
|
|
Used in IOC substitution files and Qt UI files.
|
|
agebd_env_suffix_lower:
|
|
source: environment
|
|
description: >-
|
|
Lowercase suffix appended to host names, e.g. sls-vserv-bd-01-dev.
|
|
Used in IOC parameter files.
|
|
ioc_port:
|
|
source: registry
|
|
description: >-
|
|
IOC port for the service being deployed, read from
|
|
config/services_registry.yml.
|
|
|
|
# Where deploy-time tokens are allowed to live, as repo-root-relative globs.
|
|
locations:
|
|
# Rendered at deploy time by agebd.subs. A token here is resolved.
|
|
render:
|
|
- services/*/current/ioc
|
|
- services/*/current/systemd
|
|
- qt
|
|
# Carry deploy-time tokens verbatim, because the copy they produce lands in
|
|
# a render path. A token here is NOT resolved in place.
|
|
passthrough:
|
|
- templates
|
|
- cli/tests/fixtures
|
|
# The substitution machinery itself: code that renders, generates or
|
|
# documents tokens. Naming a token here is expected; nothing is resolved.
|
|
# These paths use {{ }} as their own template language (Ansible, copier), so
|
|
# the leftover-delimiter check does not apply to them.
|
|
references:
|
|
- ansible/tasks/*
|
|
- .gitea/scripts
|
|
- cli/src/models
|
|
- packages/agebd/src/agebd
|
|
- packages/agebd/tests
|
|
- scripts/ci
|
|
- scripts/tests
|
|
- config
|