Files
OpenShell/tasks/scripts/test-packaging-assets.sh
Oliver Calder 1ad4e428a6 fix(snap): simplify snap hooks (#3988)
* fix(snap): simplify snap hooks

The `post-refresh` hook runs after initial snap installation as well, so
there is no need to call the `install` hook from within the
`post-refresh` hook; instead, the logic can simply be moved into the
`post-refresh` hook directly, and the `install` hook removed.

Also, the existing `install` hook logic looked for an insecure
configuration, and if found, replaced the entire configuration file with
a minimal default in the current format. But OpenShell does that default
behavior without any config file, so we may as well simply remove the
configuration file entirely to keep up-to-date with the current default
behavior. Let OpenShell create a configuration file if it needs to,
rather than auto-create one via the packaging scripts.

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* fix(snap): remove the connect-plug-docker hook

The `openshell:docker` is auto-connected to the system `:docker` slot,
so there should not be a need to separately restart the gateway service
when the interface is connected.

For locally-built test snaps which were not published to the store, the
autoconnection is not made, but when the snap is installed, the gateway
will attempt to start anyway and fail to find any available compute
driver, so quickly restart until it hits the systemd start-limit, after
which systemd prevents the service from being started again. If a user
tries to manually connect their locally-built `openshell` snap to the
`:docker` slot, then the `connect-plug-docker` hook runs and triggers a
restart of the gateway, which will usually fail because the start limit
has already been hit. An error in the hook will thus cause the interface
connection to be undone, which is undesirable.

Thus, we can remove this hook entirely, and instead allow interface
connections to succeed as intended. The user still needs to manually
restart the gateway service after making a manual connection (as was the
case previously) and probably needs to `systemctl reset-failed` first,
but at least connection will succeed beforehand so they can proceed with
these steps.

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* fix(snap): set refresh-mode: endure again, with manual restart

Return to the previous behavior before commit a67567e58, where the
gateway is not stopped before refreshes. The `post-refresh` hook
now restarts the gateway if the TLS configuration was corrected, so we
don't have to enforce restarting the gateway on every refresh even when
not necessary. Thus, set `refresh-mode: endure`, and let the hook decide
when the gateway needs to be restarted.

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* fix(snap): update docs and tests to reflect snap hook changes

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* docs(snap): remove verbose explanation of snap gateway refresh behavior

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

---------

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>
2026-10-01 15:10:38 +00:00

202 lines
8.3 KiB
Bash
Executable File

#!/usr/bin/env bash
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
assert_contains() {
local file=$1
local expected=$2
if ! grep -Fq -- "$expected" "$file"; then
echo "FAIL: ${file} is missing expected text:" >&2
echo " ${expected}" >&2
exit 1
fi
}
assert_not_contains() {
local file=$1
local unexpected=$2
if grep -Fq -- "$unexpected" "$file"; then
echo "FAIL: ${file} contains stale text:" >&2
echo " ${unexpected}" >&2
exit 1
fi
}
assert_file_exists() {
local file=$1
if [[ ! -f "$file" ]]; then
echo "ERROR: ${file} not found" >&2
exit 1
fi
}
service="${ROOT}/deploy/deb/openshell-gateway.service"
control="${ROOT}/deploy/deb/control.in"
spec="${ROOT}/openshell.spec"
assert_file_exists "$service"
assert_file_exists "$control"
assert_file_exists "$spec"
# Debian control files are RFC822-style metadata. Older dpkg-deb releases
# reject comment lines as malformed fields, so keep SPDX metadata in the
# adjacent .license sidecar instead of emitting it into DEBIAN/control.
if grep -Eq '^[[:space:]]*#' "$control"; then
echo "FAIL: Debian control template contains a comment field" >&2
exit 1
fi
if [[ $(sed -n '/[^[:space:]]/ { p; q; }' "$control") != "Package: openshell" ]]; then
echo "FAIL: Debian control template must begin with the Package field" >&2
exit 1
fi
assert_contains \
"$service" \
'Environment=OPENSHELL_LOCAL_TLS_DIR=%h/.local/state/openshell/tls'
assert_contains \
"$service" \
'ExecStartPre=/usr/bin/openshell-gateway generate-certs --output-dir ${OPENSHELL_LOCAL_TLS_DIR} --server-san host.openshell.internal'
assert_not_contains "$service" '%S/openshell/tls'
assert_contains \
"$spec" \
'Environment=OPENSHELL_LOCAL_TLS_DIR=%%h/.local/state/openshell/tls'
assert_contains \
"$spec" \
'ExecStartPre=/usr/bin/openshell-gateway generate-certs --output-dir ${OPENSHELL_LOCAL_TLS_DIR} --server-san host.openshell.internal'
assert_contains "$spec" 'ExecStartPre=/usr/bin/openshell-gateway config preflight'
assert_contains "$spec" '%package prover'
assert_contains "$spec" '%files prover'
assert_contains "$spec" '%{_bindir}/%{name}-prover'
assert_not_contains "$spec" '%%S/openshell/tls'
# Schema-v2 package startup wiring.
snap_wrapper="${ROOT}/tasks/scripts/snap-gateway-wrapper.sh"
snapcraft="${ROOT}/snapcraft.yaml"
snap_install_docs="${ROOT}/docs/about/installation.mdx"
snap_canary="${ROOT}/.github/workflows/release-canary.yml"
snap_repro="${ROOT}/nix/test-guest/scripts/snap-gateway-repro.sh"
snap_post_refresh_hook="${ROOT}/snap/hooks/post-refresh"
package_deb="${ROOT}/tasks/scripts/package-deb.sh"
assert_file_exists "$snap_wrapper"
assert_file_exists "$snapcraft"
assert_file_exists "$snap_install_docs"
assert_file_exists "$snap_canary"
assert_file_exists "$snap_repro"
assert_file_exists "$snap_post_refresh_hook"
assert_file_exists "$package_deb"
assert_contains "$service" "ExecStartPre=/usr/bin/openshell-gateway config preflight"
assert_contains "$package_deb" "\$src_dir/openshell-gateway.service"
assert_contains "$package_deb" "\$pkgroot/usr/lib/systemd/user/openshell-gateway.service"
assert_contains "$snap_wrapper" "if [ -n \"\${OPENSHELL_GATEWAY_CONFIG:-}\" ]; then"
assert_contains \
"$snap_wrapper" \
"elif [ -e \"\$CANONICAL_CONFIG_FILE\" ] || [ -L \"\$CANONICAL_CONFIG_FILE\" ]; then"
assert_contains "$snap_wrapper" "config preflight -- --config \"\$CANONICAL_CONFIG_FILE\" \"\$@\""
assert_not_contains "$snap_wrapper" "[ -f \"\$CANONICAL_CONFIG_FILE\" ]"
bash "$ROOT/tasks/scripts/test-snap-gateway-wrapper.sh" "$snap_wrapper"
# Store installs autoconnect all required interfaces and require snapd 2.76 for
# the system Docker slot. Manual connection for locally-built snaps requires
# snapd 2.77.
assert_contains "$snapcraft" "assumes: [snapd2.76]"
for snap_file in \
"$snapcraft" \
"$snap_install_docs" \
"$snap_canary" \
"$snap_repro" \
"$snap_post_refresh_hook"; do
assert_not_contains "$snap_file" "docker:docker-daemon"
assert_not_contains "$snap_file" "default-provider: docker"
done
if [[ -e "${ROOT}/snap/hooks/connect-plug-docker" ]]; then
echo "FAIL: obsolete Snap Docker connection hook must not exist" >&2
exit 1
fi
if [[ -e "${ROOT}/snap/hooks/install" ]]; then
echo "FAIL: obsolete Snap install hook must not exist" >&2
exit 1
fi
assert_contains "$snapcraft" 'refresh-mode: endure'
if [[ ! -x "$snap_post_refresh_hook" ]]; then
echo "FAIL: Snap post-refresh hook must be executable" >&2
exit 1
fi
assert_not_contains "$ROOT/tasks/scripts/snap-gateway-wrapper.sh" 'OPENSHELL_DISABLE_TLS'
bash "$ROOT/tasks/scripts/test-snap-post-refresh-hook.sh" "$snap_post_refresh_hook"
assert_not_contains "$snap_install_docs" "snap connect openshell:home"
assert_not_contains "$snap_install_docs" "snap connect openshell:network"
assert_not_contains "$snap_install_docs" "snap connect openshell:network-bind"
assert_contains "$snap_install_docs" "snap connect openshell:docker :docker"
assert_contains "$snap_install_docs" "systemctl reset-failed snap.openshell.gateway.service"
assert_contains "$snap_install_docs" "snap restart openshell.gateway"
assert_contains "$snap_install_docs" "Snap refreshes keep the running gateway process active"
assert_contains "$snap_install_docs" "install script refreshes and restarts the gateway automatically"
assert_contains "$snap_canary" "install.sh | sh"
assert_contains "$snap_canary" "ubuntu-snap-system-docker:"
assert_contains "$snap_canary" "ubuntu-snap-docker-preflight:"
assert_contains "$snap_repro" 'OPENSHELL_INSTALL_METHOD=snap OPENSHELL_VERSION=dev sh "${install_script}"'
assert_contains "$snap_repro" "system-docker"
assert_contains "$snap_repro" "missing-docker"
assert_contains "$snap_repro" "docker-snap"
assert_not_contains "$snap_canary" "--dangerous"
assert_not_contains "$snap_repro" "--dangerous"
assert_not_contains "$snap_canary" "snap connect openshell:docker"
assert_not_contains "$snap_repro" "snap connect openshell:docker"
if ! awk '/config preflight/ { seen = 1 } /generate-certs/ { exit !seen }' "$service"; then
echo "FAIL: Debian preflight must precede certificate generation" >&2
exit 1
fi
if ! awk \
'/^ExecStartPre=.*gateway-migrate-config / { migrated = 1 } \
/^ExecStartPre=\/usr\/bin\/openshell-gateway config preflight$/ { preflight = migrated } \
/^ExecStartPre=\/usr\/bin\/openshell-gateway generate-certs/ { exit !(preflight && migrated) }' \
"$spec"; then
echo "FAIL: RPM migration and preflight must precede certificate generation" >&2
exit 1
fi
# Build a throwaway package when Debian tooling is available to prove the
# staged unit comes from deploy/deb/. Other hosts retain the static source-to-
# destination assertion above; the real Debian upgrade lane remains required.
if command -v dpkg-deb >/dev/null 2>&1; then
package_work=$(mktemp -d "${TMPDIR:-/tmp}/openshell-package-assets.XXXXXX")
trap 'rm -rf "$package_work"' EXIT
mkdir -p "$package_work/bin" "$package_work/output"
for binary in openshell openshell-gateway openshell-prover openshell-driver-vm; do
printf '#!/bin/sh\nexit 0\n' >"$package_work/bin/$binary"
chmod +x "$package_work/bin/$binary"
done
OPENSHELL_CLI_BINARY="$package_work/bin/openshell" \
OPENSHELL_GATEWAY_BINARY="$package_work/bin/openshell-gateway" \
OPENSHELL_PROVER_BINARY="$package_work/bin/openshell-prover" \
OPENSHELL_DRIVER_VM_BINARY="$package_work/bin/openshell-driver-vm" \
OPENSHELL_DEB_VERSION=0.0.0 \
OPENSHELL_DEB_ARCH=amd64 \
OPENSHELL_OUTPUT_DIR="$package_work/output" \
"$package_deb" >/dev/null
dpkg-deb --fsys-tarfile "$package_work/output/openshell_0.0.0_amd64.deb" \
| tar -xOf - ./usr/lib/systemd/user/openshell-gateway.service \
>"$package_work/staged.service"
if ! cmp -s "$service" "$package_work/staged.service"; then
echo "FAIL: package-deb did not stage the current Debian service" >&2
exit 1
fi
if ! dpkg-deb --fsys-tarfile "$package_work/output/openshell_0.0.0_amd64.deb" \
| tar -tf - | grep -x './usr/bin/openshell-prover' >/dev/null; then
echo "FAIL: package-deb did not stage openshell-prover" >&2
exit 1
fi
else
echo "SKIP: dpkg-deb unavailable; Debian artifact staging requires its assigned lane"
fi
echo "packaging asset tests passed"