@@ -15,6 +15,7 @@ import (
1515 "gitmdm/internal/gitmdm"
1616 "io"
1717 "log"
18+ "math"
1819 "net/http"
1920 "os"
2021 "os/exec"
@@ -34,6 +35,14 @@ import (
3435const (
3536 // Command execution timeout.
3637 commandTimeout = 10 * time .Second
38+
39+ // OS constants.
40+ osWindows = "windows"
41+ osDarwin = "darwin"
42+ osLinux = "linux"
43+
44+ // Windows command constants.
45+ wmicCmd = "wmic"
3746 // Maximum output size to prevent memory exhaustion.
3847 maxOutputSize = 92160 // 90KB limit (matching server)
3948 // Maximum log output length for readability.
@@ -156,10 +165,39 @@ func main() {
156165 LoggedInUsers : agent .loggedInUsers (ctx ),
157166 }
158167
159- if err := agent .sendReport (ctx , report ); err != nil {
168+ // Retry the verification with exponential backoff
169+ var lastErr error
170+ for attempt := 0 ; attempt <= maxRetries ; attempt ++ {
171+ if attempt > 0 {
172+ backoff := time .Duration (float64 (initialBackoff ) * math .Pow (2 , float64 (attempt - 1 )))
173+ if backoff > maxBackoff {
174+ backoff = maxBackoff
175+ }
176+ log .Printf ("[INFO] Retrying verification (attempt %d/%d) after %v..." , attempt , maxRetries , backoff )
177+ select {
178+ case <- time .After (backoff ):
179+ case <- ctx .Done ():
180+ cancel ()
181+ //nolint:gocritic,lll // exitAfterDefer
182+ log .Fatalf ("Verification cancelled: %v" , ctx .Err ())
183+ }
184+ }
185+
186+ if err := agent .sendReport (ctx , report ); err != nil {
187+ lastErr = err
188+ log .Printf ("[WARN] Verification attempt %d failed: %v" , attempt + 1 , err )
189+ continue
190+ }
191+ // Success!
192+ lastErr = nil
193+ break
194+ }
195+
196+ if lastErr != nil {
160197 cancel ()
161- //nolint:gocritic,lll // exitAfterDefer
162- log .Fatalf ("Failed to verify server connection: %v\n Please check your --server and --join parameters" , err )
198+ //nolint:lll // exitAfterDefer
199+ log .Fatalf ("Failed to verify server connection after %d attempts: %v\n " +
200+ "Please check your --server and --join parameters" , maxRetries + 1 , lastErr )
163201 }
164202
165203 log .Println ("✓ Server connection verified successfully" )
@@ -550,8 +588,8 @@ func (*Agent) systemUptime(ctx context.Context) string {
550588 cmd = exec .CommandContext (ctx , "uptime" )
551589 case "solaris" , "illumos" :
552590 cmd = exec .CommandContext (ctx , "uptime" )
553- case "windows" :
554- cmd = exec .CommandContext (ctx , "wmic" , "os" , "get" , "lastbootuptime" )
591+ case osWindows :
592+ cmd = exec .CommandContext (ctx , wmicCmd , "os" , "get" , "lastbootuptime" )
555593 default :
556594 return "unsupported"
557595 }
@@ -568,22 +606,22 @@ func (*Agent) cpuLoad(ctx context.Context) string {
568606
569607 var cmd * exec.Cmd
570608 switch runtime .GOOS {
571- case "linux" :
609+ case osLinux :
572610 cmd = exec .CommandContext (ctx , "cat" , "/proc/loadavg" )
573611 case "darwin" , "freebsd" , "openbsd" , "netbsd" , "dragonfly" :
574612 cmd = exec .CommandContext (ctx , "sysctl" , "-n" , "vm.loadavg" )
575613 case "solaris" , "illumos" :
576614 cmd = exec .CommandContext (ctx , "uptime" )
577- case "windows" :
578- cmd = exec .CommandContext (ctx , "wmic" , "cpu" , "get" , "loadpercentage" )
615+ case osWindows :
616+ cmd = exec .CommandContext (ctx , wmicCmd , "cpu" , "get" , "loadpercentage" )
579617 default :
580618 return "unsupported"
581619 }
582620
583621 if output , err := cmd .Output (); err == nil {
584622 result := strings .TrimSpace (string (output ))
585623 // For Linux /proc/loadavg, extract just the three load averages
586- if runtime .GOOS == "linux" {
624+ if runtime .GOOS == osLinux {
587625 fields := strings .Fields (result )
588626 if len (fields ) >= 3 {
589627 result = strings .Join (fields [:3 ], " " )
@@ -609,16 +647,16 @@ func (*Agent) loggedInUsers(ctx context.Context) string {
609647 switch runtime .GOOS {
610648 case "linux" , "darwin" , "freebsd" , "openbsd" , "netbsd" , "dragonfly" , "solaris" , "illumos" :
611649 cmd = exec .CommandContext (ctx , "who" )
612- case "windows" :
613- cmd = exec .CommandContext (ctx , "wmic" , "computersystem" , "get" , "username" )
650+ case osWindows :
651+ cmd = exec .CommandContext (ctx , wmicCmd , "computersystem" , "get" , "username" )
614652 default :
615653 return "unsupported"
616654 }
617655
618656 if output , err := cmd .Output (); err == nil {
619657 result := strings .TrimSpace (string (output ))
620658 // Count unique users for Unix-like systems
621- if runtime .GOOS != "windows" {
659+ if runtime .GOOS != osWindows {
622660 lines := strings .Split (result , "\n " )
623661 userMap := make (map [string ]bool )
624662 for _ , line := range lines {
@@ -646,7 +684,7 @@ func (*Agent) osInfo(ctx context.Context) string {
646684 defer cancel ()
647685 var cmd * exec.Cmd
648686 switch runtime .GOOS {
649- case "linux" :
687+ case osLinux :
650688 // Try to get pretty name from os-release
651689 if data , err := os .ReadFile ("/etc/os-release" ); err == nil {
652690 lines := strings .Split (string (data ), "\n " )
@@ -659,17 +697,17 @@ func (*Agent) osInfo(ctx context.Context) string {
659697 }
660698 // Fallback to uname
661699 cmd = exec .CommandContext (ctx , "uname" , "-s" )
662- case "darwin" :
700+ case osDarwin :
663701 cmd = exec .CommandContext (ctx , "sw_vers" , "-productName" )
664- case "windows" :
665- cmd = exec .CommandContext (ctx , "wmic" , "os" , "get" , "Caption" , "/value" )
702+ case osWindows :
703+ cmd = exec .CommandContext (ctx , wmicCmd , "os" , "get" , "Caption" , "/value" )
666704 default :
667705 cmd = exec .CommandContext (ctx , "uname" , "-s" )
668706 }
669707 if cmd != nil {
670708 if output , err := cmd .Output (); err == nil {
671709 result := strings .TrimSpace (string (output ))
672- if runtime .GOOS == "windows" && strings .Contains (result , "Caption=" ) {
710+ if runtime .GOOS == osWindows && strings .Contains (result , "Caption=" ) {
673711 result = strings .TrimPrefix (result , "Caption=" )
674712 }
675713 if result != "" {
@@ -691,18 +729,18 @@ func (*Agent) osVersion(ctx context.Context) string {
691729 defer cancel ()
692730 var cmd * exec.Cmd
693731 switch runtime .GOOS {
694- case "linux" :
732+ case osLinux :
695733 cmd = exec .CommandContext (ctx , "uname" , "-r" )
696- case "darwin" :
734+ case osDarwin :
697735 cmd = exec .CommandContext (ctx , "sw_vers" , "-productVersion" )
698- case "windows" :
699- cmd = exec .CommandContext (ctx , "wmic" , "os" , "get" , "Version" , "/value" )
736+ case osWindows :
737+ cmd = exec .CommandContext (ctx , wmicCmd , "os" , "get" , "Version" , "/value" )
700738 default :
701739 cmd = exec .CommandContext (ctx , "uname" , "-r" )
702740 }
703741 if output , err := cmd .Output (); err == nil {
704742 result := strings .TrimSpace (string (output ))
705- if runtime .GOOS == "windows" && strings .Contains (result , "Version=" ) {
743+ if runtime .GOOS == osWindows && strings .Contains (result , "Version=" ) {
706744 result = strings .TrimPrefix (result , "Version=" )
707745 }
708746 if result != "" {
@@ -827,7 +865,7 @@ func illumosHardwareID() string {
827865func windowsHardwareID () string {
828866 ctx , cancel := context .WithTimeout (context .Background (), 5 * time .Second )
829867 defer cancel ()
830- cmd := exec .CommandContext (ctx , "wmic" , "csproduct" , "get" , "UUID" )
868+ cmd := exec .CommandContext (ctx , wmicCmd , "csproduct" , "get" , "UUID" )
831869 output , err := cmd .Output ()
832870 if err != nil {
833871 if * debug {
@@ -857,17 +895,17 @@ func hardwareID() string {
857895
858896 var id string
859897 switch runtime .GOOS {
860- case "darwin" :
898+ case osDarwin :
861899 id = darwinHardwareID ()
862- case "linux" :
900+ case osLinux :
863901 id = linuxHardwareID ()
864902 case "freebsd" , "openbsd" , "netbsd" , "dragonfly" :
865903 id = bsdHardwareID ()
866904 case "solaris" :
867905 id = solarisHardwareID ()
868906 case "illumos" :
869907 id = illumosHardwareID ()
870- case "windows" :
908+ case osWindows :
871909 id = windowsHardwareID ()
872910 default :
873911 if * debug {
@@ -1218,7 +1256,7 @@ func (*Agent) displayAllChecks(results map[string]CheckResult, checkOrder []stri
12181256 }
12191257 printLine ("[Command %d of %d - %s]" , i + 1 , len (result .Outputs ), status )
12201258 }
1221-
1259+
12221260 if output .Command != "" {
12231261 printLine ("Command: %s" , output .Command )
12241262 } else if output .File != "" {
0 commit comments