mirror of https://github.com/minio/minio.git
				
				
				
			feat: update binary once and push it to other servers (#15407)
This commit is contained in:
		
							parent
							
								
									916f274c83
								
							
						
					
					
						commit
						8ec888d13d
					
				| 
						 | 
					@ -142,7 +142,16 @@ func (a adminAPIHandlers) ServerUpdateHandler(w http.ResponseWriter, r *http.Req
 | 
				
			||||||
		return
 | 
							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 {
 | 
							if nerr.Err != nil {
 | 
				
			||||||
			err := AdminError{
 | 
								err := AdminError{
 | 
				
			||||||
				Code:       AdminUpdateApplyFailure,
 | 
									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 {
 | 
						if err != nil {
 | 
				
			||||||
		logger.LogIf(ctx, fmt.Errorf("server update failed with %w", err))
 | 
							logger.LogIf(ctx, fmt.Errorf("server update failed with %w", err))
 | 
				
			||||||
		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
 | 
							writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -356,8 +356,8 @@ func (sys *NotificationSys) DownloadProfilingData(ctx context.Context, writer io
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// DownloadBinary - asks remote peers to download a new binary from the URL and to verify the checksum
 | 
					// VerifyBinary - asks remote peers to verify the checksum
 | 
				
			||||||
func (sys *NotificationSys) DownloadBinary(ctx context.Context, u *url.URL, sha256Sum []byte, releaseInfo string) []NotificationPeerErr {
 | 
					func (sys *NotificationSys) VerifyBinary(ctx context.Context, u *url.URL, sha256Sum []byte, releaseInfo string, reader []byte) []NotificationPeerErr {
 | 
				
			||||||
	ng := WithNPeers(len(sys.peerClients))
 | 
						ng := WithNPeers(len(sys.peerClients))
 | 
				
			||||||
	for idx, client := range sys.peerClients {
 | 
						for idx, client := range sys.peerClients {
 | 
				
			||||||
		if client == nil {
 | 
							if client == nil {
 | 
				
			||||||
| 
						 | 
					@ -365,7 +365,7 @@ func (sys *NotificationSys) DownloadBinary(ctx context.Context, u *url.URL, sha2
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		client := client
 | 
							client := client
 | 
				
			||||||
		ng.Go(ctx, func() error {
 | 
							ng.Go(ctx, func() error {
 | 
				
			||||||
			return client.DownloadBinary(ctx, u, sha256Sum, releaseInfo)
 | 
								return client.VerifyBinary(ctx, u, sha256Sum, releaseInfo, reader)
 | 
				
			||||||
		}, idx, *client.host)
 | 
							}, idx, *client.host)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return ng.Wait()
 | 
						return ng.Wait()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -422,16 +422,18 @@ type binaryInfo struct {
 | 
				
			||||||
	URL         *url.URL
 | 
						URL         *url.URL
 | 
				
			||||||
	Sha256Sum   []byte
 | 
						Sha256Sum   []byte
 | 
				
			||||||
	ReleaseInfo string
 | 
						ReleaseInfo string
 | 
				
			||||||
 | 
						BinaryFile  []byte
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// DownloadBinary - sends download binary message to remote peers.
 | 
					// VerifyBinary - sends verify binary message to remote peers.
 | 
				
			||||||
func (client *peerRESTClient) DownloadBinary(ctx context.Context, u *url.URL, sha256Sum []byte, releaseInfo string) error {
 | 
					func (client *peerRESTClient) VerifyBinary(ctx context.Context, u *url.URL, sha256Sum []byte, releaseInfo string, readerInput []byte) error {
 | 
				
			||||||
	values := make(url.Values)
 | 
						values := make(url.Values)
 | 
				
			||||||
	var reader bytes.Buffer
 | 
						var reader bytes.Buffer
 | 
				
			||||||
	if err := gob.NewEncoder(&reader).Encode(binaryInfo{
 | 
						if err := gob.NewEncoder(&reader).Encode(binaryInfo{
 | 
				
			||||||
		URL:         u,
 | 
							URL:         u,
 | 
				
			||||||
		Sha256Sum:   sha256Sum,
 | 
							Sha256Sum:   sha256Sum,
 | 
				
			||||||
		ReleaseInfo: releaseInfo,
 | 
							ReleaseInfo: releaseInfo,
 | 
				
			||||||
 | 
							BinaryFile:  readerInput,
 | 
				
			||||||
	}); err != nil {
 | 
						}); err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -770,7 +770,7 @@ func (s *peerRESTServer) DownloadBinaryHandler(w http.ResponseWriter, r *http.Re
 | 
				
			||||||
		return
 | 
							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)
 | 
							s.writeErrorResponse(w, err)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -19,6 +19,7 @@ package cmd
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"bufio"
 | 
						"bufio"
 | 
				
			||||||
 | 
						"bytes"
 | 
				
			||||||
	"crypto"
 | 
						"crypto"
 | 
				
			||||||
	"crypto/tls"
 | 
						"crypto/tls"
 | 
				
			||||||
	"encoding/hex"
 | 
						"encoding/hex"
 | 
				
			||||||
| 
						 | 
					@ -505,26 +506,38 @@ func getUpdateReaderFromURL(u *url.URL, transport http.RoundTripper, mode string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var updateInProgress uint32
 | 
					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) {
 | 
						if !atomic.CompareAndSwapUint32(&updateInProgress, 0, 1) {
 | 
				
			||||||
		return errors.New("update already in progress")
 | 
							return errors.New("update already in progress")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	defer atomic.StoreUint32(&updateInProgress, 0)
 | 
						defer atomic.StoreUint32(&updateInProgress, 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	transport := getUpdateTransport(30 * time.Second)
 | 
						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{
 | 
						opts := selfupdate.Options{
 | 
				
			||||||
		Hash:     crypto.SHA256,
 | 
							Hash:     crypto.SHA256,
 | 
				
			||||||
		Checksum: sha256Sum,
 | 
							Checksum: sha256Sum,
 | 
				
			||||||
| 
						 | 
					@ -552,7 +565,7 @@ func downloadBinary(u *url.URL, sha256Sum []byte, releaseInfo string, mode strin
 | 
				
			||||||
		opts.Verifier = v
 | 
							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
 | 
							var pathErr *os.PathError
 | 
				
			||||||
		if errors.As(err, &pathErr) {
 | 
							if errors.As(err, &pathErr) {
 | 
				
			||||||
			return AdminError{
 | 
								return AdminError{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue