diff --git a/cmd/admin-handlers.go b/cmd/admin-handlers.go index 2304df875..47aa089c9 100644 --- a/cmd/admin-handlers.go +++ b/cmd/admin-handlers.go @@ -142,7 +142,16 @@ func (a adminAPIHandlers) ServerUpdateHandler(w http.ResponseWriter, r *http.Req return } - for _, nerr := range globalNotificationSys.DownloadBinary(ctx, u, sha256Sum, releaseInfo) { + // Download Binary Once + reader, err := downloadBinary(u, mode) + if err != nil { + logger.LogIf(ctx, fmt.Errorf("server update failed with %w", err)) + writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) + return + } + + // Push binary to other servers + for _, nerr := range globalNotificationSys.VerifyBinary(ctx, u, sha256Sum, releaseInfo, reader) { if nerr.Err != nil { err := AdminError{ Code: AdminUpdateApplyFailure, @@ -156,7 +165,7 @@ func (a adminAPIHandlers) ServerUpdateHandler(w http.ResponseWriter, r *http.Req } } - err = downloadBinary(u, sha256Sum, releaseInfo, mode) + err = verifyBinary(u, sha256Sum, releaseInfo, mode, reader) if err != nil { logger.LogIf(ctx, fmt.Errorf("server update failed with %w", err)) writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) diff --git a/cmd/notification.go b/cmd/notification.go index 92e2a2cac..e4c12e878 100644 --- a/cmd/notification.go +++ b/cmd/notification.go @@ -356,8 +356,8 @@ func (sys *NotificationSys) DownloadProfilingData(ctx context.Context, writer io return } -// DownloadBinary - asks remote peers to download a new binary from the URL and to verify the checksum -func (sys *NotificationSys) DownloadBinary(ctx context.Context, u *url.URL, sha256Sum []byte, releaseInfo string) []NotificationPeerErr { +// VerifyBinary - asks remote peers to verify the checksum +func (sys *NotificationSys) VerifyBinary(ctx context.Context, u *url.URL, sha256Sum []byte, releaseInfo string, reader []byte) []NotificationPeerErr { ng := WithNPeers(len(sys.peerClients)) for idx, client := range sys.peerClients { if client == nil { @@ -365,7 +365,7 @@ func (sys *NotificationSys) DownloadBinary(ctx context.Context, u *url.URL, sha2 } client := client ng.Go(ctx, func() error { - return client.DownloadBinary(ctx, u, sha256Sum, releaseInfo) + return client.VerifyBinary(ctx, u, sha256Sum, releaseInfo, reader) }, idx, *client.host) } return ng.Wait() diff --git a/cmd/peer-rest-client.go b/cmd/peer-rest-client.go index 7a88edaef..f392d5494 100644 --- a/cmd/peer-rest-client.go +++ b/cmd/peer-rest-client.go @@ -422,16 +422,18 @@ type binaryInfo struct { URL *url.URL Sha256Sum []byte ReleaseInfo string + BinaryFile []byte } -// DownloadBinary - sends download binary message to remote peers. -func (client *peerRESTClient) DownloadBinary(ctx context.Context, u *url.URL, sha256Sum []byte, releaseInfo string) error { +// VerifyBinary - sends verify binary message to remote peers. +func (client *peerRESTClient) VerifyBinary(ctx context.Context, u *url.URL, sha256Sum []byte, releaseInfo string, readerInput []byte) error { values := make(url.Values) var reader bytes.Buffer if err := gob.NewEncoder(&reader).Encode(binaryInfo{ URL: u, Sha256Sum: sha256Sum, ReleaseInfo: releaseInfo, + BinaryFile: readerInput, }); err != nil { return err } diff --git a/cmd/peer-rest-server.go b/cmd/peer-rest-server.go index 5e7e68d7a..0fef48c51 100644 --- a/cmd/peer-rest-server.go +++ b/cmd/peer-rest-server.go @@ -770,7 +770,7 @@ func (s *peerRESTServer) DownloadBinaryHandler(w http.ResponseWriter, r *http.Re return } - if err = downloadBinary(info.URL, info.Sha256Sum, info.ReleaseInfo, getMinioMode()); err != nil { + if err = verifyBinary(info.URL, info.Sha256Sum, info.ReleaseInfo, getMinioMode(), info.BinaryFile); err != nil { s.writeErrorResponse(w, err) return } diff --git a/cmd/update.go b/cmd/update.go index 8cae892e5..4a80d59b4 100644 --- a/cmd/update.go +++ b/cmd/update.go @@ -19,6 +19,7 @@ package cmd import ( "bufio" + "bytes" "crypto" "crypto/tls" "encoding/hex" @@ -505,26 +506,38 @@ func getUpdateReaderFromURL(u *url.URL, transport http.RoundTripper, mode string var updateInProgress uint32 -func downloadBinary(u *url.URL, sha256Sum []byte, releaseInfo string, mode string) (err error) { +// Function to get the reader from an architecture +func downloadBinary(u *url.URL, mode string) (readerReturn []byte, err error) { + transport := getUpdateTransport(30 * time.Second) + var reader io.ReadCloser + if u.Scheme == "https" || u.Scheme == "http" { + reader, err = getUpdateReaderFromURL(u, transport, mode) + if err != nil { + return nil, err + } + } else { + reader, err = getUpdateReaderFromFile(u) + if err != nil { + return nil, err + } + } + + // convert a Reader to bytes + binaryFile, err := ioutil.ReadAll(reader) + if err != nil { + return nil, err + } + + return binaryFile, nil +} + +func verifyBinary(u *url.URL, sha256Sum []byte, releaseInfo string, mode string, reader []byte) (err error) { if !atomic.CompareAndSwapUint32(&updateInProgress, 0, 1) { return errors.New("update already in progress") } defer atomic.StoreUint32(&updateInProgress, 0) transport := getUpdateTransport(30 * time.Second) - var reader io.ReadCloser - if u.Scheme == "https" || u.Scheme == "http" { - reader, err = getUpdateReaderFromURL(u, transport, mode) - if err != nil { - return err - } - } else { - reader, err = getUpdateReaderFromFile(u) - if err != nil { - return err - } - } - opts := selfupdate.Options{ Hash: crypto.SHA256, Checksum: sha256Sum, @@ -552,7 +565,7 @@ func downloadBinary(u *url.URL, sha256Sum []byte, releaseInfo string, mode strin opts.Verifier = v } - if err = selfupdate.PrepareAndCheckBinary(reader, opts); err != nil { + if err = selfupdate.PrepareAndCheckBinary(bytes.NewReader(reader), opts); err != nil { var pathErr *os.PathError if errors.As(err, &pathErr) { return AdminError{