From 813d96709e6b20c5677fdecd2a84034c88ee78b0 Mon Sep 17 00:00:00 2001 From: Florian Schmidt Date: Sat, 18 Jul 2026 09:48:02 +0200 Subject: [PATCH] Deploy: make the LXC updater a real file so existing containers can bootstrap it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The updater was emitted from a heredoc inside the installer, so a container provisioned before it existed had no way to obtain /usr/bin/update — 'update' just reported command not found, with no path forward short of reinstalling. Ship it as deploy/install/metervault-update.sh and have the installer install(1) it from the checkout it just built. An already-provisioned container can now bootstrap from its own source tree after a git pull, and the updater refreshes itself (atomic rename, since bash reads a running script lazily) so the same stranding does not recur. Uses echo rather than msg_warn for the missing-file case: msg_warn is not otherwise relied on in this script, and an undefined function under the framework ERR trap would abort an otherwise-successful install. Claude-Session: https://claude.ai/code/session_01V6joyergfvVLFEizH1hJLd --- deploy/install/metervault-install.sh | 30 ++++++---------- deploy/install/metervault-update.sh | 52 ++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 20 deletions(-) create mode 100644 deploy/install/metervault-update.sh diff --git a/deploy/install/metervault-install.sh b/deploy/install/metervault-install.sh index 0e3f2c3..9aa5fb1 100755 --- a/deploy/install/metervault-install.sh +++ b/deploy/install/metervault-install.sh @@ -224,27 +224,17 @@ WantedBy=multi-user.target EOF } -# A self-contained in-container updater: pull the latest source and rebuild, no host round-trip and -# no re-fetch of the community-scripts framework (safer + simpler than re-running the ct script). +# Install the in-container updater from the checkout we just built, rather than emitting it from a +# heredoc here. Keeping it a real file in the repo means an already-provisioned container can +# bootstrap /usr/bin/update itself after a git pull, instead of being stranded on whatever the +# installer wrote the day it ran. write_update_command() { - cat <<'EOF' >/usr/bin/update -#!/usr/bin/env bash -set -euo pipefail -if ! systemd-detect-virt --container --quiet 2>/dev/null; then - echo "Run 'update' inside the MeterVault LXC, not on the Proxmox host." >&2 - exit 1 -fi -export DOTNET_CLI_TELEMETRY_OPTOUT=1 DOTNET_NOLOGO=1 -echo "Stopping metervault…"; systemctl stop metervault || true -echo "Pulling latest source…" -git -C /opt/metervault-src fetch --depth 1 origin master -git -C /opt/metervault-src reset --hard origin/master -echo "Rebuilding (dotnet publish)…" -dotnet publish /opt/metervault-src/src/App/MeterVault.App.csproj -c Release -o /opt/metervault /p:UseAppHost=false -echo "Starting metervault…"; systemctl start metervault -echo "MeterVault updated." -EOF - chmod +x /usr/bin/update + local src="${SOURCE_DIR}/deploy/install/metervault-update.sh" + if [[ ! -f "${src}" ]]; then + echo "Updater script not found at ${src} — skipping 'update' command." >&2 + return 0 + fi + install -m 0755 "${src}" /usr/bin/update } main() { diff --git a/deploy/install/metervault-update.sh b/deploy/install/metervault-update.sh new file mode 100644 index 0000000..683a992 --- /dev/null +++ b/deploy/install/metervault-update.sh @@ -0,0 +1,52 @@ +#!/usr/bin/env bash +# MeterVault in-container updater — installed to /usr/bin/update by metervault-install.sh. +# Pulls the latest source and rebuilds in place: no host round-trip and no re-fetch of the +# community-scripts framework (safer + simpler than re-running the ct script). +# +# Kept as a standalone file rather than a heredoc in the installer so an already-provisioned +# container can bootstrap it straight from its own checkout: +# git -C /opt/metervault-src fetch --depth 1 origin master +# git -C /opt/metervault-src reset --hard origin/master +# install -m 0755 /opt/metervault-src/deploy/install/metervault-update.sh /usr/bin/update +set -euo pipefail + +: "${SOURCE_DIR:=/opt/metervault-src}" +: "${INSTALL_DIR:=/opt/metervault}" +: "${METERVAULT_BRANCH:=master}" + +# SAFETY GUARD — this must run INSIDE the MeterVault LXC, never on the Proxmox host. +if ! systemd-detect-virt --container --quiet 2>/dev/null; then + echo "Run 'update' inside the MeterVault LXC, not on the Proxmox host." >&2 + exit 1 +fi + +if [[ ! -d "${SOURCE_DIR}/.git" ]]; then + echo "No source checkout at ${SOURCE_DIR} — cannot rebuild. Reinstall to restore it." >&2 + exit 1 +fi + +export DOTNET_CLI_TELEMETRY_OPTOUT=1 DOTNET_NOLOGO=1 + +echo "Stopping metervault…" +systemctl stop metervault || true + +echo "Pulling latest source…" +git -C "${SOURCE_DIR}" fetch --depth 1 origin "${METERVAULT_BRANCH}" +git -C "${SOURCE_DIR}" reset --hard "origin/${METERVAULT_BRANCH}" + +echo "Rebuilding (dotnet publish — this can take a few minutes)…" +dotnet publish "${SOURCE_DIR}/src/App/MeterVault.App.csproj" -c Release -o "${INSTALL_DIR}" /p:UseAppHost=false + +echo "Starting metervault…" +systemctl start metervault + +# Refresh this script from the checkout we just pulled, so a change to the updater itself lands +# without stranding the container again. Atomic rename, never an in-place write: bash reads the +# running script lazily, so truncating it mid-run would corrupt the remainder of this execution. +self="${SOURCE_DIR}/deploy/install/metervault-update.sh" +if [[ -f "${self}" ]] && ! cmp -s "${self}" /usr/bin/update; then + install -m 0755 "${self}" /usr/bin/.update.new && mv /usr/bin/.update.new /usr/bin/update + echo "Updater itself refreshed — the new version applies from the next run." +fi + +echo "MeterVault updated."