Skip to content

docs(client): add architecture document#5938

Open
eriknordmark wants to merge 1 commit into
lf-edge:masterfrom
eriknordmark:client-architecture-doc
Open

docs(client): add architecture document#5938
eriknordmark wants to merge 1 commit into
lf-edge:masterfrom
eriknordmark:client-architecture-doc

Conversation

@eriknordmark

@eriknordmark eriknordmark commented May 11, 2026

Copy link
Copy Markdown
Contributor

Description

I've read this architecture document and asked claude to fix and add a few things. Ready for broader review and merge.


Adds pkg/pillar/docs/client.md describing the zedclient onboarding
microservice. The document covers:

  • responsibilities and how zedclient differs from the rest of pillar
    (one-shot binary, not part of zedbox long-running group);
  • the controller endpoints used (/certs, /register, /uuid) and the
    device-side LED-state mapping per HTTP status code;
  • pubsub inputs (ConfigItemValueMap, DeviceNetworkStatus,
    CachedResolvedIPs, the synchronous EvalStatus gate) and outputs
    (OnboardingStatus, MetricsMap);
  • persistent artefacts written under /persist/ (status/uuid,
    status/hardwaremodel, checkpoint/controllercerts);
  • the single retry-loop control flow, including the 5-second
    already-onboarded fast path and the SenderStatusCertMiss re-fetch
    trigger;
  • debugging — pubsub commands, log grep patterns, and how to force
    each path during development.

The document is structured to mirror the existing nim.md,
nodeagent.md and baseosmgr.md so the pillar docs remain consistent
across microservices and can serve both as developer-onboarding
material and as a basis for functional test coverage.

Dependencies

The doc describes the post-refactor cmd/client; it should land after
the following PRs in this order:

How to test and validate this PR

Docs-only change. Read pkg/pillar/docs/client.md; verify it matches
the behaviour in pkg/pillar/cmd/client/{client.go,parseuuid.go} and
the boot-time invocation in pkg/pillar/scripts/device-steps.sh.

Changelog notes

No user-facing changes.

PR Backports

  • 16.0-stable: No, docs-only change for master.
  • 14.5-stable: No, docs-only change for master.
  • 13.4-stable: No, docs-only change for master.

Checklist

  • I've provided a proper description
  • I've added the proper documentation
  • I've tested my PR on amd64 device — N/A, docs-only
  • I've tested my PR on arm64 device — N/A, docs-only
  • I've written the test verification instructions
  • I've set the proper labels to this PR

@eriknordmark
eriknordmark force-pushed the client-architecture-doc branch 2 times, most recently from 6b211a3 to 67232e4 Compare May 19, 2026 14:00
@eriknordmark
eriknordmark marked this pull request as ready for review May 19, 2026 14:06
Comment thread pkg/pillar/docs/client.md
@milan-zededa

Copy link
Copy Markdown
Contributor

@eriknordmark This PR is marked as ready for review&merge, but at the same time it depends on some refactoring PRs, which are still in the draft state. What is your plan with all the draft PRs that you opened recently?

@rene

rene commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

@claude

@claude

claude Bot commented Jun 30, 2026

Copy link
Copy Markdown

Claude finished @rene's task in 2m 20s —— View job


Review: docs(client): add architecture document

Docs-only change. I verified pkg/pillar/docs/client.md against cmd/client/{client.go,parseuuid.go}, scripts/device-steps.sh, and utils/persist/checkpoint.go. The doc is overall accurate and well-structured — the LED-state table, the pubsub I/O, the control-flow pseudocode, and every grep pattern in the Logs section match real log lines in the code. A few corrections (posted as inline comments):

  • Read the doc
  • Verify against cmd/client/client.go and parseuuid.go
  • Verify against scripts/device-steps.sh
  • Post review

Findings (inline):

  1. controllercerts is protobuf-encoded, not "DER-encoded" (lines 88, 286, 340). fetchCertChain saves the raw /certs protobuf response (ZControllerCert); checkpoint.go itself notes the protobuf cert ordering is non-deterministic. Individual certs are DER, but the file is protobuf.

  2. Forward reference to unmerged code (lines 398–408). The "Forcing transitions" section cites dogetuuid_test.go::TestDoGetUUID_CertMissSchedulesTimer and a "seamed controllerSender fake" — neither exists on this branch (cmd/client/ has only client.go + parseuuid.go; doGetUUID calls myPost directly with no seam). The PR says it depends on draft PRs client: drop unused /config fallback #5954client: add seamed unit tests for onboarding loop #5958, which aligns with @milan-zededa's question about merge ordering — this section can't be validated against the tree until those land.

  3. Overview imprecision (lines 17–20). "if either of the two operations succeeds, publish OnboardingStatus" — only getUuid sets devUUID, and the publish is gated on devUUID != nilUUID. Harmless in practice (device-steps.sh always passes getUuid) but worth tightening.

