Skip to content

Commit c15a87b

Browse files
committed
Docker agent: add arch-aware self-update download
Refs #526
1 parent f622b23 commit c15a87b

File tree

1 file changed

+84
-14
lines changed

1 file changed

+84
-14
lines changed

internal/dockeragent/agent.go

Lines changed: 84 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"net/http"
1313
"os"
1414
"os/exec"
15+
"runtime"
1516
"strings"
1617
"syscall"
1718
"time"
@@ -825,6 +826,34 @@ func (a *Agent) checkForUpdates(ctx context.Context) {
825826
a.logger.Info().Msg("Agent updated successfully, restarting...")
826827
}
827828

829+
func determineSelfUpdateArch() string {
830+
switch runtime.GOARCH {
831+
case "amd64":
832+
return "linux-amd64"
833+
case "arm64":
834+
return "linux-arm64"
835+
case "arm":
836+
return "linux-armv7"
837+
}
838+
839+
out, err := exec.Command("uname", "-m").Output()
840+
if err != nil {
841+
return ""
842+
}
843+
844+
normalized := strings.ToLower(strings.TrimSpace(string(out)))
845+
switch normalized {
846+
case "x86_64", "amd64":
847+
return "linux-amd64"
848+
case "aarch64", "arm64":
849+
return "linux-arm64"
850+
case "armv7l", "armhf", "armv7":
851+
return "linux-armv7"
852+
default:
853+
return ""
854+
}
855+
}
856+
828857
// selfUpdate downloads the new agent binary and replaces the current one
829858
func (a *Agent) selfUpdate(ctx context.Context) error {
830859
target := a.primaryTarget()
@@ -838,28 +867,69 @@ func (a *Agent) selfUpdate(ctx context.Context) error {
838867
return fmt.Errorf("failed to get executable path: %w", err)
839868
}
840869

841-
// Download new binary
842-
url := fmt.Sprintf("%s/download/pulse-docker-agent", target.URL)
843-
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
844-
if err != nil {
845-
return fmt.Errorf("failed to create download request: %w", err)
870+
downloadBase := strings.TrimRight(target.URL, "/") + "/download/pulse-docker-agent"
871+
archParam := determineSelfUpdateArch()
872+
873+
type downloadCandidate struct {
874+
url string
875+
arch string
846876
}
847877

848-
if target.Token != "" {
849-
req.Header.Set("X-API-Token", target.Token)
850-
req.Header.Set("Authorization", "Bearer "+target.Token)
878+
candidates := make([]downloadCandidate, 0, 2)
879+
if archParam != "" {
880+
candidates = append(candidates, downloadCandidate{
881+
url: fmt.Sprintf("%s?arch=%s", downloadBase, archParam),
882+
arch: archParam,
883+
})
851884
}
885+
candidates = append(candidates, downloadCandidate{url: downloadBase})
852886

853887
client := a.httpClientFor(target)
854-
resp, err := client.Do(req)
855-
if err != nil {
856-
return fmt.Errorf("failed to download new binary: %w", err)
888+
var resp *http.Response
889+
var lastErr error
890+
891+
for _, candidate := range candidates {
892+
req, err := http.NewRequestWithContext(ctx, http.MethodGet, candidate.url, nil)
893+
if err != nil {
894+
lastErr = fmt.Errorf("failed to create download request: %w", err)
895+
continue
896+
}
897+
898+
if target.Token != "" {
899+
req.Header.Set("X-API-Token", target.Token)
900+
req.Header.Set("Authorization", "Bearer "+target.Token)
901+
}
902+
903+
response, err := client.Do(req)
904+
if err != nil {
905+
lastErr = fmt.Errorf("failed to download new binary: %w", err)
906+
continue
907+
}
908+
909+
if response.StatusCode != http.StatusOK {
910+
lastErr = fmt.Errorf("download failed with status: %s", response.Status)
911+
response.Body.Close()
912+
continue
913+
}
914+
915+
resp = response
916+
if candidate.arch != "" {
917+
a.logger.Debug().
918+
Str("arch", candidate.arch).
919+
Msg("Self-update: downloaded architecture-specific agent binary")
920+
} else if archParam != "" {
921+
a.logger.Debug().Msg("Self-update: falling back to server default agent binary")
922+
}
923+
break
857924
}
858-
defer resp.Body.Close()
859925

860-
if resp.StatusCode != http.StatusOK {
861-
return fmt.Errorf("download failed with status: %s", resp.Status)
926+
if resp == nil {
927+
if lastErr == nil {
928+
lastErr = errors.New("failed to download new binary")
929+
}
930+
return lastErr
862931
}
932+
defer resp.Body.Close()
863933

864934
// Create temporary file
865935
tmpFile, err := os.CreateTemp("", "pulse-docker-agent-*.tmp")

0 commit comments

Comments
 (0)