From d78c8cb8d82dee8e98c837e5bc5012012412c7d9 Mon Sep 17 00:00:00 2001 From: mrhid6 Date: Fri, 17 Jul 2026 15:38:00 +0100 Subject: [PATCH] fix: Fixed agent windows version --- installer/setup.ps1 | 47 ++++++++++++++++++++++++++++++------- installer/vantage-agent.wxs | 3 ++- internal/sync/sync.go | 47 +++++++++++++++++++++++++++++++++++++ 3 files changed, 88 insertions(+), 9 deletions(-) diff --git a/installer/setup.ps1 b/installer/setup.ps1 index caf7fc4..d32cb6f 100644 --- a/installer/setup.ps1 +++ b/installer/setup.ps1 @@ -66,8 +66,17 @@ try { $cfgDir = Join-Path $env:ProgramData "vantage" New-Item -ItemType Directory -Force -Path $cfgDir | Out-Null + $cfgPath = Join-Path $cfgDir "config.yaml" - $cfg = @" + # Preserve existing config on upgrade. A MajorUpgrade re-runs this script with + # no SERVERID/TOKEN, so blindly rewriting would wipe the agent_token the agent + # persisted after Register(). Only (re)write when a ServerId is supplied + # (fresh install / explicit re-register). + if ((Test-Path $cfgPath) -and (-not $ServerId)) { + Write-Log "config.yaml exists and no ServerId supplied - preserving existing config (upgrade)" + } + else { + $cfg = @" server_url: "$ServerUrl" server_id: "$ServerId" pre_reg_token: "$Token" @@ -75,12 +84,12 @@ agent_token: "" poll_interval: 30s tls: true "@ - $cfgPath = Join-Path $cfgDir "config.yaml" - Set-Content -Path $cfgPath -Value $cfg -Encoding utf8 - Write-Log "wrote $cfgPath" + Set-Content -Path $cfgPath -Value $cfg -Encoding utf8 + Write-Log "wrote $cfgPath" - # Lock down ACL: SYSTEM + Administrators only - Invoke-Native -File "icacls" -Arguments @($cfgPath, "/inheritance:r", "/grant:r", "SYSTEM:F", "Administrators:F") + # Lock down ACL: SYSTEM + Administrators only + Invoke-Native -File "icacls" -Arguments @($cfgPath, "/inheritance:r", "/grant:r", "SYSTEM:F", "Administrators:F") + } if (-not $InstallDir) { $InstallDir = $PSScriptRoot } $nssm = Join-Path $InstallDir "nssm.exe" @@ -89,9 +98,31 @@ tls: true if (-not (Test-Path $nssm)) { throw "nssm.exe not found at $nssm" } if (-not (Test-Path $exe)) { throw "vantage-agent.exe not found at $exe" } - Invoke-Native -File $nssm -Arguments @("install", "VantageAgent", $exe) + # Install only if the service isn't already registered (an upgrade may leave + # it in place). "nssm install" on an existing service errors otherwise. + $exists = Get-Service -Name "VantageAgent" -ErrorAction SilentlyContinue + if (-not $exists) { + Invoke-Native -File $nssm -Arguments @("install", "VantageAgent", $exe) + } else { + Write-Log "VantageAgent service already exists - updating binary path" + Invoke-Native -File $nssm -Arguments @("set", "VantageAgent", "Application", $exe) + } Invoke-Native -File $nssm -Arguments @("set", "VantageAgent", "Start", "SERVICE_AUTO_START") - Invoke-Native -File $nssm -Arguments @("start", "VantageAgent") + + # Redirect service stdout/stderr to log files (nssm discards them otherwise) + # with online rotation at ~1MB. + $outLog = Join-Path $logDir "agent-stdout.log" + $errLog = Join-Path $logDir "agent-stderr.log" + Invoke-Native -File $nssm -Arguments @("set", "VantageAgent", "AppStdout", $outLog) + Invoke-Native -File $nssm -Arguments @("set", "VantageAgent", "AppStderr", $errLog) + Invoke-Native -File $nssm -Arguments @("set", "VantageAgent", "AppStdoutCreationDisposition", "4") + Invoke-Native -File $nssm -Arguments @("set", "VantageAgent", "AppStderrCreationDisposition", "4") + Invoke-Native -File $nssm -Arguments @("set", "VantageAgent", "AppRotateFiles", "1") + Invoke-Native -File $nssm -Arguments @("set", "VantageAgent", "AppRotateOnline", "1") + Invoke-Native -File $nssm -Arguments @("set", "VantageAgent", "AppRotateBytes", "1048576") + + # restart (not just start) so an upgrade picks up the new binary + Invoke-NativeSoft -File $nssm -Arguments @("restart", "VantageAgent") Write-Log "=== setup ok ===" exit 0 diff --git a/installer/vantage-agent.wxs b/installer/vantage-agent.wxs index e4a53a9..2f81fbe 100644 --- a/installer/vantage-agent.wxs +++ b/installer/vantage-agent.wxs @@ -1,7 +1,8 @@ + diff --git a/internal/sync/sync.go b/internal/sync/sync.go index 07ab92b..b6a8cc8 100644 --- a/internal/sync/sync.go +++ b/internal/sync/sync.go @@ -11,6 +11,7 @@ import ( "net/http" "os" "os/exec" + "path/filepath" "runtime" "strings" "time" @@ -265,6 +266,11 @@ func handleDeleteKey(cmd *pb.ServerCommand) { } func handleUpdateAgent(cmd *pb.ServerCommand) { + if runtime.GOOS == "windows" { + handleUpdateAgentWindows(cmd) + return + } + u := cmd.UpdateAgent arch := runtime.GOARCH // "amd64" or "arm64" tag := "agent%2Fv" + u.Version @@ -305,6 +311,47 @@ func handleUpdateAgent(cmd *pb.ServerCommand) { exec.Command("systemctl", "restart", "vantage-agent").Run() } +// handleUpdateAgentWindows downloads the latest MSI and launches msiexec to +// perform a MajorUpgrade. msiexec is started DETACHED (via "cmd /c start") so +// that when the upgrade stops the VantageAgent service, nssm's process-tree +// kill of this agent does not also kill the installer mid-flight. Config +// (server_id, agent_token) is preserved by setup.ps1 on upgrade. +func handleUpdateAgentWindows(cmd *pb.ServerCommand) { + u := cmd.UpdateAgent + tag := "agent%2Fv" + u.Version + msiURL := fmt.Sprintf("%s/mrhid6/vantage/releases/download/%s/vantage-agent.msi", u.GiteaBaseURL, tag) + checksumURL := fmt.Sprintf("%s/mrhid6/vantage/releases/download/%s/checksums-msi.txt", u.GiteaBaseURL, tag) + + log.Printf("updating agent to v%s from %s (cmd=%s)", u.Version, u.GiteaBaseURL, cmd.CommandId) + + msiPath := filepath.Join(os.TempDir(), "vantage-agent-update.msi") + if err := downloadFile(msiURL, msiPath); err != nil { + log.Printf("update download failed (cmd=%s): %v", cmd.CommandId, err) + return + } + + checksumData, err := httpGetBytes(checksumURL) + if err != nil { + log.Printf("update checksum fetch failed (cmd=%s): %v", cmd.CommandId, err) + return + } + if err := verifyChecksum(msiPath, "vantage-agent.msi", checksumData); err != nil { + log.Printf("update checksum mismatch (cmd=%s): %v", cmd.CommandId, err) + os.Remove(msiPath) + return + } + + logPath := filepath.Join(os.TempDir(), "vantage-agent-msi.log") + log.Printf("launching msiexec for upgrade to v%s (cmd=%s)", u.Version, cmd.CommandId) + // "start" detaches msiexec from this process tree so the service stop + // during the upgrade does not terminate the installer. + up := exec.Command("cmd", "/c", "start", "", "/wait", "msiexec", "/i", msiPath, "/qn", "/norestart", "/l*v", logPath) + if err := up.Start(); err != nil { + log.Printf("failed to launch msiexec (cmd=%s): %v", cmd.CommandId, err) + return + } +} + func downloadFile(url, dest string) error { resp, err := http.Get(url) //nolint:gosec if err != nil {