docs: refresh the machine workloads how-to#2443
docs: refresh the machine workloads how-to#2443tonyandrewmeyer wants to merge 15 commits intocanonical:mainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
Refreshes the “run workloads on a machine charm” how-to to provide an end-to-end recommended pattern (code structure, package install, service lifecycle, and testing) for machine charms in the Ops documentation.
Changes:
- Adds MyST frontmatter with an HTML meta description and rewrites the introduction with links to examples.
- Introduces guidance on separating charm vs workload logic, installing workloads via charmlibs (APT/snap), and managing lifecycle/events.
- Adds testing guidance with example unit tests (Scenario) and integration tests (Jubilant), plus an examples/see-also section.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
dwilding
left a comment
There was a problem hiding this comment.
Thanks for spending time on this. It's a massive improvement over what we currently have!
Co-authored-by: Dave Wilding <tech@dpw.me>
Co-authored-by: Dave Wilding <tech@dpw.me>
|
|
||
| - **systemd units** (most APT packages) — use {external+charmlibs:ref}`charmlibs-systemd <charmlibs-systemd>`, or call `systemctl` as a subprocess. | ||
| - **snap services** — use `snap.Snap.start` / `.stop` / `.restart` from the snap library. | ||
| - **A process you launch directly** — use `subprocess.run` to start the daemon. The charm process is short-lived, so the command you run should return immediately and have a daemonized process. Send signals with `os.kill` (such as `SIGTERM` to stop and `SIGUSR1` to reload config). Read the workload's man page for the signals it supports. |
There was a problem hiding this comment.
Should we be recommending subprocess.Popen with args like stdout/err/in=subprocess.DEVNULL and start_new_session=True for starting long-running processes that don't take care of launching a separate daemon themselves?
Should we give explicit advice for how to get/store the daemon's PID? e.g. ideally the workload writes it to a known path, otherwise you should do so yourself.
There was a problem hiding this comment.
I'm not sure. I somewhat feel like our guidance should be "make a snap" if there isn't one, and then just use the snap instructions. But I felt that was maybe too aggressive and so included this fairly basic bit about not using snaps or debs. I'm not sure how much detail we want to go into - do we consider this a reasonable way to manage workloads?
There was a problem hiding this comment.
I like the idea of recommending making a snap for production use if there isn't one. Then we can frame launching a process directly as being for prototyping, and then I think it's fine as-is.
|
|
||
| For more on state-transition testing — including `State.from_context`, reusing state across events, and accessing the charm instance — see {ref}`write-unit-tests-for-a-charm`. | ||
|
|
||
| ## Write integration tests |
There was a problem hiding this comment.
Should we mention 'functional' style tests as well (in the sense used in charmlibs) -- non-Juju integration tests? These are typically a lot faster than Juju tests while giving you coverage of interactions with the real workload.
There was a problem hiding this comment.
Good suggestion, yes. I'll add a section for that.
Co-authored-by: James Garner <james.garner@canonical.com>
Adjust the "how to run workloads on a machine charm" how-to guide:
Preview