feat(snap): add snap install method to install.sh when available#2250
feat(snap): add snap install method to install.sh when available#2250olivercalder wants to merge 7 commits into
snap install method to install.sh when available#2250Conversation
|
All contributors have signed the DCO ✍️ ✅ |
|
I have read the DCO document and I hereby sign the DCO. |
|
recheck |
…ovisioning Add snap install path to install.sh so that on Linux systems with snapd available and no native Docker Engine installed, the installer chooses the snap path. Snap is preferred when 'snap' command exists and 'snapd.socket' is active. New functions: - has_snapd(): detects snapd availability via snap command + snapd.socket - has_native_docker(): pre-flight check for conflicting native Docker - install_linux_snap(): installs openshell snap, Docker snap if missing, connects interfaces (best-effort), registers gateway via HTTP, verifies status - register_local_gateway_snap(): gateway add with http:// URL (no mTLS) - wait_for_local_gateway_listener_snap(): waits for HTTP listener linux_package_method() returns 'snap' when snapd is available and no native docker, respecting OPENSHELL_INSTALL_METHOD=classic override. The installer handles the full flow: installing Docker snap if missing, connecting all required interfaces, and registering the gateway. Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
Fix the snap gateway protocol from https to http to match what the installer actually registers. Correct misleading claims that the installer "exits with an error" and "refuses" snap installs on hosts with native Docker — it silently falls back to classic. Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
Adjust the wording of the installation docs for the `openshell` snap. In particular, clarify when the snap will be installed, how it currently requires the docker snap, and how to override the installation method. Also, prune some of the manual interface connections, as these have since been granted autoconnection via snap store assertions. See: https://forum.snapcraft.io/t/please-update-snap-declaration-assertion-for-openshell/51762 Signed-off-by: Oliver Calder <oliver.calder@canonical.com>
As @drew suggested, add `deb`, `rpm`, `snap`, and `homebrew` as installation methods which the user can specify via `OPENSHELL_INSTALL_METHOD` rather than falling back to detecting the package manager automatically. `homebrew` is not yet supported on Linux, and it is the only supported option on MacOS. Also adds a TODO to implement `install_linux_homebrew` in the future. Signed-off-by: Oliver Calder <oliver.calder@canonical.com>
70480f2 to
22525a2
Compare
|
Rebased to pull in the changes from #2280 which remove the |
|
We're shipping an improvement to the Once snapd 2.77 hits |
|
Would you mind updating the release-canary Github Action to use this? Presently it fetches the snap from the release artifacts and installs it manually, but the other installations (excepting Kubernetes) use install.sh to install the latest available version. In the near future this will all change when we revamp the build and release process, but for now consistency is probably better. I'm unsure about exposing an env var to force the installation mechanism. To me, the contract of |
Split the `ubuntu` release canary into three jobs: - `ubuntu-deb`: test that `install.sh` installs the OpenShell .deb package on Ubuntu when snapd is not present. - `ubuntu-deb-native-docker`: test that `install.sh` installs the OpenShell .deb package on Ubuntu when a native docker daemon is present -- this will change when snapd 2.77 is released to the `latest/stable` channel, which will allow the `openshell` snap to connect to non-snap Docker daemons; this job will then be renamed to `ubuntu-snap-native-docker`. - `ubuntu-snap-without-docker`: test that `install.sh` installs both the `openshell` and `docker` snaps if snapd is present and there is no Docker daemon installed. In all variants, the canary tests that `openshell status` succeeds after installation. Signed-off-by: Oliver Calder <oliver.calder@canonical.com>
The change in snapd to support the `openshell` snap connecting to a non-snap Docker daemon will ship in snapd 2.77, not 2.76. Also, all the `openshell` snap interfaces are now auto-connected, so there is no need for manual connection anymore. Remove these from the description. Signed-off-by: Oliver Calder <oliver.calder@canonical.com>
The contract of `install.sh` is to choose the best installation method for the host system. Adding the `OPENSHELL_INSTALL_METHOD` variable breaks that contract, so it is best to remove it. Signed-off-by: Oliver Calder <oliver.calder@canonical.com>
|
Done and done, thanks for the suggestions. I've split the
In all jobs, test that The .deb package and snap package both need to be tested, and the snap will need to be tested with both the |
|
Label |
| fi | ||
| sudo systemctl start docker || sudo service docker start | ||
| mkdir -p "${HOME}/.config/openshell" | ||
| printf 'OPENSHELL_DRIVERS=docker\n' > "${HOME}/.config/openshell/gateway.env" |
There was a problem hiding this comment.
Is this line required? I would have expected gateway auto-detection of Docker to work.
There was a problem hiding this comment.
I'm not certain, it may work without. This is directly copied from the existing ubuntu job (now called ubuntu-deb-native-docker). These two jobs are largely equivalent at the moment, but ubuntu-deb-native-docker will become ubuntu-snap-native-docker once native docker support works by default.
| When installing from the Snap Store, snapd automatically connects the `home`, | ||
| `network`, and `network-bind` plugs. The `docker` plug still | ||
| requires manual connection: | ||
| The OpenShell snap requires the Docker snap, which you can install with: |
There was a problem hiding this comment.
If the OpenShell snap requires the Docker snap, does that also mean it cannot be used with Podman? I'm wondering what this means for auto-detection, which prefers Podman over Docker. It seems like we need to document this limitation of the snap more clearly, if that's the case. I'd expect to see the docs say very clearly that the snap only works with Docker and you should configure Docker as the openshell driver explicitly to avoid issues if you also have Podman running.
There was a problem hiding this comment.
Currently, yes, the OpenShell snap requires the Docker snap. But we can fairly easily extend this:
Non-snap Docker
We landed support for connecting to a non-snap Docker daemon in snapd 2.77, being cut nowish and released to latest/stable in ~6 weeks. But we can test this immediately by trying snapd latest/edge channel in the install scripts/jobs.
Podman
We can support connecting to Podman by requesting a store assertion to allow connecting the podman interface on https://forum.snapcraft.io/. We at Canonical can of course drive this request, but before doing so we should probably settle on a direction regarding running the gateway daemon as a system or user service.
As for why we need a store assertion for connecting to Podman but not to Docker: there's a docker snap which provides the docker-daemon slot for OpenShell's docker plug to connect to (and the new docker interface change allows connecting to the system slot, i.e. non-snap Docker daemon), but there is no snap of Podman. The current podman interface disallows connection without an assertion, which is a bit weird, usually super-privileged interfaces just deny installation without an assertion, but for historical reasons the docker and podman interfaces were defined a bit differently from most interfaces.
System vs user service
The most important thing to decide IMO is whether we want to run the OpenShell gateway daemon as a system service or user service. Currently, it's a system service, which has WantedBy=multi-user.target, so it starts as root after boot. This makes sense with Docker, as Docker also runs as root as a system service. AFAIK you can run podman as a system service, but a major benefit of Podman is that it can run rootless as a user service. It doesn't make sense for an OpenShell gateway system daemon to try to talk to a podman user service, so it feels like if we want to prioritize rootless Podman support, we probably want to run the gateway as a user service.
This change could be made immediately, if desired. This can be done by adding daemon-scope: user to snapcraft.yaml next to the daemon: simple field. The user-daemons feature in snapd is still experimental, but there's an override in snapd which already allows particular snaps to run user daemons, and openshell is one of the snaps explicitly allowed -- that means users/install.sh would not need to manually enable the user-daemons feature. Additionally, the snapd team (and I in particular) are working to polish that feature and enable it by default for the next snapd release or so (2.78 or 2.79).
But, running as a user service has potential drawbacks IMO, which are not specific to the snap or any packaging format. Currently, you can install the openshell snap in a headless environment and connect to it, since it runs as root, no user logged in. But if the gateway service runs as a user daemon, then you'd need to log in with a particular user in order to start the gateway, and then enable linger or run in tmux or something if you want that service to persist. And since (AFAIK) the gateway always tries to listen on the same port, then if more than one user logs into a system, the gateway will fail to start for everyone but the first user who happened to log in.
My understanding is there is discussion about switching to using a unix domain socket for the gateway user service instead of listening on a port, and that would indeed fix the user conflict issue, though if there's only a user service then there still wouldn't be a good way to connect to connect to the gateway if it's not running on your local machine, nor to handle running in headless boxes without user logged in.
So it feels to me like there are some situations where one would reasonably want to run as a system service (e.g. in headless environment) and some where a user service makes more sense (e.g. on a local end-user machine). I see a few possibilities:
- Just include two daemons in the
snapcraft.yamlappsstanza, one of which is a system daemon and one of which is a user daemon, and run both- This would require the user daemon to not try to bind to the same port as the system daemon, though, else they'd conflict and fail to start one or the other service
- Add the ability to select at install time whether you want to include the system service or user service, or neither
- This sounds like a good use for snap components
- You'd end up with something like
snap install openshell+system-gatewayorsnap install openshell+user-gateway - Then
snap install openshellshould do some sensible default, probably install the user gateway component, as running the gateway as a user service is presumably less privileged, and more what an end user runninginstall.shorsnap install openshellis likely to want
- Add the ability to configure this after installation
- This would likely be done via snap configuration options which we can define to enable or disable the system or user service OpenShell gateway depending on the setting.
- You'd end up with something like
snap set openshell gateway-scope=systemorsnap set openshell gateway-scope=user, with the default probably beinguser
Personally, I feel like it's a bad idea to switch the gateway to run as a user service without first switching to using unix domain sockets instead of listening on a fixed port. But this is an upstream OpenShell concern, not specific to the snap packaging. And we're happy to help package whatever configuration you'd prefer.
|
/ok to test c91aea9 |
|
I ran this with e2e but what I actually meant to do was run the release-canary workflow for it, which I did here: https://github.com/NVIDIA/OpenShell/actions/runs/29593468971 The snap installation without Docker failed, which we expect until this is merged and a new snap is published. The others succeeded, though, which is good. |
olivercalder
left a comment
There was a problem hiding this comment.
Thanks for the review. I've written up some notes about the current state of things regarding the openshell snap connecting to snap/non-snap Docker, Podman, and running as a system vs user service.
| When installing from the Snap Store, snapd automatically connects the `home`, | ||
| `network`, and `network-bind` plugs. The `docker` plug still | ||
| requires manual connection: | ||
| The OpenShell snap requires the Docker snap, which you can install with: |
There was a problem hiding this comment.
Currently, yes, the OpenShell snap requires the Docker snap. But we can fairly easily extend this:
Non-snap Docker
We landed support for connecting to a non-snap Docker daemon in snapd 2.77, being cut nowish and released to latest/stable in ~6 weeks. But we can test this immediately by trying snapd latest/edge channel in the install scripts/jobs.
Podman
We can support connecting to Podman by requesting a store assertion to allow connecting the podman interface on https://forum.snapcraft.io/. We at Canonical can of course drive this request, but before doing so we should probably settle on a direction regarding running the gateway daemon as a system or user service.
As for why we need a store assertion for connecting to Podman but not to Docker: there's a docker snap which provides the docker-daemon slot for OpenShell's docker plug to connect to (and the new docker interface change allows connecting to the system slot, i.e. non-snap Docker daemon), but there is no snap of Podman. The current podman interface disallows connection without an assertion, which is a bit weird, usually super-privileged interfaces just deny installation without an assertion, but for historical reasons the docker and podman interfaces were defined a bit differently from most interfaces.
System vs user service
The most important thing to decide IMO is whether we want to run the OpenShell gateway daemon as a system service or user service. Currently, it's a system service, which has WantedBy=multi-user.target, so it starts as root after boot. This makes sense with Docker, as Docker also runs as root as a system service. AFAIK you can run podman as a system service, but a major benefit of Podman is that it can run rootless as a user service. It doesn't make sense for an OpenShell gateway system daemon to try to talk to a podman user service, so it feels like if we want to prioritize rootless Podman support, we probably want to run the gateway as a user service.
This change could be made immediately, if desired. This can be done by adding daemon-scope: user to snapcraft.yaml next to the daemon: simple field. The user-daemons feature in snapd is still experimental, but there's an override in snapd which already allows particular snaps to run user daemons, and openshell is one of the snaps explicitly allowed -- that means users/install.sh would not need to manually enable the user-daemons feature. Additionally, the snapd team (and I in particular) are working to polish that feature and enable it by default for the next snapd release or so (2.78 or 2.79).
But, running as a user service has potential drawbacks IMO, which are not specific to the snap or any packaging format. Currently, you can install the openshell snap in a headless environment and connect to it, since it runs as root, no user logged in. But if the gateway service runs as a user daemon, then you'd need to log in with a particular user in order to start the gateway, and then enable linger or run in tmux or something if you want that service to persist. And since (AFAIK) the gateway always tries to listen on the same port, then if more than one user logs into a system, the gateway will fail to start for everyone but the first user who happened to log in.
My understanding is there is discussion about switching to using a unix domain socket for the gateway user service instead of listening on a port, and that would indeed fix the user conflict issue, though if there's only a user service then there still wouldn't be a good way to connect to connect to the gateway if it's not running on your local machine, nor to handle running in headless boxes without user logged in.
So it feels to me like there are some situations where one would reasonably want to run as a system service (e.g. in headless environment) and some where a user service makes more sense (e.g. on a local end-user machine). I see a few possibilities:
- Just include two daemons in the
snapcraft.yamlappsstanza, one of which is a system daemon and one of which is a user daemon, and run both- This would require the user daemon to not try to bind to the same port as the system daemon, though, else they'd conflict and fail to start one or the other service
- Add the ability to select at install time whether you want to include the system service or user service, or neither
- This sounds like a good use for snap components
- You'd end up with something like
snap install openshell+system-gatewayorsnap install openshell+user-gateway - Then
snap install openshellshould do some sensible default, probably install the user gateway component, as running the gateway as a user service is presumably less privileged, and more what an end user runninginstall.shorsnap install openshellis likely to want
- Add the ability to configure this after installation
- This would likely be done via snap configuration options which we can define to enable or disable the system or user service OpenShell gateway depending on the setting.
- You'd end up with something like
snap set openshell gateway-scope=systemorsnap set openshell gateway-scope=user, with the default probably beinguser
Personally, I feel like it's a bad idea to switch the gateway to run as a user service without first switching to using unix domain sockets instead of listening on a fixed port. But this is an upstream OpenShell concern, not specific to the snap packaging. And we're happy to help package whatever configuration you'd prefer.
| fi | ||
| sudo systemctl start docker || sudo service docker start | ||
| mkdir -p "${HOME}/.config/openshell" | ||
| printf 'OPENSHELL_DRIVERS=docker\n' > "${HOME}/.config/openshell/gateway.env" |
There was a problem hiding this comment.
I'm not certain, it may work without. This is directly copied from the existing ubuntu job (now called ubuntu-deb-native-docker). These two jobs are largely equivalent at the moment, but ubuntu-deb-native-docker will become ubuntu-snap-native-docker once native docker support works by default.
Summary
Update
install.shto install the OpenShellsnappackage if snapd is available on the system and the required conditions are met. Also add theOPENSHELL_INSTALL_METHODenvironment variable to force a particular install method rather than fall back to automatic system detection.Related Issue
Based on: #1697 (picking up the work from @zyga)
Addresses: #1674
Changes
snapdand if compatible conditions (dockersnap) are met, installs the snap from the store.OPENSHELL_INSTALL_METHODto override automatic detectiondeb,rpm,snap, andhomebrewTesting
mise run pre-commitpassesChecklist