confd: set IITO startup/failure conditions (fixes status LEDs) - #1587
confd: set IITO startup/failure conditions (fixes status LEDs)#1587pjator wants to merge 2 commits into
Conversation
|
When Currently, a condition is set when startup is applied: Line 844 in 279fc86 But there are no corresponding conditions for the failure cases. I suggest we add those and then update the IITO configuration to match. |
wkz
left a comment
There was a problem hiding this comment.
Let's fix the root cause so that it (1) fixes all boards and (2) also fixes the error cases when startup fails to apply cleanly.
|
Fixed per your suggestion. confd now sets run/startup/success after a clean bootstrap and run/failure/success/run/failure/failure in handle_startup_failure() (fail-secure + panic paths). The board-specific workaround is dropped. Verified on hardware: LED lights on boot, eMMC visible. |
There was a problem hiding this comment.
Thanks for taking another stab at this! Sorry about the slew of comments 😅 - you picked a pretty core piece of code for your first contribution.
In addition to these changes, I think handle_startup_failure() might need some additional changes. Let's wait and see what @troglobit thinks.
Also, the IITO config needs to be updated to reference the new condition names.
| char path[128]; | ||
| char *p; | ||
|
|
||
| snprintf(path, sizeof(path), "/run/finit/cond/%s", cond); |
There was a problem hiding this comment.
| snprintf(path, sizeof(path), "/run/finit/cond/%s", cond); | |
| snprintf(path, sizeof(path), "/run/finit/cond/usr/%s", cond); |
I understand the impulse to use the old condition names from IITO's config. However, the run/ namespace is reserved by Finit to signal the status of run jobs under its control. The usr/ namespace is allocated for general use by the system.
| /* mkdir -p parent directories (e.g. /run/finit/cond/run/startup) */ | ||
| for (p = path + strlen("/run/finit/cond/"); *p; p++) { | ||
| if (*p == '/') { | ||
| *p = '\0'; | ||
| mkdir(path, 0755); | ||
| *p = '/'; | ||
| } | ||
| } |
There was a problem hiding this comment.
| /* mkdir -p parent directories (e.g. /run/finit/cond/run/startup) */ | |
| for (p = path + strlen("/run/finit/cond/"); *p; p++) { | |
| if (*p == '/') { | |
| *p = '\0'; | |
| mkdir(path, 0755); | |
| *p = '/'; | |
| } | |
| } |
Finit guarantees that /run/finit/cond/usr exists (via a tmpfiles snippet). So with the suggested change above, together with limiting condition names to a single level, we can safely skip this.
| symlink("/run/finit/cond/reconf", "/run/finit/cond/usr/bootstrap"); | ||
|
|
||
| /* Signal IITO that startup applied cleanly (status LEDs) */ | ||
| set_finit_cond("run/startup/success"); | ||
|
|
There was a problem hiding this comment.
| symlink("/run/finit/cond/reconf", "/run/finit/cond/usr/bootstrap"); | |
| /* Signal IITO that startup applied cleanly (status LEDs) */ | |
| set_finit_cond("run/startup/success"); | |
| set_finit_cond("bootstrap"); |
Let's move the existing condition to use the new helper, but I don't think we can be sure that startup has cleanly applied at this point. I have marked that point in a separate comment.
| if (r != SR_ERR_OK) | ||
| WARN("Failed to sync startup datastore: %s", sr_strerror(r)); | ||
|
|
||
| return 0; |
There was a problem hiding this comment.
| set_finit_cond("startup-config-ok"); | |
| return 0; |
I believe this is the point where we want to signal a successful application of startup-config
| int r; | ||
|
|
||
| ERROR("Failed loading startup-config, reverting to Fail Secure mode!"); | ||
|
|
There was a problem hiding this comment.
| set_finit_cond("startup-config-error"); |
Whatever happens beyond this point, I think we should leave a marker that we could not apply startup-config.
| /* Nuclear option: wipe everything */ | ||
| systemf("rm -f /etc/sysrepo/data/*startup* /etc/sysrepo/data/*running* /dev/shm/sr_*"); | ||
| set_finit_cond("run/failure/failure"); | ||
| return; |
There was a problem hiding this comment.
@troglobit: Should we not emit the CRITICAL ERROR: ... in this scenario as well? The system is still without any defined config in this case, no?
There was a problem hiding this comment.
Agreed. The more feedback we can provide the user with in these cases the better. Possibly those cases could also be consolidated better than what I managed in my refactor.
| ERROR("Failed loading failure-config, aborting!"); | ||
| banner_append("CRITICAL ERROR: Logins are disabled, no credentials available"); | ||
| systemf("initctl -nbq runlevel 9"); | ||
| set_finit_cond("run/failure/failure"); |
There was a problem hiding this comment.
| set_finit_cond("run/failure/failure"); | |
| set_finit_cond("failure-config-error"); |
Depending on @troglobit's input, this path may have to be merged with the earlier error path. But I think at think point we want to signal "we tried, but failed, to apply failure-config.
There was a problem hiding this comment.
Yup, agreed. Just a heads up on the grammar there, I've tried to consistently apply the progressive form of the noun in error and status messages, throughout. So something like, CRIT("failed applying failure-config, error %d: %s"); or something.
| } | ||
|
|
||
| banner_append("ERROR: Corrupt startup-config, system has reverted to default login credentials"); | ||
| set_finit_cond("run/failure/success"); |
There was a problem hiding this comment.
| set_finit_cond("run/failure/success"); | |
| set_finit_cond("failure-config-ok"); |
For symmetry with the other condition names.
|
@wkz Thanks for the thorough review — it's really helpful, and I agree with the direction (usr/ namespace, single-level condition names, and updating the IITO config accordingly). I'll wait for @troglobit's input before pushing an updated version, so we can address everything in one pass and match the structure you'd prefer. I'll follow up once he's had a chance to weigh in. |
|
Impressive going into the deepest and darkest places, which admittedly needs better lighting. I agree in general with @wkz, only had a minor comment to add. |
The product and common iitod.json configurations reference finit
conditions to drive the status LEDs, but nothing ever creates them,
so the LEDs stay dark on every boot.
confd now signals the outcome of the bootstrap sequence via finit
conditions in the usr/ namespace:
usr/bootstrap bootstrap entered (Finit guarantees
/run/finit/cond/usr exists)
usr/startup-config-ok startup-config applied cleanly
usr/startup-config-error startup-config failed, fail-secure mode
usr/failure-config-ok failure-config (or factory default) loaded
usr/failure-config-error failure-config could not be applied
The IITO configuration is updated to reference the new condition
names, and the failure paths now emit a CRITICAL ERROR banner so the
user always gets feedback when the system is left without a defined
configuration.
Co-authored-by: Jarvis (Hermes Agent) <jarvis@woxblom.com>
|
@wkz @troglobit Thanks for the thorough review! @troglobit — the final frontier admittedly doesn't come with streetlights. 🖖 All feedback addressed and force-pushed (a7c95cd):
Build verified (aarch64), hardware test planned for this evening when I get home from work. |
|
Hardware test: IITO conditions verified on physical device Tested on a NanoPi R2S Plus (32 GB eMMC variant) with the full chain: main + #1586 + #1588 + #1589 + this PR. Built clean from scratch, installed via RAUC (secondary slot), boot status good. Results: Caveat: the test unit failed at the end of the session. A power-rail component — identified as the 3.3 V LDO (U13) on the USB-C power path per the FriendlyELEC schematic — released smoke and the board no longer powers up. Notably, the unit was powered by a 100 W USB-PD charger; a PD negotiation to a higher voltage (9/12 V) on a circuit designed for 5 V would exceed the LDO's rating and is the most plausible cause (and my mistake). We found no mechanism by which the software changes could cause a power-rail failure, but we cannot entirely rule out that the code or test procedure played a part. The conditions/LED behaviour above was observed before the unit failed. All software-side validation (boot, conditions, LEDs, WebUI, networking) is complete and passes. Replacement parts are ordered and I will attempt to repair the device, but I cannot provide Infamy test results since the device died while I was running those tests overnight. Image of component that is smoking.
|
Thanks for verifying!
Ouch! 😞 |
|
Hardware test NanoPi R2S Plus (eMMC): PASS — no regressions observed Tested on NanoPi R2S Plus (eMMC) with the full chain: A note on the test unit: as commented above it suffered a hardware failure on the power side during my initial testing (the M.2/WiFi regulator, U13 / SY8089A, blew up). After some soldering-iron magic I removed U13 — it only supplies the M.2 expansion slot, which is not in use — and the board came back to life, which allowed me to complete the Infamy tests below. Infamy suite (test mode, RESTCONF):
Manual verification (normal operation):
Not passed (pre-existing, not caused by this PR):
On a personal note: the Infamy tests are not the easiest to set up and run on physical hardware for a beginner, and I have not managed to produce a |


iitod.json expects /run/finit/cond/run/startup/success before the LAN and status LEDs light up, but nothing ever creates it. Add a small finit service (after confd/ready) that sets the condition on every boot.
Description
Checklist
Tick relevant boxes, this PR is-a or has-a: