cmd/snapd/cli: add snap routine user-service-precondition command - #17379
cmd/snapd/cli: add snap routine user-service-precondition command#17379olivercalder wants to merge 8 commits into
Conversation
Add a new `logind` package similar to the existing `systemd` package. Add a private function to invoke `loginctl`, and expose a `SessionClass` method which calls `loginctl show-session auto -p Class` and parses the resulting `Class=foo` to return `foo`. Signed-off-by: Oliver Calder <oliver.calder@canonical.com>
There was a problem hiding this comment.
Pull request overview
This PR introduces a hidden snap routine user-service-precondition subcommand intended for use in systemd ExecCondition= to prevent snap user daemons from starting in greeter sessions, by querying the current session class via loginctl.
Changes:
- Add a new
logindpackage that wrapsloginctl show-session auto -p Classand parses the session class. - Add the hidden
snap routine user-service-preconditioncommand that exits non-zero forgreeter(or when session class cannot be determined), with a configurable--error-exit-code. - Add unit tests for the new
logindpackage and the new routine command.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| logind/logind.go | Adds loginctl wrapper and SessionClass() parser used to determine current session class. |
| logind/logind_test.go | Adds tests covering class parsing and error formatting behavior. |
| logind/export_test.go | Exposes setters on logind.Error for black-box tests. |
| cmd/snapd/cli/export_test.go | Adds a mock hook for the logind session class function used by the routine command. |
| cmd/snapd/cli/cmd_routine_user_service_precondition.go | Adds the hidden snap routine user-service-precondition command that enforces the greeter/session-class precondition. |
| cmd/snapd/cli/cmd_routine_user_service_precondition_test.go | Adds tests validating exit-status behavior and stderr output for greeter/no-session cases. |
|
Fri Jul 24 13:27:10 UTC 2026 Failures:Preparing:
Executing:
Skipped tests from snapd-testing-skipIf you wish to have any of the below tests run in your PR, in your PR description, add 'unskip:' followed by a copy-and-pasted list of the below tests you wish to run (unskip plus test list must be valid yaml)
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #17379 +/- ##
==========================================
- Coverage 78.92% 78.92% -0.01%
==========================================
Files 1395 1395
Lines 195977 196064 +87
Branches 2466 2466
==========================================
+ Hits 154680 154743 +63
- Misses 32018 32035 +17
- Partials 9279 9286 +7
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
10aeb6b to
c78b2f4
Compare
pedronis
left a comment
There was a problem hiding this comment.
the panic shouldn't be used
Signed-off-by: Oliver Calder <oliver.calder@canonical.com>
Signed-off-by: Oliver Calder <oliver.calder@canonical.com>
Add a new `snap routine` subcommand designed to exit with an error code if invoked from within a systemd session with class which is`greeter`. The intent is for this to be called from `ExecCondition` stanzas in systemd unit files. Thus, the subcommand is hidden. Because this will be invoked by `systemd` via `ExecCondition` when deciding whether to start the service, the `SuccessExitStatus` also applies. Thus, we need to be sure not to exit with an error code which happens to match one of the success codes. To accomplish this, the new `snap routine user-service-precondition` command includes an optional argument `--error-exit-code` which takes an integer as an argument, defaulting to 1. The caller must ensure that the exit code passed in is not a success exit status. Signed-off-by: Oliver Calder <oliver.calder@canonical.com>
Signed-off-by: Oliver Calder <oliver.calder@canonical.com>
In order to exit with a particular error code, a panic was used, which was then caught and the code used to exit cleanly. However, this is unnecessary for `snap routine user-service-precondition`, we can instead simply add a new error type and handle it like other special error cases in `exitCodeFromError`. Signed-off-by: Oliver Calder <oliver.calder@canonical.com>
c78b2f4 to
a5f73fc
Compare
| return ErrExtraArgs | ||
| } | ||
| if x.ErrorExitCode < 1 || x.ErrorExitCode > 255 { | ||
| return &userSessionPreconditionError{code: 1, msg: "invalid --error-exit-code: must be in range 1-255"} |
There was a problem hiding this comment.
Yeah that makes more sense, thanks
Signed-off-by: Oliver Calder <oliver.calder@canonical.com>
pedronis
left a comment
There was a problem hiding this comment.
high level +1 but get closer reviews once the prereq are merged
zyga
left a comment
There was a problem hiding this comment.
Lgtm with two small suggestions inline.
| switch { | ||
| case err == nil: | ||
| return 0 | ||
| case errors.As(err, &userSessionPreconditionErr): |
There was a problem hiding this comment.
This could have been a more generic error type that can be used by any CLI.
In my go-cmdr library I use a pair of interfaces: https://pkg.go.dev/gitlab.com/zygoon/go-cmdr#ExitCoder and https://pkg.go.dev/gitlab.com/zygoon/go-cmdr#ExitMessenger to allow commands to influence the exit code and the (custom) error message a specific error should convey.
| // strip the "Class=" prefix from the output | ||
| orig := strings.TrimSpace(string(out)) | ||
| before, after, ok := strings.Cut(orig, "=") | ||
| if !ok || before != "Class" || after == "" || strings.Contains(after, "=") { |
There was a problem hiding this comment.
Nitpick: propName, propValue?
This PR is based on #17378. It's the second in a chain to implement
ExecConditionchecks to prevent user daemons from running within sessions with classgreeter. Spec here: https://docs.google.com/document/d/1PeWQrLDExIb5I7HqDYm1dn9WzQcqksKBn5a6V5ASvoI/editAdd a new
snap routinesubcommand designed to exit with an error code if invoked from within a systemd session with class which isgreeter. The intent is for this to be called fromExecConditionstanzas in systemd unit files. Thus, the subcommand is hidden.Because this will be invoked by
systemdviaExecConditionwhen deciding whether to start the service, theSuccessExitStatusalso applies. Thus, we need to be sure not to exit with an error code which happens to match one of the success codes. To accomplish this, the newsnap routine user-service-preconditioncommand includes an optional argument--error-exit-codewhich takes an integer as an argument, defaulting to 1. The caller must ensure that the exit code passed in is not a success exit status.CC @aleasto
This work is tracked internally by https://warthogs.atlassian.net/browse/SNAPDENG-37244