fix(heating-can): stop the native services before removing their units #477
@@ -34,17 +34,42 @@
|
||||
# stopped and masked rather than merely disabled -- masked so a stray
|
||||
# `systemctl start` or a leftover dependency cannot bring them back alongside
|
||||
# the containers.
|
||||
- name: Stop and mask the native CAN services
|
||||
ansible.builtin.systemd:
|
||||
name: "{{ item }}"
|
||||
state: stopped
|
||||
enabled: false
|
||||
masked: true
|
||||
- name: Find which native CAN units still exist
|
||||
ansible.builtin.stat:
|
||||
path: "/etc/systemd/system/{{ item }}.service"
|
||||
loop:
|
||||
- open3e
|
||||
- e3oncan
|
||||
failed_when: false
|
||||
register: heating_can_native_units
|
||||
|
||||
# Stop and disable BEFORE anything else, and do NOT swallow the result.
|
||||
#
|
||||
# The first version did stop + disable + mask in one call with
|
||||
# failed_when: false, then deleted the unit files. Masking a unit whose file
|
||||
# still exists conflicts, so the call failed, failed_when hid it, nothing was
|
||||
# stopped -- and the next task deleted the unit files out from under two
|
||||
# running processes. systemctl is-enabled then reported "not-found" and looked
|
||||
# clean while is-active still said "active".
|
||||
#
|
||||
# The result on 2026-08-10 was two open3e instances issuing UDS requests on the
|
||||
# same CAN bus for nine minutes, fighting over the open3e-edge client ID and
|
||||
# kicking each other off the broker.
|
||||
#
|
||||
# Only units that actually exist are touched, so a fresh host does not need an
|
||||
# error swallowed to get through this.
|
||||
- name: Stop and disable the native CAN services
|
||||
ansible.builtin.systemd:
|
||||
name: "{{ item.item }}"
|
||||
state: stopped
|
||||
enabled: false
|
||||
loop: "{{ heating_can_native_units.results }}"
|
||||
loop_control:
|
||||
label: "{{ item.item }}"
|
||||
when: item.stat.exists
|
||||
|
||||
# Masking is deliberately NOT used. It writes a symlink at the same path the
|
||||
# next task removes, so the two cancel out -- which is half of how the original
|
||||
# failed. With the unit files gone there is nothing left to start.
|
||||
- name: Remove the native unit files
|
||||
ansible.builtin.file:
|
||||
path: "/etc/systemd/system/{{ item }}.service"
|
||||
@@ -54,10 +79,30 @@
|
||||
- e3oncan
|
||||
notify: Reload systemd
|
||||
|
||||
# The venvs are the point of this change -- leaving them would leave the thing
|
||||
# that churned. Their configuration is NOT removed: devices.json, the overlay
|
||||
# and the env file are still rendered below and bind-mounted into the
|
||||
# containers.
|
||||
# The invariant that actually matters is "no native process is on the CAN bus",
|
||||
# and systemd reporting success is not the same claim. Two open3e instances
|
||||
# polling one bus is the failure this whole block exists to prevent, so it is
|
||||
# asserted directly rather than inferred from the calls above.
|
||||
- name: Check for surviving native CAN processes
|
||||
ansible.builtin.command:
|
||||
argv: [pgrep, -af, "edge-host/(open3e|e3oncan)"]
|
||||
register: heating_can_survivors
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
|
||||
- name: Assert no native CAN process survived
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- heating_can_survivors.stdout | default('') | length == 0
|
||||
fail_msg: >-
|
||||
A native open3e/e3oncan process is still running after the units were
|
||||
stopped and removed:
|
||||
{{ heating_can_survivors.stdout_lines | default([]) | join('; ') }}.
|
||||
Starting the container now would put two readers on the same CAN bus --
|
||||
two open3e instances issue competing UDS requests and take over each
|
||||
other's MQTT session. Kill the survivors, then re-run.
|
||||
success_msg: No native CAN processes remain; safe to start the container.
|
||||
|
||||
- name: Remove the native venvs
|
||||
ansible.builtin.file:
|
||||
path: "{{ item }}"
|
||||
|
||||
Reference in New Issue
Block a user