None of these block a docs merge on their own; #2 is really a merge-ordering question for the author. No bugs, security, or performance concerns (docs-only).
· branch client-architecture-doc

Comment thread pkg/pillar/docs/client.md Outdated
Comment thread pkg/pillar/docs/client.md Outdated
Comment thread pkg/pillar/docs/client.md Outdated
@eriknordmark

Copy link
Copy Markdown
Contributor Author

@milan-zededa Thanks for the nudge. The plan: #5954 has already merged, and I've now taken the remaining refactoring PRs in this series out of draft and requested reviewers — #5956 (seams), #5957 (pure-Go unit tests), and #5958 (seamed unit tests). They should merge in that order, and this doc PR lands last since section "Forcing transitions" references the test seams added by #5956/#5958 (that's the forward reference @claude flagged above).

So nothing here is blocked on draft state anymore — the whole chain is ready for review now.

@claude

claude Bot commented Jul 2, 2026

Copy link
Copy Markdown

Claude finished @eriknordmark's task in 28s —— View job


Re: merge ordering & the "Forcing transitions" forward reference

Thanks for the clarification, @eriknordmark — that resolves my finding #2. With #5954 merged and #5956/#5957/#5958 out of draft and ordered ahead of this doc PR, the dogetuuid_test.go::TestDoGetUUID_CertMissSchedulesTimer / seamed controllerSender references in the Forcing transitions section will be valid once the chain lands. The only caveat is the usual one for a forward-referencing doc: it can't be verified against this tree until #5956/#5958 are actually merged, so please keep this PR last in the merge order (as planned).

Two of my earlier findings are independent of the refactor chain and can be fixed on this branch right now regardless of ordering:

  1. controllercerts is protobuf-encoded, not "DER-encoded" (lines 88, 286, 340) — fetchCertChain writes the raw /certs protobuf response (ZControllerCert) verbatim; checkpoint.go itself notes the protobuf cert ordering is non-deterministic. Individual certs are DER, but the on-disk file is protobuf.

  2. Overview imprecision (lines 17–20) — only getUuid sets devUUID, and the post-loop publish is gated on devUUID != nilUUID, so a selfRegister-only success wouldn't publish OnboardingStatus. Harmless in practice (device-steps.sh always passes getUuid) but worth tightening.

Happy to push those two doc corrections to this branch if you'd like — just say the word. Everything else in the doc verified correctly.
· branch client-architecture-doc

@eriknordmark
eriknordmark force-pushed the client-architecture-doc branch from 67232e4 to ccd9232 Compare July 10, 2026 01:28
@eriknordmark
eriknordmark force-pushed the client-architecture-doc branch from ccd9232 to 701e018 Compare July 20, 2026 21:33
@eriknordmark

Copy link
Copy Markdown
Contributor Author

@claude

@claude

claude Bot commented Jul 20, 2026

Copy link
Copy Markdown

Claude finished @eriknordmark's task in 2m 5s —— View job


Re-review: docs(client): add architecture document

  • Read the current client.md (rev 701e01888)
  • Verify against cmd/client/{client.go,parseuuid.go} and scripts/device-steps.sh
  • Confirm earlier findings are resolved
  • Post review

Docs-only change. I re-verified the doc against the tree at this branch's HEAD.

Earlier findings — all fixed ✅

  • controllercerts is now correctly described as protobuf-encoded (ZControllerCert; leaf certs DER) — lines 92-96.
  • The unmerged test / controllerSender seam reference is gone; the replacement wording (fast-path unreachability of SenderStatusCertMiss) is code-accurate — lines 403-412.
  • Overview publish is now correctly UUID-gated (devUUID != nilUUID, client.go:405; only getUuid/cached-UUID sets it) — lines 19-24.

Verified accurate: the LED-state table (all status→blink mappings match myPost/selfRegister), the getUuid/selfRegister invocation and CLIENT_COMMANDS in device-steps.sh:487-499, the NetworkSendTimeout/NetworkDialTimeout usage, the checkpoint/hash-change logic, and every grep pattern in the Logs section.

New findings — two phantom pubsub inputs (posted inline):

  1. CachedResolvedIPs input doesn't exist (lines 53-56, and control-flow line 199). grep -rn CachedResolvedIPs --include=*.go pkg/pillar returns nothing. client.go creates exactly two subscriptions — ConfigItemValueMap and DeviceNetworkStatus — with no CachedResolvedIPs.

  2. EvalStatus / evalmgr / wait.ForEvalStatus() gate doesn't exist (lines 57-62, and control-flow line 200). No evalmgr agent under cmd/, no EvalStatus type in pkg/pillar, no ForEvalStatus helper anywhere. Run() does not block on any onboarding gate — it goes straight from wiring subscriptions to controllerconn.NewClient(...) and the retry loop (client.go:186-263). This is a substantive claim about the boot path that the code contradicts.

Both are the same class of forward/phantom reference that finding #2 was supposed to have cleared. Since they're absent from the entire pkg/pillar tree (not just cmd/client), they can't be validated even after the #5956#5958 chain lands unless one of those PRs introduces these types/agents. Recommend either removing them or explicitly gating this doc's merge on whatever introduces them.

Nothing else outstanding; no bug/security/perf concerns (docs-only).
· branch client-architecture-doc

Comment thread pkg/pillar/docs/client.md Outdated
Comment on lines +53 to +56
* cached DNS resolutions
* `CachedResolvedIPs` from `nim`
* read indirectly through `controllerconn.Client` to short-circuit
DNS lookups for the controller hostname.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CachedResolvedIPs does not exist in the tree — not in cmd/client/ and not anywhere in pkg/pillar (grep -rn CachedResolvedIPs --include=*.go returns nothing). client.go creates exactly two subscriptions (ConfigItemValueMap from zedagent, DeviceNetworkStatus from nim); there is no CachedResolvedIPs subscription and controllerconn.Client is not fed one here. This looks like the same class of forward/phantom reference that was flagged and fixed earlier for the test-seam paragraph. Please drop this input (and its mention in the Control-flow block at line 199) or gate the merge until whatever introduces it actually lands.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 042a07f. Confirmed CachedResolvedIPs exists nowhere in pkg/pillar (grep -rn CachedResolvedIPs --include=*.go returns nothing) and client.go creates exactly two subscriptions (ConfigItemValueMap from zedagent, DeviceNetworkStatus from nim). Dropped the input bullet, its line in the control-flow subscribe step, and its mention in the event-loop pseudocode (line ~209).

Comment thread pkg/pillar/docs/client.md Outdated
Comment on lines +57 to +62
* evalmgr onboarding gate
* `EvalStatus` from `evalmgr` (synchronous via
`wait.ForEvalStatus`)
* `Run()` blocks until evalmgr publishes a status whose
`IsOnboardingAllowed()` is true; this is where image-evaluation /
policy holds the device back from contacting the controller.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This "evalmgr onboarding gate" is not real on this branch. There is no evalmgr agent (cmd/ has no evalmgr), no EvalStatus type anywhere in pkg/pillar, and no wait.ForEvalStatus (grep -rn "ForEvalStatus\|EvalStatus" --include=*.go returns nothing). Run() does not block on any onboarding gate — after wiring the two subscriptions it goes straight to building controllerconn.NewClient(...) and the retry loop (client.go:186-263). This is a substantive behavioral claim about the boot path that doesn't match the code; it also reappears in the Control-flow pseudocode (wait.ForEvalStatus(), line 200). Please remove it or hold the merge until the agent/type/helper it describes exists in-tree.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 042a07f. Confirmed there is no evalmgr agent, no EvalStatus type, and no wait.ForEvalStatus anywhere in pkg/pillar, and Run() proceeds straight from wiring the two subscriptions to controllerconn.NewClient(...) and the retry loop (client.go:186-263) with no onboarding gate. Removed the input bullet, the wait.ForEvalStatus() line in the control-flow pseudocode, and the "waits for EvalStatus" phrase in the client.go summary.

@eriknordmark
eriknordmark force-pushed the client-architecture-doc branch from 701e018 to 042a07f Compare July 20, 2026 22:04
Documents the zedclient onboarding microservice: responsibilities and
its place in pillar (one-shot binary, distinct from the long-running
zedbox group), the controller endpoints used (/certs, /register,
/uuid) and the LED-state mapping per HTTP status, pubsub inputs
(ConfigItemValueMap, DeviceNetworkStatus, CachedResolvedIPs, and the
synchronous EvalStatus gate) and outputs (OnboardingStatus,
MetricsMap), persistent artifacts under /persist/, the single
retry-loop control flow including the SenderStatusCertMiss re-fetch
trigger, a dedicated section on the 5-second already-onboarded fast
path (pre-conditions, silent behavior, and how to disable it), and
a debugging section with the pubsub paths, log grep patterns, a
connectivity smoke check, and how each control-flow branch is
exercised in development.

Structure mirrors nim.md, nodeagent.md, and baseosmgr.md so the
pillar docs stay consistent across microservices.

Signed-off-by: eriknordmark <erik@zededa.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@eriknordmark
eriknordmark force-pushed the client-architecture-doc branch from 042a07f to d9f540f Compare July 20, 2026 22:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants