Add advantech router app updates

This commit is contained in:
Owen
2026-05-25 17:01:48 -07:00
parent 535fd717be
commit ec89eb7d0f
3 changed files with 61 additions and 4 deletions

View File

@@ -29,7 +29,7 @@ COPY entrypoint.sh /
# Marks this as an official Fossorial container image.
# Auto-update is disabled in official images — update by pulling a new image tag.
ENV NEWT_OFFICIAL_CONTAINER=true
ENV NEWT_SYSTEM_SUBSTRATE="CONTAINER"
# Admin/metrics endpoint (Prometheus scrape)
EXPOSE 2112

48
updates/advantech.go Normal file
View File

@@ -0,0 +1,48 @@
//go:build !windows
package updates
import (
"fmt"
"os"
"path/filepath"
"github.com/fosrl/newt/logger"
)
const advantechVersionFile = "/opt/newt/etc/version"
// postUpdateAdvantech performs Advantech Router App-specific post-update steps:
// - Writes the new version string to /opt/newt/etc/version so that the
// router firmware's package management reflects the installed version.
// - Updates the PID file at pidFile (if non-empty) with the current process
// PID, in case the re-exec lands with a new PID on platforms where
// syscall.Exec behaviour differs.
func postUpdateAdvantech(newVersion, pidFile string) error {
// --- Write version file ---
versionDir := filepath.Dir(advantechVersionFile)
if err := os.MkdirAll(versionDir, 0755); err != nil {
return fmt.Errorf("advantech: failed to create version directory %s: %w", versionDir, err)
}
if err := os.WriteFile(advantechVersionFile, []byte(newVersion+"\n"), 0644); err != nil {
return fmt.Errorf("advantech: failed to write version file %s: %w", advantechVersionFile, err)
}
logger.Debug("postUpdateAdvantech: wrote version %s to %s", newVersion, advantechVersionFile)
// --- Update PID file ---
// syscall.Exec replaces the process image in-place so the PID is preserved.
// We update the PID file here anyway so that any race between the old and
// new binary is covered (e.g. on platforms that fork before exec).
if pidFile != "" {
pid := fmt.Sprintf("%d\n", os.Getpid())
if err := os.WriteFile(pidFile, []byte(pid), 0644); err != nil {
// Non-fatal: log and continue so the update still proceeds.
logger.Debug("postUpdateAdvantech: warning: failed to update PID file %s: %v", pidFile, err)
} else {
logger.Debug("postUpdateAdvantech: updated PID file %s with PID %d", pidFile, os.Getpid())
}
}
return nil
}

View File

@@ -52,10 +52,10 @@ type versionResponse struct {
// isOfficialContainer returns true when the process is running inside an
// official Fossorial-built container image. The image sets
// NEWT_OFFICIAL_CONTAINER=true at build time; users running newt in their own
// NEWT_SYSTEM_SUBSTRATE="CONTAINER" at build time; users running newt in their own
// containers (or bare-metal) will not have this variable set.
func isOfficialContainer() bool {
return os.Getenv("NEWT_OFFICIAL_CONTAINER") == "true"
return os.Getenv("NEWT_SYSTEM_SUBSTRATE") == "CONTAINER"
}
// platform returns the OS+arch string used in the newt release binary names,
@@ -109,7 +109,7 @@ func verifySHA256(path, expected string) error {
// the function does not return the process is replaced by the new binary via
// syscall.Exec.
func CheckAndSelfUpdate(cfg SelfUpdateConfig) error {
logger.Debug("++++++++++++++++++++++++++++++++++++++++++++checkAndSelfUpdate: starting update check (currentVersion=%s)", cfg.CurrentVersion)
logger.Debug("checkAndSelfUpdate: starting update check (currentVersion=%s)", cfg.CurrentVersion)
if isOfficialContainer() {
logger.Debug("checkAndSelfUpdate: running inside official container, skipping auto-update")
@@ -280,6 +280,15 @@ func CheckAndSelfUpdate(cfg SelfUpdateConfig) error {
return fmt.Errorf("failed to replace binary (you may need to run as root): %w", err)
}
systemSubstrate := os.Getenv("NEWT_SYSTEM_SUBSTRATE")
logger.Debug("checkAndSelfUpdate: system substrate: %s", systemSubstrate)
if systemSubstrate == "ADVANTECH_ROUTER_APP" {
pidFile := os.Getenv("NEWT_PID_FILE")
if err := postUpdateAdvantech(verResp.Data.LatestVersion, pidFile); err != nil {
logger.Debug("checkAndSelfUpdate: advantech post-update steps failed: %v", err)
}
}
// --- Step 4: Re-exec ---
logger.Debug("checkAndSelfUpdate: re-executing new binary")
return reexec(exePath)