diff --git a/.github/scripts/smoke-test-deb.sh b/.github/scripts/smoke-test-deb.sh index 24a4e1a08..2bb84a55c 100644 --- a/.github/scripts/smoke-test-deb.sh +++ b/.github/scripts/smoke-test-deb.sh @@ -167,6 +167,9 @@ check_config_init info "Checking systemd unit file…" check_unit_file "fail" +info "Checking service file has exactly one ExecStart directive…" +check_single_execstart + # ── Service startup (best-effort) ───────────────────────────────────────────── check_service_startup diff --git a/.github/scripts/smoke-test-lib.sh b/.github/scripts/smoke-test-lib.sh index d0f19f4a4..585db78ed 100644 --- a/.github/scripts/smoke-test-lib.sh +++ b/.github/scripts/smoke-test-lib.sh @@ -140,6 +140,27 @@ check_unit_file() { fi } +check_single_execstart() { + local unit_file="" count + for path in "${UNIT_FILE_PATHS[@]}"; do + if [ -f "$path" ]; then + unit_file="$path" + break + fi + done + if [ -z "$unit_file" ]; then + warn "Skipping ExecStart check: no unit file found (check_unit_file already reported this)." + return + fi + # Match only non-empty ExecStart= lines; bare 'ExecStart=' is a reset directive. + count=$(grep -c '^ExecStart=[^[:space:]]' "$unit_file" 2>/dev/null || true) + if [ "$count" -eq 1 ]; then + pass "Service file has exactly one ExecStart directive" + else + fail "Service file has $count ExecStart directives (expected exactly 1)" + fi +} + check_service_startup() { info "[Best-effort] Checking service startup…" warn "systemd service startup testing is best-effort in containers." diff --git a/.github/scripts/smoke-test-rpm.sh b/.github/scripts/smoke-test-rpm.sh index c5b89155c..2fce4b71f 100644 --- a/.github/scripts/smoke-test-rpm.sh +++ b/.github/scripts/smoke-test-rpm.sh @@ -6,7 +6,7 @@ # - Package installs correctly via dnf # - Expected files and directories are present # - Binary is functional (--help, --config-init-only) -# - Service registration creates the expected systemd unit file +# - systemd unit file is installed (part of the .rpm package) # - Default configuration file is generated # # Environment variables (required): @@ -19,18 +19,8 @@ # script (after-install) gates ALL service-related actions on the # presence of /run/systemd/system. This means: # - Config initialization is skipped. -# - Service registration is skipped (no unit file is created). # - Service enable/start is skipped. -# This script compensates by running --config-init-only and -# service register manually. -# -# DIFFERENCE FROM DEB: -# The .deb package includes the systemd unit file directly (installed -# by dpkg via dh_installsystemd). The .rpm package does NOT bundle the -# unit file; instead, the postinst calls `devolutions-gateway service -# register` to create it at install time. This means that in a container -# without systemd, the unit file will only exist if we manually run -# `service register`. +# This script compensates by running --config-init-only manually. # ────────────────────────────────────────────────────────────────────────────── set -euo pipefail @@ -50,10 +40,8 @@ WEBAPP_DIR=/usr/share/devolutions-gateway/webapp CONFIG_DIR=/etc/devolutions-gateway CONFIG_FILE=$CONFIG_DIR/gateway.json -# The .rpm package does NOT bundle the unit file; it is created by -# `devolutions-gateway service register` at install time (or manually below). +# The .rpm package bundles the unit file directly (installed by fpm/rpm). UNIT_FILE_PATHS=( - /etc/systemd/system/devolutions-gateway.service /usr/lib/systemd/system/devolutions-gateway.service /lib/systemd/system/devolutions-gateway.service ) @@ -171,27 +159,18 @@ check_binary_help info "Checking config initialization…" check_config_init -# ── Service registration ────────────────────────────────────────────────────── -# The RPM does NOT bundle the systemd unit file. The postinst calls -# `devolutions-gateway service register` to create it. In containers -# without systemd, the postinst skips this, so we try it manually. - -info "Checking service registration…" -info "Running service registration manually…" -SERVICE_REG_OUTPUT=$("$BINARY" service register 2>&1) && SERVICE_REG_RC=$? || SERVICE_REG_RC=$? -if [ "$SERVICE_REG_RC" -eq 0 ]; then - pass "Service registration command succeeded" -else - warn "Service registration returned exit code $SERVICE_REG_RC (may require systemd)." - info "Output: $SERVICE_REG_OUTPUT" -fi - # ── systemd unit file ───────────────────────────────────────────────────────── -# Unit file is only present if service register succeeded above; -# absence is a warning rather than a hard failure. +# The .rpm package bundles the unit file directly, so it must be present +# after installation regardless of whether systemd is running. info "Checking systemd unit file…" -check_unit_file "warn" +check_unit_file "fail" + +# ── Single ExecStart directive ──────────────────────────────────────────────── +# Regression guard: two ExecStart= lines make systemd refuse to start the service. + +info "Checking service file has exactly one ExecStart directive…" +check_single_execstart # ── Service startup (best-effort) ───────────────────────────────────────────── diff --git a/ci/package-gateway-rpm.ps1 b/ci/package-gateway-rpm.ps1 index 1dbfc4ecd..f233f60df 100644 --- a/ci/package-gateway-rpm.ps1 +++ b/ci/package-gateway-rpm.ps1 @@ -69,12 +69,14 @@ function New-GatewayRpm() { '--url', 'https://devolutions.net' '--license', 'Apache-2.0 OR MIT' '--rpm-attr', '755,root,root:/usr/bin/devolutions-gateway' + '--rpm-attr', '644,root,root:/usr/lib/systemd/system/devolutions-gateway.service' '--rpm-changelog', $pkgChangelog '--after-install', 'package/Linux/gateway/rpm/postinst' '--before-remove', 'package/Linux/gateway/rpm/prerm' '--after-remove', 'package/Linux/gateway/rpm/postrm' '--' "$Bin=/usr/bin/devolutions-gateway" + 'package/Linux/gateway/rpm/service=/usr/lib/systemd/system/devolutions-gateway.service' "$generatedUpstreamChangelog=/usr/share/doc/devolutions-gateway/ChangeLog" "$pkgDir/copyright=/usr/share/doc/devolutions-gateway/copyright" "$LibxmfFile=/usr/lib/devolutions-gateway/libxmf.so" diff --git a/ci/tlk.ps1 b/ci/tlk.ps1 index cf0fc0aef..effead9db 100755 --- a/ci/tlk.ps1 +++ b/ci/tlk.ps1 @@ -867,7 +867,7 @@ class TlkRecipe $s = New-Changelog -Format 'RpmPackaging' -InputFile $UpstreamChangelogFile -Packager $Packager -Email $Email Set-Content -Path $RpmPackagingChangelogFile -Value $s - $FpmArgs = @( + $FpmOptions = @( '--force' '--verbose' '-s', 'dir' @@ -882,24 +882,28 @@ class TlkRecipe '--license', 'Apache-2.0 OR MIT' '--rpm-attr', "755,root,root:/usr/bin/$PkgName" '--rpm-changelog', $RpmPackagingChangelogFile - '--after-install', "$InputPackagePath/$($this.Product)/rpm/postinst" + '--after-install', "$InputPackagePath/$($this.Product)/rpm/postinst" '--before-remove', "$InputPackagePath/$($this.Product)/rpm/prerm" '--after-remove', "$InputPackagePath/$($this.Product)/rpm/postrm" - '--' + ) + + $FpmFiles = @( "$Executable=/usr/bin/$PkgName" "$RpmUpstreamChangelogFile=/usr/share/doc/$PkgName/ChangeLog" "$CopyrightFile=/usr/share/doc/$PkgName/copyright" ) if ($this.Product -eq "gateway") { - $FpmArgs += @( + $FpmOptions += '--rpm-attr', '644,root,root:/usr/lib/systemd/system/devolutions-gateway.service' + $FpmFiles += @( + "$InputPackagePath/gateway/rpm/service=/usr/lib/systemd/system/devolutions-gateway.service", "$DGatewayWebClient=/usr/share/devolutions-gateway/webapp/client", "$DGatewayWebPlayer=/usr/share/devolutions-gateway/webapp/player", "$DGatewayLibXmf=/usr/lib/devolutions-gateway/libxmf.so" ) } - & 'fpm' @FpmArgs | Out-Host + & 'fpm' @FpmOptions '--' @FpmFiles | Out-Host if (Test-Path Env:TARGET_OUTPUT_PATH) { $TargetOutputPath = $Env:TARGET_OUTPUT_PATH diff --git a/devolutions-gateway/src/main.rs b/devolutions-gateway/src/main.rs index 8fda2c75e..05b9e9b8f 100644 --- a/devolutions-gateway/src/main.rs +++ b/devolutions-gateway/src/main.rs @@ -107,6 +107,7 @@ fn run() -> anyhow::Result<()> { After=network-online.target [Service] + ExecStart= ExecStart=/usr/bin/devolutions-gateway --service Restart=on-failure diff --git a/package/Linux/gateway/debian/service b/package/Linux/gateway/debian/service index 86ec75014..225b847b7 100644 --- a/package/Linux/gateway/debian/service +++ b/package/Linux/gateway/debian/service @@ -1,4 +1,5 @@ [Unit] +Description=Devolutions Gateway After=network-online.target [Service] @@ -6,4 +7,4 @@ ExecStart=/usr/bin/devolutions-gateway --service Restart=on-failure [Install] -WantedBy=multi-user.target \ No newline at end of file +WantedBy=multi-user.target diff --git a/package/Linux/gateway/rpm/postinst b/package/Linux/gateway/rpm/postinst index f1655efd8..a603368ec 100644 --- a/package/Linux/gateway/rpm/postinst +++ b/package/Linux/gateway/rpm/postinst @@ -6,9 +6,8 @@ if [ ! -d /etc/devolutions-gateway ]; then fi if [ -d /run/systemd/system ]; then - /usr/bin/devolutions-gateway service register >/dev/null systemctl daemon-reload /usr/bin/devolutions-gateway --config-init-only >/dev/null - systemctl enable --now devolutions-gateway >/dev/null 2>&1 - systemctl restart devolutions-gateway >/dev/null 2>&1 + systemctl enable --now devolutions-gateway >/dev/null 2>&1 || true + systemctl restart devolutions-gateway >/dev/null 2>&1 || true fi diff --git a/package/Linux/gateway/rpm/postrm b/package/Linux/gateway/rpm/postrm index 53708f9f5..057eb06ca 100644 --- a/package/Linux/gateway/rpm/postrm +++ b/package/Linux/gateway/rpm/postrm @@ -4,8 +4,12 @@ set -e action="$1" -# Only do complete clean-up on purge. -if [ "$action" != "purge" ] ; then +if [ -d /run/systemd/system ]; then + systemctl daemon-reload >/dev/null 2>&1 || true +fi + +# Only do complete clean-up on final erase ($1 == 0); upgrades pass $1 >= 1. +if [ "$action" -ne 0 ] ; then exit 0 fi diff --git a/package/Linux/gateway/rpm/prerm b/package/Linux/gateway/rpm/prerm index 47e982c6a..7c995b036 100644 --- a/package/Linux/gateway/rpm/prerm +++ b/package/Linux/gateway/rpm/prerm @@ -14,7 +14,6 @@ if [ "$action" = "upgrade" ] ; then fi if [ -d /run/systemd/system ]; then - systemctl stop devolutions-gateway >/dev/null 2>&1 - /usr/bin/devolutions-gateway service unregister >/dev/null - systemctl daemon-reload -fi \ No newline at end of file + systemctl stop devolutions-gateway >/dev/null 2>&1 || true + systemctl disable devolutions-gateway >/dev/null 2>&1 || true +fi diff --git a/package/Linux/gateway/rpm/service b/package/Linux/gateway/rpm/service new file mode 100644 index 000000000..defef6792 --- /dev/null +++ b/package/Linux/gateway/rpm/service @@ -0,0 +1,10 @@ +[Unit] +Description=Devolutions Gateway +After=network-online.target + +[Service] +ExecStart=/usr/bin/devolutions-gateway --service +Restart=on-failure + +[Install] +WantedBy=multi-user.target