@@ -2,6 +2,7 @@ package commands
22
33import (
44 "context"
5+ "crypto/sha256"
56 "encoding/json"
67 "fmt"
78 "io"
@@ -28,6 +29,7 @@ type ServerVersionResponse struct {
2829 Size int64 `json:"size"`
2930 Hash string `json:"hash"`
3031 DownloadURL string `json:"downloadUrl"`
32+ BinaryData []byte `json:"-"` // Binary data (not serialized to JSON)
3133}
3234
3335type ServerVersionInfo struct {
@@ -81,11 +83,10 @@ func checkVersion() error {
8183 logger .Info ("Agent update available!" )
8284 fmt .Printf (" Current version: %s\n " , currentVersion )
8385 fmt .Printf (" Latest version: %s\n " , latestVersion )
84- fmt .Printf (" Last checked: %s\n " , versionInfo .LastChecked )
85-
8686 fmt .Printf ("\n To update, run: patchmon-agent update-agent\n " )
8787 } else {
8888 logger .WithField ("version" , currentVersion ).Info ("Agent is up to date" )
89+ fmt .Printf ("Agent is up to date (version %s)\n " , currentVersion )
8990 }
9091
9192 return nil
@@ -108,12 +109,12 @@ func updateAgent() error {
108109
109110 logger .WithField ("version" , binaryInfo .Version ).Info ("Found latest version" )
110111
111- logger .WithField ( "url" , binaryInfo . DownloadURL ). Info ("Downloading latest agent..." )
112+ logger .Info ("Using downloaded agent binary ..." )
112113
113- // Download new version
114- newAgentData , err := downloadBinaryFromServer ( binaryInfo .DownloadURL )
115- if err != nil {
116- return fmt .Errorf ("failed to download new agent: %w" , err )
114+ // Use the binary data directly from the server response
115+ newAgentData := binaryInfo .BinaryData
116+ if len ( newAgentData ) == 0 {
117+ return fmt .Errorf ("no binary data received from server" )
117118 }
118119
119120 // Create backup of current executable
@@ -148,6 +149,14 @@ func updateAgent() error {
148149
149150 logger .WithField ("version" , binaryInfo .Version ).Info ("Agent updated successfully" )
150151
152+ // Restart the systemd service to pick up the new binary
153+ logger .Info ("Restarting patchmon-agent service..." )
154+ if err := restartService (); err != nil {
155+ logger .WithError (err ).Warn ("Failed to restart service (this is not critical)" )
156+ } else {
157+ logger .Info ("Service restarted successfully" )
158+ }
159+
151160 // Send updated information to PatchMon
152161 logger .Info ("Sending updated information to PatchMon..." )
153162 if err := sendReport (); err != nil {
@@ -167,7 +176,15 @@ func getServerVersionInfo() (*ServerVersionInfo, error) {
167176 }
168177 cfg := cfgManager .GetConfig ()
169178
170- url := fmt .Sprintf ("%s/api/v1/agent/version" , cfg .PatchmonServer )
179+ // Load credentials for API authentication
180+ if err := cfgManager .LoadCredentials (); err != nil {
181+ return nil , fmt .Errorf ("failed to load credentials: %w" , err )
182+ }
183+ credentials := cfgManager .GetCredentials ()
184+
185+ architecture := getArchitecture ()
186+ currentVersion := strings .TrimPrefix (version .Version , "v" )
187+ url := fmt .Sprintf ("%s/api/v1/hosts/agent/version?arch=%s&type=go¤tVersion=%s" , cfg .PatchmonServer , architecture , currentVersion )
171188
172189 ctx , cancel := context .WithTimeout (context .Background (), serverTimeout )
173190 defer cancel ()
@@ -178,6 +195,8 @@ func getServerVersionInfo() (*ServerVersionInfo, error) {
178195 }
179196
180197 req .Header .Set ("User-Agent" , fmt .Sprintf ("patchmon-agent/%s" , version .Version ))
198+ req .Header .Set ("X-API-ID" , credentials .APIID )
199+ req .Header .Set ("X-API-KEY" , credentials .APIKey )
181200
182201 resp , err := http .DefaultClient .Do (req )
183202 if err != nil {
@@ -209,8 +228,14 @@ func getLatestBinaryFromServer() (*ServerVersionResponse, error) {
209228 }
210229 cfg := cfgManager .GetConfig ()
211230
231+ // Load credentials for API authentication
232+ if err := cfgManager .LoadCredentials (); err != nil {
233+ return nil , fmt .Errorf ("failed to load credentials: %w" , err )
234+ }
235+ credentials := cfgManager .GetCredentials ()
236+
212237 architecture := getArchitecture ()
213- url := fmt .Sprintf ("%s/api/v1/agent/latest/ %s" , cfg .PatchmonServer , architecture )
238+ url := fmt .Sprintf ("%s/api/v1/hosts/ agent/download?arch= %s" , cfg .PatchmonServer , architecture )
214239
215240 ctx , cancel := context .WithTimeout (context .Background (), serverTimeout )
216241 defer cancel ()
@@ -221,6 +246,8 @@ func getLatestBinaryFromServer() (*ServerVersionResponse, error) {
221246 }
222247
223248 req .Header .Set ("User-Agent" , fmt .Sprintf ("patchmon-agent/%s" , version .Version ))
249+ req .Header .Set ("X-API-ID" , credentials .APIID )
250+ req .Header .Set ("X-API-KEY" , credentials .APIKey )
224251
225252 resp , err := http .DefaultClient .Do (req )
226253 if err != nil {
@@ -236,51 +263,28 @@ func getLatestBinaryFromServer() (*ServerVersionResponse, error) {
236263 return nil , fmt .Errorf ("server returned status %d" , resp .StatusCode )
237264 }
238265
239- var binaryInfo ServerVersionResponse
240- if err := json .NewDecoder (resp .Body ).Decode (& binaryInfo ); err != nil {
241- return nil , fmt .Errorf ("failed to decode binary info: %w" , err )
242- }
243-
244- return & binaryInfo , nil
245- }
246-
247- // downloadBinaryFromServer downloads a binary from the PatchMon server
248- func downloadBinaryFromServer (url string ) ([]byte , error ) {
249- ctx , cancel := context .WithTimeout (context .Background (), 5 * time .Minute )
250- defer cancel ()
251-
252- req , err := http .NewRequestWithContext (ctx , "GET" , url , nil )
266+ // Read the binary data
267+ binaryData , err := io .ReadAll (resp .Body )
253268 if err != nil {
254- return nil , err
269+ return nil , fmt . Errorf ( "failed to read binary data: %w" , err )
255270 }
256271
257- req .Header .Set ("User-Agent" , fmt .Sprintf ("patchmon-agent/%s" , version .Version ))
258-
259- resp , err := http .DefaultClient .Do (req )
260- if err != nil {
261- return nil , err
262- }
263- defer func () {
264- if closeErr := resp .Body .Close (); closeErr != nil {
265- logger .WithError (closeErr ).Debug ("Failed to close response body" )
266- }
267- }()
268-
269- if resp .StatusCode != http .StatusOK {
270- return nil , fmt .Errorf ("download failed with status %d" , resp .StatusCode )
271- }
272-
273- data , err := io .ReadAll (resp .Body )
274- if err != nil {
275- return nil , fmt .Errorf ("failed to read response body: %w" , err )
276- }
277-
278- return data , nil
272+ // Calculate hash
273+ hash := fmt .Sprintf ("%x" , sha256 .Sum256 (binaryData ))
274+
275+ return & ServerVersionResponse {
276+ Version : version .Version , // We'll get the actual version from the server later
277+ Architecture : architecture ,
278+ Size : int64 (len (binaryData )),
279+ Hash : hash ,
280+ DownloadURL : url ,
281+ BinaryData : binaryData , // Store the binary data directly
282+ }, nil
279283}
280284
281285// getArchitecture returns the architecture string for the current platform
282286func getArchitecture () string {
283- return fmt . Sprintf ( "linux-%s" , runtime .GOARCH )
287+ return runtime .GOARCH
284288}
285289
286290// copyFile copies a file from src to dst
@@ -293,4 +297,19 @@ func copyFile(src, dst string) error {
293297 return os .WriteFile (dst , data , 0755 )
294298}
295299
300+ // restartService restarts the patchmon-agent systemd service
301+ func restartService () error {
302+ ctx , cancel := context .WithTimeout (context .Background (), 30 * time .Second )
303+ defer cancel ()
304+
305+ cmd := exec .CommandContext (ctx , "systemctl" , "restart" , "patchmon-agent" )
306+ output , err := cmd .CombinedOutput ()
307+ if err != nil {
308+ return fmt .Errorf ("failed to restart service: %w, output: %s" , err , string (output ))
309+ }
310+
311+ logger .WithField ("output" , string (output )).Debug ("Service restart command completed" )
312+ return nil
313+ }
314+
296315// Removed update-crontab command (cron is no longer used)
0 commit comments