Refactor/central substitutions #70
Open
labrec_b
wants to merge 4 commits from
refactor/central-substitutions into main
pull from: refactor/central-substitutions
merge into: :main
:main
:feature/gui-add-topbar
:feature/qt-workflow-action
:feature/add-service-playground
:gitea-pages
:feature/prod-cicd-runner
:docs/user-docs-improvements
:feature/deploy-service-dispatch
:feature/add-process-and-file-version-for-services
:feature/ui-subs-in-deploy
:feature/ioc-on-cicd-runner
:refactor/central-substitutions
:refactor/extract-base-runner
:chore/sub-env-vars-cicd
:chore/remove-opt-gfa-python
:feature/setup-prod-hla-runner
:feature/gui-startup-script
:feature/add-services-tests-cicd
:feature/pixi
:feature/cicd-tests-package-agebd
:feature/add-params-ioc
:chore/migrate-ansible-logic-to-workflow-steps
:feature/add-gitea-pages-docs
:feature/cli-add-service-gui-creation-options
:feature/add-service-test-20260727
:chore/remove-pv-external
:feature/add-new-service-all-migrate-python
:feature/add-new-service-all-migrate
:chore/migrate-all-services
:feature/add-new-service-all
:feature/add-service-taubpm
:feature/add-service-dbpm3curr
:feature/add-service-nturns
:feature/ui
4
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
4a73e52a35 |
refactor: one definition per naming rule, drop ansible (step 5)
Consolidates the last duplicated derivations, and removes the ansible
tree along with the CLI surface that existed only to drive it.
Naming rules:
* agebd/names.py holds ServiceName -- the single definition of how a
service name is spelled in each context: dir_name, module_name,
ioc_name, systemd_unit_name and the case forms. The environment
suffix is deliberately not part of it; that stays a deploy-time
token applied to these base names.
* cli's Service model delegates every name_* property to it, so the
CLI and the CI scripts derive names the same way.
* scripts/ci/service_names.py emits the derived forms as shell
assignments, and deploy-and-restart-service.sh evals them instead of
carrying its own tr calls and its own copy of the systemd naming
convention. Values are shell-quoted, and an invalid name exits
non-zero emitting nothing, so an eval cannot leave empty variables
behind.
Registry lookups:
* agebd.subs.find_service_entry is now the only place that answers
"which registry entry is this service", used by read_ioc_port,
get_ioc_port.py and cli's ServiceRegistry. get_ioc_port.py no longer
parses the registry itself.
* That also settles a semantic split: ServiceRegistry matched names
case-sensitively while read_ioc_port did not. Both now match
case-insensitively via ServiceName, so 'tune', 'Tune' and 'TUNE'
resolve to the same service everywhere.
Ansible removal:
* ansible/ is deleted, along with cli/src/ioc.py, cli/src/core/
ansible.py, the IOC_ENV enum, the ansible and ansible-runner
dependencies, and docs/developer/ansible.md.
* This removes the 'agebd ioc install|start|restart' commands. They
were pure playbook wrappers, so they could not outlive the
playbooks; IOC install, start and restart now have no automation
path in this repo.
bin/start_service.sh keeps deriving its two name forms in bash, with a
comment saying why: it runs on the deploy host before the service venv
exists, so it cannot import agebd. It is the one deliberate exception.
Verified: get_ioc_port.py, cli's ServiceRegistry and agebd's renderer all
return 50007 for 'tune', 'Tune' and 'TUNE'; the shell-emitted names match
the committed on-disk layout for real services including the dashed
OpticsFF-X02S; the CLI runs with only the 'service' command left.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
||
|
|
ee5f331f4c |
feat: render qt/ at deploy time and enforce the suffix (step 4)
qt/ was declared a render path in step 1 but nothing rendered it: the Qt
deploy step was a plain rsync, so the UI files shipped with literal
placeholders in every PV name.
* deploy.yml renders the deployed qt/ directory with render_subs.py
after the rsync. No --service is needed; qt holds no per-service
token, and a file that acquired one would fail the step rather than
ship the placeholder.
* bin/sls_hla_launch_gui.sh no longer passes an AGEBD_ENV_SUFFIX macro.
No .ui file has referenced $(AGEBD_ENV_SUFFIX) since
|
||
|
|
5e4246508b |
refactor: route deploy consumers through the central config (step 3)
Both deploy paths now take their token values from
config/environments.yml instead of defining their own copies.
CI / shell path:
* scripts/ci/render_subs.py renders deployed files via agebd.subs.
* deploy-and-restart-service.sh drops its dev/prod if-else and its four
sed calls for one render_subs.py invocation, and aborts the deploy if
rendering fails rather than restarting a service whose files still
contain placeholders.
Ansible path:
* ansible/tasks/utils/load-substitutions.yml reads the central config on
the controller and exposes the token table for this environment.
* ioc-install and service-deploy-and-restart now loop over that table
instead of listing tokens inline, so a new token needs no ansible
edit.
* env_suffix_upper/lower are gone from both inventories. The inventory
says which environment it is; the central config says what that
environment means. The facts are renamed to agebd_env_suffix_upper /
_lower to match the token names, removing a rename trap.
Ansible keeps using ansible.builtin.replace rather than calling
agebd.subs, because ioc-install runs on hosts with no uv or Python
environment for this repo. Only the mechanism differs now; the values and
the token list are shared.
Verified: both playbook paths run locally against dev and prod and
produce the expected output, an undeclared environment fails loudly in
both paths, and a misspelled token exits non-zero instead of shipping the
placeholder.
Not addressed here, still step 5: ansible/tasks/utils/get-ioc-port.yml
matches CamelCase registry names against a lowercase input and returns
nothing, so the ansible ioc-install path cannot resolve a port. This is
pre-existing and unchanged by this commit.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
||
|
|
cfd3ecad6c |
refactor: centralize deploy-time substitutions (steps 1-2)
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>
|