@@ -21,6 +21,29 @@ const (
2121 MacosCollectorVersion = "11.2.3"
2222)
2323
24+ // getUpdaterVersion reads the desired updater version from version.json
25+ // (the updater_version field). Falls back to UpdaterVersion if the
26+ // file is missing, unreadable, or the field is empty.
27+ //
28+ // The source of truth for this value is version.json shipped by the server,
29+ // which the updater promotes on each successful agent update.
30+ func getUpdaterVersion () string {
31+ var v struct {
32+ UpdaterVersion string `json:"updater_version"`
33+ }
34+ versionPath := filepath .Join (fs .GetExecutablePath (), "version.json" )
35+ if ! fs .Exists (versionPath ) {
36+ return UpdaterVersion
37+ }
38+ if err := fs .ReadJSON (versionPath , & v ); err != nil {
39+ return UpdaterVersion
40+ }
41+ if v .UpdaterVersion == "" {
42+ return UpdaterVersion
43+ }
44+ return v .UpdaterVersion
45+ }
46+
2447// UpdaterFile returns the updater binary name with OS and architecture suffix.
2548// Format: utmstack_updater_service_<os>_<arch>[.exe]
2649// Examples:
@@ -37,16 +60,17 @@ func UpdaterFile(suffix string) string {
3760
3861// Dependency represents a dependency that the agent needs.
3962type Dependency struct {
40- Name string // Unique identifier
41- Version string // Current version in this agent build
42- BinaryPath string // Path to check if already exists
43- DownloadURL func (server string ) string // URL template to download from
44- DownloadName string // Filename to save as (if different from BinaryPath basename)
45- Critical bool // If true, failure blocks agent startup
46- PostDownload func () error // Run after download (e.g., unzip). Can be nil.
47- Configure func () error // Run on first install (can be nil)
48- Update func () error // Run on version change (can be nil, uses Configure)
49- Uninstall func () error // Run when dependency is removed (can be nil)
63+ Name string // Unique identifier
64+ Version string // Current version in this agent build
65+ BinaryPath string // Path to check if already exists
66+ DownloadURL func (server string ) string // URL template to download from
67+ DownloadName string // Filename to save as (if different from BinaryPath basename)
68+ Critical bool // If true, failure blocks agent startup
69+ PreDownload func () (cleanup func (), err error ) // Called before download, returns cleanup for rollback
70+ PostDownload func () error // Run after download (e.g., unzip). Can be nil.
71+ Configure func () error // Run on first install (can be nil)
72+ Update func () error // Run on version change (can be nil, uses Configure)
73+ Uninstall func () error // Run when dependency is removed (can be nil)
5074}
5175
5276// Exists checks if the dependency binary exists on disk.
@@ -188,13 +212,34 @@ func Reconcile(server string, skipCertValidation bool) error {
188212 } else if inst .Version != dep .Version {
189213 // VERSION CHANGED: Download (if needed) and update
190214 utils .Logger .Info ("Updating dependency: %s (%s -> %s)" , dep .Name , inst .Version , dep .Version )
215+
216+ // Call PreDownload hook if defined
217+ var cleanup func ()
218+ if dep .PreDownload != nil {
219+ var err error
220+ cleanup , err = dep .PreDownload ()
221+ if err != nil {
222+ errMsg := fmt .Errorf ("failed to run PreDownload for %s: %v" , dep .Name , err )
223+ utils .Logger .ErrorF ("%v" , errMsg )
224+ if dep .Critical {
225+ criticalErrors = append (criticalErrors , errMsg )
226+ }
227+ continue
228+ }
229+ }
230+
191231 if dep .DownloadURL != nil {
192232 if err := downloadDependency (dep , server , skipCertValidation ); err != nil {
193233 errMsg := fmt .Errorf ("failed to download dependency update %s: %v" , dep .Name , err )
194234 utils .Logger .ErrorF ("%v" , errMsg )
195235 if dep .Critical {
196236 criticalErrors = append (criticalErrors , errMsg )
197237 }
238+ // Rollback: call cleanup if PreDownload succeeded
239+ if cleanup != nil {
240+ utils .Logger .Info ("Rolling back PreDownload changes for %s" , dep .Name )
241+ cleanup ()
242+ }
198243 continue
199244 }
200245 }
@@ -210,6 +255,11 @@ func Reconcile(server string, skipCertValidation bool) error {
210255 if dep .Critical {
211256 criticalErrors = append (criticalErrors , errMsg )
212257 }
258+ // Rollback: call cleanup if PreDownload succeeded
259+ if cleanup != nil {
260+ utils .Logger .Info ("Rolling back PreDownload changes for %s" , dep .Name )
261+ cleanup ()
262+ }
213263 continue
214264 }
215265 }
0 commit comments