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 a06fded, and the
    suffix is now baked in at deploy time. This removes the last
    hardcoded '-DEV' outside config/environments.yml.

check_ui_files.py is rewritten for the chosen convention. It asserted the
old caQtDM macro, and its regex had stopped matching anything at all once
placeholders appeared in device names -- against the pre-fix Service
Manager it inspected 0 names, where the new check finds 16 violations.
The new rule: every AGEBD- device name carries the suffix token, except
systemd unit names, which are the same in both environments. The token
name is read from the central config so a rename cannot leave this check
enforcing a stale one.

Fixing what that check surfaced, all in A_BD_ServiceManager.ui:

  * 16 'IOC=AGEBD-CPCL-<NAME>' caInclude macro values had no suffix. The
    included UI uses them as PV prefixes ($(IOC):STATUS, $(IOC):RESTART),
    so the dev Service Manager was reading status from, and sending
    restarts to, production IOCs.
  * Two ssh commands hardcoded sls-vserv-bd-hla01, so the dev GUI's
    restart button targeted the production HLA host.
  * cli generates those macro values, so the generator emits the token
    too and new services are no longer born with the bug.

These were latent while qt/ shipped unrendered placeholders; turning
rendering on would have made them live.

Verified: dev renders -DEV device names and the -dev host, prod renders
byte-identical to the currently deployed prod files, no placeholder
survives in either, and all 24 UI files stay well-formed XML.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Benjamin Labrecque
2026-08-20 12:12:11 +02:00
co-authored by Claude Opus 5
parent 5e4246508b
commit ee5f331f4c
8 changed files with 174 additions and 37 deletions
+4 -1
View File
@@ -133,8 +133,11 @@ class _ServiceManagerUIMacroElement(BaseModel):
ui_filename: str
def to_string(self) -> str:
# The IOC macro is used as a PV prefix inside the included UI
# ($(IOC):STATUS, $(IOC):RESTART), so it carries the environment
# suffix token and is resolved when qt/ is rendered at deploy time.
return (
f"IOC=AGEBD-CPCL-{self.service_name_upper},"
f"IOC=AGEBD-CPCL-{self.service_name_upper}@@agebd_env_suffix_upper@@,"
f"service={self.service_name_upper},"
f"name={self.service_name_camel},"
f"panel={self.panel},"
@@ -138,7 +138,7 @@ caLabel[statusTip="Operation"]{
</rect>
</property>
<property name="macro">
<string>IOC=AGEBD-CPCL-DBPM3CURR,service=DBPM3CURR,name=DBPM3Curr,panel=1,svc_exist=1,panelcmd=A_BD_DBPM3Curr.ui;IOC=AGEBD-CPCL-TAUBPM,service=TAUBPM,name=TauBPM,panel=1,svc_exist=1,panelcmd=A_BD_TauBPM.ui;IOC=AGEBD-CPCL-TAUPCT,service=TAUPCT,name=TauPCT,panel=1,svc_exist=1,panelcmd=A_BD_TauPCT.ui;IOC=AGEBD-CPCL-TIMING,service=TIMING,name=Timing,panel=1,svc_exist=1,panelcmd=A_BD_Timing.ui;IOC=AGEBD-CPCL-SCRUBBING,service=SCRUBBING,name=Scrubbing,panel=1,svc_exist=1,panelcmd=A_BD_Scrubbing.ui;IOC=AGEBD-CPCL-INJECTIONGUARD,service=INJECTIONGUARD,name=InjectionGuard,panel=1,svc_exist=1,panelcmd=A_BD_InjectionGuard.ui;IOC=AGEBD-CPCL-POSTMORTEMLOG,service=POSTMORTEMLOG,name=PostMortemLog,panel=1,svc_exist=1,panelcmd=A_BD_PostMortemLog.ui;IOC=AGEBD-CPCL-TUNEBUMP,service=TUNEBUMP,name=TuneBump,panel=1,svc_exist=1,panelcmd=A_BD_TuneBump.ui;IOC=AGEBD-CPCL-PLOTS,service=PLOTS,name=Plots,panel=0,svc_exist=1,panelcmd=A_BD_Plots.ui;IOC=AGEBD-CPCL-ORBITBUMP,service=ORBITBUMP,name=OrbitBump,panel=1,svc_exist=0,panelcmd=A_BD_OrbitBump.ui;IOC=AGEBD-CPCL-TUNEFBX,service=TUNEFBX,name=Hor. Tune Feedback,panel=1,svc_exist=1,panelcmd=A_BD_TuneBump.ui;IOC=AGEBD-CPCL-TUNEFBY,service=TUNEFBY,name=Ver. Tune Feedback,panel=1,svc_exist=1,panelcmd=A_BD_TuneBump.ui;IOC=AGEBD-CPCL-TESTSERVICE99-X00,service=TESTSERVICE99-X00,name=TestService99-X00,panel=1,svc_exist=1,panelcmd=A_BD_TestService99-X00.ui</string>
<string>IOC=AGEBD-CPCL-DBPM3CURR@@agebd_env_suffix_upper@@,service=DBPM3CURR,name=DBPM3Curr,panel=1,svc_exist=1,panelcmd=A_BD_DBPM3Curr.ui;IOC=AGEBD-CPCL-TAUBPM@@agebd_env_suffix_upper@@,service=TAUBPM,name=TauBPM,panel=1,svc_exist=1,panelcmd=A_BD_TauBPM.ui;IOC=AGEBD-CPCL-TAUPCT@@agebd_env_suffix_upper@@,service=TAUPCT,name=TauPCT,panel=1,svc_exist=1,panelcmd=A_BD_TauPCT.ui;IOC=AGEBD-CPCL-TIMING@@agebd_env_suffix_upper@@,service=TIMING,name=Timing,panel=1,svc_exist=1,panelcmd=A_BD_Timing.ui;IOC=AGEBD-CPCL-SCRUBBING@@agebd_env_suffix_upper@@,service=SCRUBBING,name=Scrubbing,panel=1,svc_exist=1,panelcmd=A_BD_Scrubbing.ui;IOC=AGEBD-CPCL-INJECTIONGUARD@@agebd_env_suffix_upper@@,service=INJECTIONGUARD,name=InjectionGuard,panel=1,svc_exist=1,panelcmd=A_BD_InjectionGuard.ui;IOC=AGEBD-CPCL-POSTMORTEMLOG@@agebd_env_suffix_upper@@,service=POSTMORTEMLOG,name=PostMortemLog,panel=1,svc_exist=1,panelcmd=A_BD_PostMortemLog.ui;IOC=AGEBD-CPCL-TUNEBUMP@@agebd_env_suffix_upper@@,service=TUNEBUMP,name=TuneBump,panel=1,svc_exist=1,panelcmd=A_BD_TuneBump.ui;IOC=AGEBD-CPCL-PLOTS@@agebd_env_suffix_upper@@,service=PLOTS,name=Plots,panel=0,svc_exist=1,panelcmd=A_BD_Plots.ui;IOC=AGEBD-CPCL-ORBITBUMP@@agebd_env_suffix_upper@@,service=ORBITBUMP,name=OrbitBump,panel=1,svc_exist=0,panelcmd=A_BD_OrbitBump.ui;IOC=AGEBD-CPCL-TUNEFBX@@agebd_env_suffix_upper@@,service=TUNEFBX,name=Hor. Tune Feedback,panel=1,svc_exist=1,panelcmd=A_BD_TuneBump.ui;IOC=AGEBD-CPCL-TUNEFBY@@agebd_env_suffix_upper@@,service=TUNEFBY,name=Ver. Tune Feedback,panel=1,svc_exist=1,panelcmd=A_BD_TuneBump.ui;IOC=AGEBD-CPCL-TESTSERVICE99-X00@@agebd_env_suffix_upper@@,service=TESTSERVICE99-X00,name=TestService99-X00,panel=1,svc_exist=1,panelcmd=A_BD_TestService99-X00.ui</string>
</property>
<property name="filename" stdset="0">
<string notr="true">A_BD_ServiceManager_inc.ui</string>
@@ -246,7 +246,7 @@ caLabel[statusTip="Operation"]{
</rect>
</property>
<property name="macro">
<string>IOC=AGEBD-CPCL-NTURNS,service=NTURNS,name=NTurns,panel=1,svc_exist=1,panelcmd=A_BD_NTurns.ui;IOC=AGEBD-CPCL-TOPUPTOOL,service=TOPUPTOOL,name=TopUpTool,panel=1,svc_exist=1,panelcmd=A_BD_TopUpTool.ui;IOC=AGEBD-CPCL-TUNE,service=TUNE,name=Tune,panel=1,svc_exist=1,panelcmd=A_BD_Tune.ui;IOC=AGEOP-CPCL-SHIFTTOOL,service=SHIFTTOOL,name=Shifttool,panel=1,svc_exist=1,panelcmd=A_OP_SchichtProtokollTool.ui,macro=FACILITY=SLS</string>
<string>IOC=AGEBD-CPCL-NTURNS@@agebd_env_suffix_upper@@,service=NTURNS,name=NTurns,panel=1,svc_exist=1,panelcmd=A_BD_NTurns.ui;IOC=AGEBD-CPCL-TOPUPTOOL@@agebd_env_suffix_upper@@,service=TOPUPTOOL,name=TopUpTool,panel=1,svc_exist=1,panelcmd=A_BD_TopUpTool.ui;IOC=AGEBD-CPCL-TUNE@@agebd_env_suffix_upper@@,service=TUNE,name=Tune,panel=1,svc_exist=1,panelcmd=A_BD_Tune.ui;IOC=AGEOP-CPCL-SHIFTTOOL,service=SHIFTTOOL,name=Shifttool,panel=1,svc_exist=1,panelcmd=A_OP_SchichtProtokollTool.ui,macro=FACILITY=SLS</string>
</property>
<property name="filename" stdset="0">
<string notr="true">A_BD_ServiceManager_inc.ui</string>
@@ -792,7 +792,7 @@ caLabel[statusTip="Operation"]{
<string>/ioc/modules/qt/iocStats.ui</string>
</property>
<property name="args">
<string>IOC=AGEBD-CPCL-MASTER;</string>
<string>IOC=AGEBD-CPCL-MASTER@@agebd_env_suffix_upper@@;</string>
</property>
</widget>
<widget class="caLabel" name="calabel_42">
@@ -986,7 +986,7 @@ caLabel[statusTip="Operation"]{
<bool>false</bool>
</property>
<property name="scriptCommand">
<string notr="true">ssh svcusr-sls2hla@sls-vserv-bd-hla01 systemctl --user restart AGEBD-SERVICE-MASTER.service</string>
<string notr="true">ssh svcusr-sls2hla@sls-vserv-bd-hla01@@agebd_env_suffix_lower@@ systemctl --user restart AGEBD-SERVICE-MASTER.service</string>
</property>
</widget>
<widget class="caScriptButton" name="cascriptbutton_2">
@@ -1015,7 +1015,7 @@ caLabel[statusTip="Operation"]{
<bool>false</bool>
</property>
<property name="scriptCommand">
<string notr="true">terminator -e "ssh svcusr-sls2hla@sls-vserv-bd-hla01"</string>
<string notr="true">terminator -e "ssh svcusr-sls2hla@sls-vserv-bd-hla01@@agebd_env_suffix_lower@@"</string>
</property>
</widget>
</widget>
@@ -138,7 +138,7 @@ caLabel[statusTip="Operation"]{
</rect>
</property>
<property name="macro">
<string>IOC=AGEBD-CPCL-DBPM3CURR,service=DBPM3CURR,name=DBPM3Curr,panel=1,svc_exist=1,panelcmd=A_BD_DBPM3Curr.ui;IOC=AGEBD-CPCL-TAUBPM,service=TAUBPM,name=TauBPM,panel=1,svc_exist=1,panelcmd=A_BD_TauBPM.ui;IOC=AGEBD-CPCL-TAUPCT,service=TAUPCT,name=TauPCT,panel=1,svc_exist=1,panelcmd=A_BD_TauPCT.ui;IOC=AGEBD-CPCL-TIMING,service=TIMING,name=Timing,panel=1,svc_exist=1,panelcmd=A_BD_Timing.ui;IOC=AGEBD-CPCL-SCRUBBING,service=SCRUBBING,name=Scrubbing,panel=1,svc_exist=1,panelcmd=A_BD_Scrubbing.ui;IOC=AGEBD-CPCL-INJECTIONGUARD,service=INJECTIONGUARD,name=InjectionGuard,panel=1,svc_exist=1,panelcmd=A_BD_InjectionGuard.ui;IOC=AGEBD-CPCL-POSTMORTEMLOG,service=POSTMORTEMLOG,name=PostMortemLog,panel=1,svc_exist=1,panelcmd=A_BD_PostMortemLog.ui;IOC=AGEBD-CPCL-TUNEBUMP,service=TUNEBUMP,name=TuneBump,panel=1,svc_exist=1,panelcmd=A_BD_TuneBump.ui;IOC=AGEBD-CPCL-PLOTS,service=PLOTS,name=Plots,panel=0,svc_exist=1,panelcmd=A_BD_Plots.ui;IOC=AGEBD-CPCL-ORBITBUMP,service=ORBITBUMP,name=OrbitBump,panel=1,svc_exist=0,panelcmd=A_BD_OrbitBump.ui;IOC=AGEBD-CPCL-TUNEFBX,service=TUNEFBX,name=Hor. Tune Feedback,panel=1,svc_exist=1,panelcmd=A_BD_TuneBump.ui;IOC=AGEBD-CPCL-TUNEFBY,service=TUNEFBY,name=Ver. Tune Feedback,panel=1,svc_exist=1,panelcmd=A_BD_TuneBump.ui</string>
<string>IOC=AGEBD-CPCL-DBPM3CURR@@agebd_env_suffix_upper@@,service=DBPM3CURR,name=DBPM3Curr,panel=1,svc_exist=1,panelcmd=A_BD_DBPM3Curr.ui;IOC=AGEBD-CPCL-TAUBPM@@agebd_env_suffix_upper@@,service=TAUBPM,name=TauBPM,panel=1,svc_exist=1,panelcmd=A_BD_TauBPM.ui;IOC=AGEBD-CPCL-TAUPCT@@agebd_env_suffix_upper@@,service=TAUPCT,name=TauPCT,panel=1,svc_exist=1,panelcmd=A_BD_TauPCT.ui;IOC=AGEBD-CPCL-TIMING@@agebd_env_suffix_upper@@,service=TIMING,name=Timing,panel=1,svc_exist=1,panelcmd=A_BD_Timing.ui;IOC=AGEBD-CPCL-SCRUBBING@@agebd_env_suffix_upper@@,service=SCRUBBING,name=Scrubbing,panel=1,svc_exist=1,panelcmd=A_BD_Scrubbing.ui;IOC=AGEBD-CPCL-INJECTIONGUARD@@agebd_env_suffix_upper@@,service=INJECTIONGUARD,name=InjectionGuard,panel=1,svc_exist=1,panelcmd=A_BD_InjectionGuard.ui;IOC=AGEBD-CPCL-POSTMORTEMLOG@@agebd_env_suffix_upper@@,service=POSTMORTEMLOG,name=PostMortemLog,panel=1,svc_exist=1,panelcmd=A_BD_PostMortemLog.ui;IOC=AGEBD-CPCL-TUNEBUMP@@agebd_env_suffix_upper@@,service=TUNEBUMP,name=TuneBump,panel=1,svc_exist=1,panelcmd=A_BD_TuneBump.ui;IOC=AGEBD-CPCL-PLOTS@@agebd_env_suffix_upper@@,service=PLOTS,name=Plots,panel=0,svc_exist=1,panelcmd=A_BD_Plots.ui;IOC=AGEBD-CPCL-ORBITBUMP@@agebd_env_suffix_upper@@,service=ORBITBUMP,name=OrbitBump,panel=1,svc_exist=0,panelcmd=A_BD_OrbitBump.ui;IOC=AGEBD-CPCL-TUNEFBX@@agebd_env_suffix_upper@@,service=TUNEFBX,name=Hor. Tune Feedback,panel=1,svc_exist=1,panelcmd=A_BD_TuneBump.ui;IOC=AGEBD-CPCL-TUNEFBY@@agebd_env_suffix_upper@@,service=TUNEFBY,name=Ver. Tune Feedback,panel=1,svc_exist=1,panelcmd=A_BD_TuneBump.ui</string>
</property>
<property name="filename" stdset="0">
<string notr="true">A_BD_ServiceManager_inc.ui</string>
@@ -246,7 +246,7 @@ caLabel[statusTip="Operation"]{
</rect>
</property>
<property name="macro">
<string>IOC=AGEBD-CPCL-NTURNS,service=NTURNS,name=NTurns,panel=1,svc_exist=1,panelcmd=A_BD_NTurns.ui;IOC=AGEBD-CPCL-TOPUPTOOL,service=TOPUPTOOL,name=TopUpTool,panel=1,svc_exist=1,panelcmd=A_BD_TopUpTool.ui;IOC=AGEBD-CPCL-TUNE,service=TUNE,name=Tune,panel=1,svc_exist=1,panelcmd=A_BD_Tune.ui;IOC=AGEOP-CPCL-SHIFTTOOL,service=SHIFTTOOL,name=Shifttool,panel=1,svc_exist=1,panelcmd=A_OP_SchichtProtokollTool.ui,macro=FACILITY=SLS</string>
<string>IOC=AGEBD-CPCL-NTURNS@@agebd_env_suffix_upper@@,service=NTURNS,name=NTurns,panel=1,svc_exist=1,panelcmd=A_BD_NTurns.ui;IOC=AGEBD-CPCL-TOPUPTOOL@@agebd_env_suffix_upper@@,service=TOPUPTOOL,name=TopUpTool,panel=1,svc_exist=1,panelcmd=A_BD_TopUpTool.ui;IOC=AGEBD-CPCL-TUNE@@agebd_env_suffix_upper@@,service=TUNE,name=Tune,panel=1,svc_exist=1,panelcmd=A_BD_Tune.ui;IOC=AGEOP-CPCL-SHIFTTOOL,service=SHIFTTOOL,name=Shifttool,panel=1,svc_exist=1,panelcmd=A_OP_SchichtProtokollTool.ui,macro=FACILITY=SLS</string>
</property>
<property name="filename" stdset="0">
<string notr="true">A_BD_ServiceManager_inc.ui</string>
@@ -792,7 +792,7 @@ caLabel[statusTip="Operation"]{
<string>/ioc/modules/qt/iocStats.ui</string>
</property>
<property name="args">
<string>IOC=AGEBD-CPCL-MASTER;</string>
<string>IOC=AGEBD-CPCL-MASTER@@agebd_env_suffix_upper@@;</string>
</property>
</widget>
<widget class="caLabel" name="calabel_42">
@@ -986,7 +986,7 @@ caLabel[statusTip="Operation"]{
<bool>false</bool>
</property>
<property name="scriptCommand">
<string notr="true">ssh svcusr-sls2hla@sls-vserv-bd-hla01 systemctl --user restart AGEBD-SERVICE-MASTER.service</string>
<string notr="true">ssh svcusr-sls2hla@sls-vserv-bd-hla01@@agebd_env_suffix_lower@@ systemctl --user restart AGEBD-SERVICE-MASTER.service</string>
</property>
</widget>
<widget class="caScriptButton" name="cascriptbutton_2">
@@ -1015,7 +1015,7 @@ caLabel[statusTip="Operation"]{
<bool>false</bool>
</property>
<property name="scriptCommand">
<string notr="true">terminator -e "ssh svcusr-sls2hla@sls-vserv-bd-hla01"</string>
<string notr="true">terminator -e "ssh svcusr-sls2hla@sls-vserv-bd-hla01@@agebd_env_suffix_lower@@"</string>
</property>
</widget>
</widget>