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>
72 lines
2.1 KiB
Python
72 lines
2.1 KiB
Python
"""
|
|
Resolve deploy-time tokens in deployed files.
|
|
|
|
Values come from config/environments.yml and config/services_registry.yml --
|
|
the single source of truth. Nothing here knows what '-DEV' is.
|
|
|
|
render_subs.py --env dev --service tune /path/to/ioc /path/to/systemd
|
|
render_subs.py --env prod /sls/bd/hla/prod/qt
|
|
|
|
Without --service only the environment tokens are available, so a file that
|
|
needs a per-service token (ioc_port) fails loudly rather than shipping the
|
|
placeholder. A path that does not exist is reported and skipped, which is how
|
|
services without a systemd unit are handled.
|
|
"""
|
|
|
|
import argparse
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
from agebd.subs import SubstitutionError, Substitutions
|
|
|
|
|
|
def render(subs, paths):
|
|
"""
|
|
Render every path in place. Returns the files that changed.
|
|
"""
|
|
changed = []
|
|
for path in paths:
|
|
if not path.exists():
|
|
print(f"skipped (does not exist): {path}")
|
|
continue
|
|
if path.is_dir():
|
|
changed.extend(subs.render_tree(path))
|
|
elif subs.render_file(path):
|
|
changed.append(path)
|
|
return changed
|
|
|
|
|
|
def main(argv=None):
|
|
parser = argparse.ArgumentParser(
|
|
description=__doc__,
|
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
)
|
|
parser.add_argument("--env", required=True, help="Deployment environment, e.g. dev")
|
|
parser.add_argument(
|
|
"--service",
|
|
default=None,
|
|
help="Service name. Required for files holding per-service tokens.",
|
|
)
|
|
parser.add_argument("paths", nargs="+", type=Path, help="Files or directories to render")
|
|
args = parser.parse_args(argv)
|
|
|
|
if args.service:
|
|
subs = Substitutions.for_service(args.env, args.service)
|
|
else:
|
|
subs = Substitutions.for_env(args.env)
|
|
|
|
changed = render(subs, args.paths)
|
|
|
|
for path in changed:
|
|
print(f"rendered: {path}")
|
|
print(f"{len(changed)} file(s) rendered for env '{args.env}'")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
try:
|
|
sys.exit(main())
|
|
except SubstitutionError as e:
|
|
print(f"error: {e}", file=sys.stderr)
|
|
sys.exit(1)
|