| 
									
										
										
										
											2021-04-19 03:41:13 +08:00
										 |  |  | // Copyright (c) 2015-2021 MinIO, Inc.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // This file is part of MinIO Object Storage stack
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // This program is free software: you can redistribute it and/or modify
 | 
					
						
							|  |  |  | // it under the terms of the GNU Affero General Public License as published by
 | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or
 | 
					
						
							|  |  |  | // (at your option) any later version.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // This program is distributed in the hope that it will be useful
 | 
					
						
							|  |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
					
						
							|  |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
					
						
							|  |  |  | // GNU Affero General Public License for more details.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // You should have received a copy of the GNU Affero General Public License
 | 
					
						
							|  |  |  | // along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
					
						
							| 
									
										
										
										
											2015-10-18 06:03:46 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-19 07:23:42 +08:00
										 |  |  | package cmd | 
					
						
							| 
									
										
										
										
											2015-10-18 06:03:46 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2017-06-25 04:17:28 +08:00
										 |  |  | 	"bufio" | 
					
						
							| 
									
										
										
										
											2022-07-29 23:34:30 +08:00
										 |  |  | 	"bytes" | 
					
						
							| 
									
										
										
										
											2017-12-16 04:33:42 +08:00
										 |  |  | 	"crypto" | 
					
						
							| 
									
										
										
										
											2020-06-04 04:18:54 +08:00
										 |  |  | 	"crypto/tls" | 
					
						
							| 
									
										
										
										
											2017-12-16 04:33:42 +08:00
										 |  |  | 	"encoding/hex" | 
					
						
							| 
									
										
										
										
											2019-09-13 04:03:42 +08:00
										 |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2017-02-15 16:31:00 +08:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2020-07-23 23:03:31 +08:00
										 |  |  | 	"io" | 
					
						
							| 
									
										
										
										
											2015-10-18 06:03:46 +08:00
										 |  |  | 	"net/http" | 
					
						
							| 
									
										
										
										
											2020-07-23 23:03:31 +08:00
										 |  |  | 	"net/url" | 
					
						
							| 
									
										
										
										
											2016-10-13 09:09:08 +08:00
										 |  |  | 	"os" | 
					
						
							| 
									
										
										
										
											2020-07-23 23:03:31 +08:00
										 |  |  | 	"path" | 
					
						
							| 
									
										
										
										
											2017-02-21 17:32:05 +08:00
										 |  |  | 	"path/filepath" | 
					
						
							| 
									
										
										
										
											2015-10-18 06:03:46 +08:00
										 |  |  | 	"runtime" | 
					
						
							| 
									
										
										
										
											2015-12-23 09:11:11 +08:00
										 |  |  | 	"strings" | 
					
						
							| 
									
										
										
										
											2022-04-20 21:18:21 +08:00
										 |  |  | 	"sync/atomic" | 
					
						
							| 
									
										
										
										
											2015-10-18 06:03:46 +08:00
										 |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-02 05:59:40 +08:00
										 |  |  | 	xhttp "github.com/minio/minio/internal/http" | 
					
						
							|  |  |  | 	"github.com/minio/minio/internal/logger" | 
					
						
							| 
									
										
										
										
											2023-09-05 03:57:37 +08:00
										 |  |  | 	"github.com/minio/pkg/v2/env" | 
					
						
							|  |  |  | 	xnet "github.com/minio/pkg/v2/net" | 
					
						
							| 
									
										
										
										
											2020-07-23 23:03:31 +08:00
										 |  |  | 	"github.com/minio/selfupdate" | 
					
						
							| 
									
										
										
										
											2023-01-24 00:07:55 +08:00
										 |  |  | 	gopsutilcpu "github.com/shirou/gopsutil/v3/cpu" | 
					
						
							| 
									
										
										
										
											2015-10-18 06:03:46 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-21 17:32:05 +08:00
										 |  |  | const ( | 
					
						
							|  |  |  | 	minioReleaseTagTimeLayout = "2006-01-02T15-04-05Z" | 
					
						
							| 
									
										
										
										
											2017-12-16 04:33:42 +08:00
										 |  |  | 	minioOSARCH               = runtime.GOOS + "-" + runtime.GOARCH | 
					
						
							| 
									
										
										
										
											2019-08-07 03:08:58 +08:00
										 |  |  | 	minioReleaseURL           = "https://dl.min.io/server/minio/release/" + minioOSARCH + SlashSeparator | 
					
						
							| 
									
										
										
										
											2020-07-23 23:03:31 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	envMinisignPubKey = "MINIO_UPDATE_MINISIGN_PUBKEY" | 
					
						
							|  |  |  | 	updateTimeout     = 10 * time.Second | 
					
						
							| 
									
										
										
										
											2017-02-21 17:32:05 +08:00
										 |  |  | ) | 
					
						
							| 
									
										
										
										
											2017-02-15 16:31:00 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-03 01:15:06 +08:00
										 |  |  | // For windows our files have .exe additionally.
 | 
					
						
							|  |  |  | var minioReleaseWindowsInfoURL = minioReleaseURL + "minio.exe.sha256sum" | 
					
						
							| 
									
										
										
										
											2015-12-23 09:11:11 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-10 07:12:13 +08:00
										 |  |  | // minioVersionToReleaseTime - parses a standard official release
 | 
					
						
							| 
									
										
										
										
											2019-04-10 02:39:42 +08:00
										 |  |  | // MinIO version string.
 | 
					
						
							| 
									
										
										
										
											2017-10-10 07:12:13 +08:00
										 |  |  | //
 | 
					
						
							|  |  |  | // An official binary's version string is the release time formatted
 | 
					
						
							|  |  |  | // with RFC3339 (in UTC) - e.g. `2017-09-29T19:16:56Z`
 | 
					
						
							|  |  |  | func minioVersionToReleaseTime(version string) (releaseTime time.Time, err error) { | 
					
						
							|  |  |  | 	return time.Parse(time.RFC3339, version) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // releaseTimeToReleaseTag - converts a time to a string formatted as
 | 
					
						
							| 
									
										
										
										
											2019-04-10 02:39:42 +08:00
										 |  |  | // an official MinIO release tag.
 | 
					
						
							| 
									
										
										
										
											2017-10-10 07:12:13 +08:00
										 |  |  | //
 | 
					
						
							|  |  |  | // An official minio release tag looks like:
 | 
					
						
							|  |  |  | // `RELEASE.2017-09-29T19-16-56Z`
 | 
					
						
							|  |  |  | func releaseTimeToReleaseTag(releaseTime time.Time) string { | 
					
						
							|  |  |  | 	return "RELEASE." + releaseTime.Format(minioReleaseTagTimeLayout) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // releaseTagToReleaseTime - reverse of `releaseTimeToReleaseTag()`
 | 
					
						
							|  |  |  | func releaseTagToReleaseTime(releaseTag string) (releaseTime time.Time, err error) { | 
					
						
							| 
									
										
										
										
											2019-08-29 06:04:43 +08:00
										 |  |  | 	fields := strings.Split(releaseTag, ".") | 
					
						
							| 
									
										
										
										
											2022-07-16 07:00:34 +08:00
										 |  |  | 	if len(fields) < 2 || len(fields) > 4 { | 
					
						
							| 
									
										
										
										
											2017-10-10 07:12:13 +08:00
										 |  |  | 		return releaseTime, fmt.Errorf("%s is not a valid release tag", releaseTag) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-08-29 06:04:43 +08:00
										 |  |  | 	if fields[0] != "RELEASE" { | 
					
						
							|  |  |  | 		return releaseTime, fmt.Errorf("%s is not a valid release tag", releaseTag) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return time.Parse(minioReleaseTagTimeLayout, fields[1]) | 
					
						
							| 
									
										
										
										
											2017-10-10 07:12:13 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // getModTime - get the file modification time of `path`
 | 
					
						
							|  |  |  | func getModTime(path string) (t time.Time, err error) { | 
					
						
							|  |  |  | 	// Convert to absolute path
 | 
					
						
							|  |  |  | 	absPath, err := filepath.Abs(path) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2019-12-03 01:28:01 +08:00
										 |  |  | 		return t, fmt.Errorf("Unable to get absolute path of %s. %w", path, err) | 
					
						
							| 
									
										
										
										
											2017-02-21 17:32:05 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-13 18:01:15 +08:00
										 |  |  | 	// Version is minio non-standard, we will use minio binary's
 | 
					
						
							|  |  |  | 	// ModTime as release time.
 | 
					
						
							| 
									
										
										
										
											2022-07-06 05:45:49 +08:00
										 |  |  | 	fi, err := Stat(absPath) | 
					
						
							| 
									
										
										
										
											2016-04-30 05:24:10 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2019-12-03 01:28:01 +08:00
										 |  |  | 		return t, fmt.Errorf("Unable to get ModTime of %s. %w", absPath, err) | 
					
						
							| 
									
										
										
										
											2015-12-23 09:11:11 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-02-15 16:31:00 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-10 07:12:13 +08:00
										 |  |  | 	// Return the ModTime
 | 
					
						
							|  |  |  | 	return fi.ModTime().UTC(), nil | 
					
						
							| 
									
										
										
										
											2015-12-23 09:11:11 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-10 07:12:13 +08:00
										 |  |  | // GetCurrentReleaseTime - returns this process's release time.  If it
 | 
					
						
							|  |  |  | // is official minio version, parsed version is returned else minio
 | 
					
						
							|  |  |  | // binary's mod time is returned.
 | 
					
						
							| 
									
										
										
										
											2017-02-15 16:31:00 +08:00
										 |  |  | func GetCurrentReleaseTime() (releaseTime time.Time, err error) { | 
					
						
							| 
									
										
										
										
											2017-10-10 07:12:13 +08:00
										 |  |  | 	if releaseTime, err = minioVersionToReleaseTime(Version); err == nil { | 
					
						
							|  |  |  | 		return releaseTime, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Looks like version is minio non-standard, we use minio
 | 
					
						
							|  |  |  | 	// binary's ModTime as release time:
 | 
					
						
							|  |  |  | 	return getModTime(os.Args[0]) | 
					
						
							| 
									
										
										
										
											2017-02-15 16:31:00 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2016-10-13 09:09:08 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-10 07:12:13 +08:00
										 |  |  | // IsDocker - returns if the environment minio is running in docker or
 | 
					
						
							|  |  |  | // not. The check is a simple file existence check.
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2023-07-04 03:30:51 +08:00
										 |  |  | // https://github.com/moby/moby/blob/master/daemon/initlayer/setup_unix.go
 | 
					
						
							|  |  |  | // https://github.com/containers/podman/blob/master/libpod/runtime.go
 | 
					
						
							| 
									
										
										
										
											2017-06-13 08:33:21 +08:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2023-07-04 03:30:51 +08:00
										 |  |  | //	"/.dockerenv":        "file",
 | 
					
						
							|  |  |  | //	"/run/.containerenv": "file",
 | 
					
						
							| 
									
										
										
										
											2017-10-10 07:12:13 +08:00
										 |  |  | func IsDocker() bool { | 
					
						
							| 
									
										
										
										
											2023-07-04 03:30:51 +08:00
										 |  |  | 	var err error | 
					
						
							|  |  |  | 	for _, envfile := range []string{ | 
					
						
							|  |  |  | 		"/.dockerenv", | 
					
						
							|  |  |  | 		"/run/.containerenv", | 
					
						
							|  |  |  | 	} { | 
					
						
							|  |  |  | 		_, err = os.Stat(envfile) | 
					
						
							|  |  |  | 		if err == nil { | 
					
						
							|  |  |  | 			return true | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-10-13 14:40:48 +08:00
										 |  |  | 	if osIsNotExist(err) { | 
					
						
							| 
									
										
										
										
											2023-07-04 03:30:51 +08:00
										 |  |  | 		// if none of the files are present we may be running inside
 | 
					
						
							|  |  |  | 		// CRI-O, Containerd etc..
 | 
					
						
							|  |  |  | 		// Fallback to our container specific ENVs if they are set.
 | 
					
						
							|  |  |  | 		return env.IsSet("MINIO_ACCESS_KEY_FILE") | 
					
						
							| 
									
										
										
										
											2022-10-13 14:40:48 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-10-13 09:09:08 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-13 14:40:48 +08:00
										 |  |  | 	// Log error, as we will not propagate it to caller
 | 
					
						
							|  |  |  | 	logger.LogIf(GlobalContext, err) | 
					
						
							| 
									
										
										
										
											2017-02-15 16:31:00 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-13 14:40:48 +08:00
										 |  |  | 	return err == nil | 
					
						
							| 
									
										
										
										
											2017-02-15 16:31:00 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-13 08:33:21 +08:00
										 |  |  | // IsDCOS returns true if minio is running in DCOS.
 | 
					
						
							|  |  |  | func IsDCOS() bool { | 
					
						
							| 
									
										
										
										
											2022-10-13 14:40:48 +08:00
										 |  |  | 	// http://mesos.apache.org/documentation/latest/docker-containerizer/
 | 
					
						
							|  |  |  | 	// Mesos docker containerizer sets this value
 | 
					
						
							|  |  |  | 	return env.Get("MESOS_CONTAINER_NAME", "") != "" | 
					
						
							| 
									
										
										
										
											2017-06-13 08:33:21 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // IsKubernetes returns true if minio is running in kubernetes.
 | 
					
						
							| 
									
										
										
										
											2017-06-09 17:42:12 +08:00
										 |  |  | func IsKubernetes() bool { | 
					
						
							| 
									
										
										
										
											2022-10-13 14:40:48 +08:00
										 |  |  | 	// Kubernetes env used to validate if we are
 | 
					
						
							|  |  |  | 	// indeed running inside a kubernetes pod
 | 
					
						
							|  |  |  | 	// is KUBERNETES_SERVICE_HOST
 | 
					
						
							|  |  |  | 	// https://github.com/kubernetes/kubernetes/blob/master/pkg/kubelet/kubelet_pods.go#L541
 | 
					
						
							|  |  |  | 	return env.Get("KUBERNETES_SERVICE_HOST", "") != "" | 
					
						
							| 
									
										
										
										
											2017-06-09 17:42:12 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-27 09:53:45 +08:00
										 |  |  | // IsBOSH returns true if minio is deployed from a bosh package
 | 
					
						
							|  |  |  | func IsBOSH() bool { | 
					
						
							|  |  |  | 	// "/var/vcap/bosh" exists in BOSH deployed instance.
 | 
					
						
							|  |  |  | 	_, err := os.Stat("/var/vcap/bosh") | 
					
						
							| 
									
										
										
										
											2020-11-24 00:36:49 +08:00
										 |  |  | 	if osIsNotExist(err) { | 
					
						
							| 
									
										
										
										
											2017-10-27 09:53:45 +08:00
										 |  |  | 		return false | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Log error, as we will not propagate it to caller
 | 
					
						
							| 
									
										
										
										
											2020-04-10 00:30:02 +08:00
										 |  |  | 	logger.LogIf(GlobalContext, err) | 
					
						
							| 
									
										
										
										
											2017-10-27 09:53:45 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return err == nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-10 02:39:42 +08:00
										 |  |  | // MinIO Helm chart uses DownwardAPIFile to write pod label info to /podinfo/labels
 | 
					
						
							| 
									
										
										
										
											2017-06-25 04:17:28 +08:00
										 |  |  | // More info: https://kubernetes.io/docs/tasks/inject-data-application/downward-api-volume-expose-pod-information/#store-pod-fields
 | 
					
						
							|  |  |  | // Check if this is Helm package installation and report helm chart version
 | 
					
						
							|  |  |  | func getHelmVersion(helmInfoFilePath string) string { | 
					
						
							|  |  |  | 	// Read the file exists.
 | 
					
						
							| 
									
										
										
										
											2022-08-02 04:22:43 +08:00
										 |  |  | 	helmInfoFile, err := Open(helmInfoFilePath) | 
					
						
							| 
									
										
										
										
											2017-10-10 07:12:13 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2019-04-10 02:39:42 +08:00
										 |  |  | 		// Log errors and return "" as MinIO can be deployed
 | 
					
						
							| 
									
										
										
										
											2017-10-10 07:12:13 +08:00
										 |  |  | 		// without Helm charts as well.
 | 
					
						
							| 
									
										
										
										
											2020-11-24 00:36:49 +08:00
										 |  |  | 		if !osIsNotExist(err) { | 
					
						
							| 
									
										
										
										
											2018-04-06 06:04:40 +08:00
										 |  |  | 			reqInfo := (&logger.ReqInfo{}).AppendTags("helmInfoFilePath", helmInfoFilePath) | 
					
						
							| 
									
										
										
										
											2020-04-10 00:30:02 +08:00
										 |  |  | 			ctx := logger.SetReqInfo(GlobalContext, reqInfo) | 
					
						
							| 
									
										
										
										
											2018-04-06 06:04:40 +08:00
										 |  |  | 			logger.LogIf(ctx, err) | 
					
						
							| 
									
										
										
										
											2017-10-10 07:12:13 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-06-25 04:17:28 +08:00
										 |  |  | 		return "" | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-01-02 15:26:59 +08:00
										 |  |  | 	defer helmInfoFile.Close() | 
					
						
							| 
									
										
										
										
											2017-06-25 04:17:28 +08:00
										 |  |  | 	scanner := bufio.NewScanner(helmInfoFile) | 
					
						
							|  |  |  | 	for scanner.Scan() { | 
					
						
							|  |  |  | 		if strings.Contains(scanner.Text(), "chart=") { | 
					
						
							|  |  |  | 			helmChartVersion := strings.TrimPrefix(scanner.Text(), "chart=") | 
					
						
							|  |  |  | 			// remove quotes from the chart version
 | 
					
						
							|  |  |  | 			return strings.Trim(helmChartVersion, `"`) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return "" | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-10 07:12:13 +08:00
										 |  |  | // IsSourceBuild - returns if this binary is a non-official build from
 | 
					
						
							|  |  |  | // source code.
 | 
					
						
							| 
									
										
										
										
											2017-02-15 16:31:00 +08:00
										 |  |  | func IsSourceBuild() bool { | 
					
						
							| 
									
										
										
										
											2017-10-10 07:12:13 +08:00
										 |  |  | 	_, err := minioVersionToReleaseTime(Version) | 
					
						
							|  |  |  | 	return err != nil | 
					
						
							| 
									
										
										
										
											2017-02-15 16:31:00 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2016-03-25 08:20:49 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-09 08:51:59 +08:00
										 |  |  | // IsPCFTile returns if server is running in PCF
 | 
					
						
							|  |  |  | func IsPCFTile() bool { | 
					
						
							|  |  |  | 	return env.Get("MINIO_PCF_TILE_VERSION", "") != "" | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-15 16:31:00 +08:00
										 |  |  | // DO NOT CHANGE USER AGENT STYLE.
 | 
					
						
							|  |  |  | // The style should be
 | 
					
						
							| 
									
										
										
										
											2017-06-09 17:42:12 +08:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2022-08-27 03:52:29 +08:00
										 |  |  | //	MinIO (<OS>; <ARCH>[; <MODE>][; dcos][; kubernetes][; docker][; source]) MinIO/<VERSION> MinIO/<RELEASE-TAG> MinIO/<COMMIT-ID> [MinIO/universe-<PACKAGE-NAME>] [MinIO/helm-<HELM-VERSION>]
 | 
					
						
							| 
									
										
										
										
											2017-02-15 16:31:00 +08:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2017-10-10 07:12:13 +08:00
										 |  |  | // Any change here should be discussed by opening an issue at
 | 
					
						
							|  |  |  | // https://github.com/minio/minio/issues.
 | 
					
						
							| 
									
										
										
										
											2017-03-17 03:21:58 +08:00
										 |  |  | func getUserAgent(mode string) string { | 
					
						
							| 
									
										
										
										
											2017-10-10 07:12:13 +08:00
										 |  |  | 	userAgentParts := []string{} | 
					
						
							|  |  |  | 	// Helper function to concisely append a pair of strings to a
 | 
					
						
							|  |  |  | 	// the user-agent slice.
 | 
					
						
							|  |  |  | 	uaAppend := func(p, q string) { | 
					
						
							|  |  |  | 		userAgentParts = append(userAgentParts, p, q) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-10 02:39:42 +08:00
										 |  |  | 	uaAppend("MinIO (", runtime.GOOS) | 
					
						
							| 
									
										
										
										
											2017-10-10 07:12:13 +08:00
										 |  |  | 	uaAppend("; ", runtime.GOARCH) | 
					
						
							| 
									
										
										
										
											2017-03-17 03:21:58 +08:00
										 |  |  | 	if mode != "" { | 
					
						
							| 
									
										
										
										
											2017-10-10 07:12:13 +08:00
										 |  |  | 		uaAppend("; ", mode) | 
					
						
							| 
									
										
										
										
											2017-03-17 03:21:58 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-06-13 08:33:21 +08:00
										 |  |  | 	if IsDCOS() { | 
					
						
							| 
									
										
										
										
											2017-10-10 07:12:13 +08:00
										 |  |  | 		uaAppend("; ", "dcos") | 
					
						
							| 
									
										
										
										
											2017-06-13 08:33:21 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-06-09 17:42:12 +08:00
										 |  |  | 	if IsKubernetes() { | 
					
						
							| 
									
										
										
										
											2017-10-10 07:12:13 +08:00
										 |  |  | 		uaAppend("; ", "kubernetes") | 
					
						
							| 
									
										
										
										
											2017-06-09 17:42:12 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-02-15 16:31:00 +08:00
										 |  |  | 	if IsDocker() { | 
					
						
							| 
									
										
										
										
											2017-10-10 07:12:13 +08:00
										 |  |  | 		uaAppend("; ", "docker") | 
					
						
							| 
									
										
										
										
											2017-02-15 16:31:00 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-10-27 09:53:45 +08:00
										 |  |  | 	if IsBOSH() { | 
					
						
							|  |  |  | 		uaAppend("; ", "bosh") | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-02-15 16:31:00 +08:00
										 |  |  | 	if IsSourceBuild() { | 
					
						
							| 
									
										
										
										
											2017-10-10 07:12:13 +08:00
										 |  |  | 		uaAppend("; ", "source") | 
					
						
							| 
									
										
										
										
											2016-03-25 08:20:49 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-02-15 16:31:00 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-10 02:39:42 +08:00
										 |  |  | 	uaAppend(") MinIO/", Version) | 
					
						
							|  |  |  | 	uaAppend(" MinIO/", ReleaseTag) | 
					
						
							|  |  |  | 	uaAppend(" MinIO/", CommitID) | 
					
						
							| 
									
										
										
										
											2017-06-13 08:33:21 +08:00
										 |  |  | 	if IsDCOS() { | 
					
						
							| 
									
										
										
										
											2019-10-05 01:35:33 +08:00
										 |  |  | 		universePkgVersion := env.Get("MARATHON_APP_LABEL_DCOS_PACKAGE_VERSION", "") | 
					
						
							| 
									
										
										
										
											2017-06-13 08:33:21 +08:00
										 |  |  | 		// On DC/OS environment try to the get universe package version.
 | 
					
						
							|  |  |  | 		if universePkgVersion != "" { | 
					
						
							| 
									
										
										
										
											2019-04-10 02:39:42 +08:00
										 |  |  | 			uaAppend(" MinIO/universe-", universePkgVersion) | 
					
						
							| 
									
										
										
										
											2017-06-13 08:33:21 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-06-25 04:17:28 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if IsKubernetes() { | 
					
						
							|  |  |  | 		// In Kubernetes environment, try to fetch the helm package version
 | 
					
						
							|  |  |  | 		helmChartVersion := getHelmVersion("/podinfo/labels") | 
					
						
							|  |  |  | 		if helmChartVersion != "" { | 
					
						
							| 
									
										
										
										
											2019-04-10 02:39:42 +08:00
										 |  |  | 			uaAppend(" MinIO/helm-", helmChartVersion) | 
					
						
							| 
									
										
										
										
											2017-06-25 04:17:28 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-09-10 08:21:39 +08:00
										 |  |  | 		// In Kubernetes environment, try to fetch the Operator, VSPHERE plugin version
 | 
					
						
							|  |  |  | 		opVersion := env.Get("MINIO_OPERATOR_VERSION", "") | 
					
						
							|  |  |  | 		if opVersion != "" { | 
					
						
							|  |  |  | 			uaAppend(" MinIO/operator-", opVersion) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		vsphereVersion := env.Get("MINIO_VSPHERE_PLUGIN_VERSION", "") | 
					
						
							|  |  |  | 		if vsphereVersion != "" { | 
					
						
							|  |  |  | 			uaAppend(" MinIO/vsphere-plugin-", vsphereVersion) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-06-25 04:17:28 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-09 08:51:59 +08:00
										 |  |  | 	if IsPCFTile() { | 
					
						
							|  |  |  | 		pcfTileVersion := env.Get("MINIO_PCF_TILE_VERSION", "") | 
					
						
							|  |  |  | 		if pcfTileVersion != "" { | 
					
						
							|  |  |  | 			uaAppend(" MinIO/pcf-tile-", pcfTileVersion) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-10-27 09:53:45 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-24 00:07:55 +08:00
										 |  |  | 	if cpus, err := gopsutilcpu.Info(); err == nil && len(cpus) > 0 { | 
					
						
							|  |  |  | 		cpuMap := make(map[string]struct{}, len(cpus)) | 
					
						
							|  |  |  | 		coreMap := make(map[string]struct{}, len(cpus)) | 
					
						
							|  |  |  | 		for i := range cpus { | 
					
						
							|  |  |  | 			cpuMap[cpus[i].PhysicalID] = struct{}{} | 
					
						
							|  |  |  | 			coreMap[cpus[i].CoreID] = struct{}{} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		cpu := cpus[0] | 
					
						
							|  |  |  | 		uaAppend(" CPU ", fmt.Sprintf("(total_cpus:%d, total_cores:%d; vendor:%s; family:%s; model:%s; stepping:%d; model_name:%s)", | 
					
						
							|  |  |  | 			len(cpuMap), len(coreMap), cpu.VendorID, cpu.Family, cpu.Model, cpu.Stepping, cpu.ModelName)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-10 07:12:13 +08:00
										 |  |  | 	return strings.Join(userAgentParts, "") | 
					
						
							| 
									
										
										
										
											2017-02-15 16:31:00 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2016-03-25 08:20:49 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-23 23:03:31 +08:00
										 |  |  | func downloadReleaseURL(u *url.URL, timeout time.Duration, mode string) (content string, err error) { | 
					
						
							| 
									
										
										
										
											2022-07-29 08:44:21 +08:00
										 |  |  | 	req, err := http.NewRequest(http.MethodGet, u.String(), nil) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return content, AdminError{ | 
					
						
							|  |  |  | 			Code:       AdminUpdateUnexpectedFailure, | 
					
						
							|  |  |  | 			Message:    err.Error(), | 
					
						
							|  |  |  | 			StatusCode: http.StatusInternalServerError, | 
					
						
							| 
									
										
										
										
											2019-08-28 02:37:47 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-07-29 08:44:21 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	req.Header.Set("User-Agent", getUserAgent(mode)) | 
					
						
							| 
									
										
										
										
											2016-08-19 23:09:05 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-29 08:44:21 +08:00
										 |  |  | 	client := &http.Client{Transport: getUpdateTransport(timeout)} | 
					
						
							|  |  |  | 	resp, err := client.Do(req) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		if xnet.IsNetworkOrHostDown(err, false) { | 
					
						
							| 
									
										
										
										
											2020-07-23 23:03:31 +08:00
										 |  |  | 			return content, AdminError{ | 
					
						
							|  |  |  | 				Code:       AdminUpdateURLNotReachable, | 
					
						
							|  |  |  | 				Message:    err.Error(), | 
					
						
							|  |  |  | 				StatusCode: http.StatusServiceUnavailable, | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2019-08-28 02:37:47 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-07-29 08:44:21 +08:00
										 |  |  | 		return content, AdminError{ | 
					
						
							|  |  |  | 			Code:       AdminUpdateUnexpectedFailure, | 
					
						
							|  |  |  | 			Message:    err.Error(), | 
					
						
							|  |  |  | 			StatusCode: http.StatusInternalServerError, | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if resp == nil { | 
					
						
							|  |  |  | 		return content, AdminError{ | 
					
						
							|  |  |  | 			Code:       AdminUpdateUnexpectedFailure, | 
					
						
							|  |  |  | 			Message:    fmt.Sprintf("No response from server to download URL %s", u), | 
					
						
							|  |  |  | 			StatusCode: http.StatusInternalServerError, | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer xhttp.DrainBody(resp.Body) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if resp.StatusCode != http.StatusOK { | 
					
						
							|  |  |  | 		return content, AdminError{ | 
					
						
							|  |  |  | 			Code:       AdminUpdateUnexpectedFailure, | 
					
						
							|  |  |  | 			Message:    fmt.Sprintf("Error downloading URL %s. Response: %v", u, resp.Status), | 
					
						
							|  |  |  | 			StatusCode: resp.StatusCode, | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-02-15 16:31:00 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-07-23 23:03:31 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-20 02:05:16 +08:00
										 |  |  | 	contentBytes, err := io.ReadAll(resp.Body) | 
					
						
							| 
									
										
										
										
											2016-10-13 09:09:08 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2019-08-28 02:37:47 +08:00
										 |  |  | 		return content, AdminError{ | 
					
						
							|  |  |  | 			Code:       AdminUpdateUnexpectedFailure, | 
					
						
							|  |  |  | 			Message:    fmt.Sprintf("Error reading response. %s", err), | 
					
						
							|  |  |  | 			StatusCode: http.StatusInternalServerError, | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-10-13 09:09:08 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-28 02:37:47 +08:00
										 |  |  | 	return string(contentBytes), nil | 
					
						
							| 
									
										
										
										
											2017-02-15 16:31:00 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2016-10-25 04:44:15 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-10 07:12:13 +08:00
										 |  |  | // parseReleaseData - parses release info file content fetched from
 | 
					
						
							|  |  |  | // official minio download server.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // The expected format is a single line with two words like:
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2019-08-29 06:04:43 +08:00
										 |  |  | // fbe246edbd382902db9a4035df7dce8cb441357d minio.RELEASE.2016-10-07T01-16-39Z.<hotfix_optional>
 | 
					
						
							| 
									
										
										
										
											2017-10-10 07:12:13 +08:00
										 |  |  | //
 | 
					
						
							|  |  |  | // The second word must be `minio.` appended to a standard release tag.
 | 
					
						
							| 
									
										
										
										
											2021-04-09 00:51:11 +08:00
										 |  |  | func parseReleaseData(data string) (sha256Sum []byte, releaseTime time.Time, releaseInfo string, err error) { | 
					
						
							| 
									
										
										
										
											2019-08-29 06:04:43 +08:00
										 |  |  | 	defer func() { | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			err = AdminError{ | 
					
						
							|  |  |  | 				Code:       AdminUpdateUnexpectedFailure, | 
					
						
							|  |  |  | 				Message:    err.Error(), | 
					
						
							|  |  |  | 				StatusCode: http.StatusInternalServerError, | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-15 16:31:00 +08:00
										 |  |  | 	fields := strings.Fields(data) | 
					
						
							|  |  |  | 	if len(fields) != 2 { | 
					
						
							|  |  |  | 		err = fmt.Errorf("Unknown release data `%s`", data) | 
					
						
							| 
									
										
										
										
											2021-04-09 00:51:11 +08:00
										 |  |  | 		return sha256Sum, releaseTime, releaseInfo, err | 
					
						
							| 
									
										
										
										
											2020-07-23 23:03:31 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	sha256Sum, err = hex.DecodeString(fields[0]) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2021-04-09 00:51:11 +08:00
										 |  |  | 		return sha256Sum, releaseTime, releaseInfo, err | 
					
						
							| 
									
										
										
										
											2015-10-18 06:03:46 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-09 00:51:11 +08:00
										 |  |  | 	releaseInfo = fields[1] | 
					
						
							| 
									
										
										
										
											2017-10-10 07:12:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-29 06:04:43 +08:00
										 |  |  | 	// Split release of style minio.RELEASE.2019-08-21T19-40-07Z.<hotfix>
 | 
					
						
							|  |  |  | 	nfields := strings.SplitN(releaseInfo, ".", 2) | 
					
						
							|  |  |  | 	if len(nfields) != 2 { | 
					
						
							| 
									
										
										
										
											2017-02-15 16:31:00 +08:00
										 |  |  | 		err = fmt.Errorf("Unknown release information `%s`", releaseInfo) | 
					
						
							| 
									
										
										
										
											2021-04-09 00:51:11 +08:00
										 |  |  | 		return sha256Sum, releaseTime, releaseInfo, err | 
					
						
							| 
									
										
										
										
											2016-03-25 08:20:49 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-08-29 06:04:43 +08:00
										 |  |  | 	if nfields[0] != "minio" { | 
					
						
							| 
									
										
										
										
											2017-10-10 07:12:13 +08:00
										 |  |  | 		err = fmt.Errorf("Unknown release `%s`", releaseInfo) | 
					
						
							| 
									
										
										
										
											2021-04-09 00:51:11 +08:00
										 |  |  | 		return sha256Sum, releaseTime, releaseInfo, err | 
					
						
							| 
									
										
										
										
											2017-02-15 16:31:00 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-29 06:04:43 +08:00
										 |  |  | 	releaseTime, err = releaseTagToReleaseTime(nfields[1]) | 
					
						
							| 
									
										
										
										
											2017-02-15 16:31:00 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2019-12-03 01:28:01 +08:00
										 |  |  | 		err = fmt.Errorf("Unknown release tag format. %w", err) | 
					
						
							| 
									
										
										
										
											2017-02-15 16:31:00 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-09 00:51:11 +08:00
										 |  |  | 	return sha256Sum, releaseTime, releaseInfo, err | 
					
						
							| 
									
										
										
										
											2017-02-15 16:31:00 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-28 02:37:47 +08:00
										 |  |  | func getUpdateTransport(timeout time.Duration) http.RoundTripper { | 
					
						
							|  |  |  | 	var updateTransport http.RoundTripper = &http.Transport{ | 
					
						
							| 
									
										
										
										
											2020-07-11 03:08:14 +08:00
										 |  |  | 		Proxy:                 http.ProxyFromEnvironment, | 
					
						
							| 
									
										
										
										
											2023-05-04 05:12:25 +08:00
										 |  |  | 		DialContext:           xhttp.NewCustomDialContext(timeout, globalTCPOptions), | 
					
						
							| 
									
										
										
										
											2019-08-28 02:37:47 +08:00
										 |  |  | 		IdleConnTimeout:       timeout, | 
					
						
							|  |  |  | 		TLSHandshakeTimeout:   timeout, | 
					
						
							|  |  |  | 		ExpectContinueTimeout: timeout, | 
					
						
							| 
									
										
										
										
											2020-06-04 04:18:54 +08:00
										 |  |  | 		TLSClientConfig: &tls.Config{ | 
					
						
							| 
									
										
										
										
											2022-01-07 03:34:02 +08:00
										 |  |  | 			RootCAs:            globalRootCAs, | 
					
						
							|  |  |  | 			ClientSessionCache: tls.NewLRUClientSessionCache(tlsClientSessionCacheSize), | 
					
						
							| 
									
										
										
										
											2020-06-04 04:18:54 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		DisableCompression: true, | 
					
						
							| 
									
										
										
										
											2019-08-28 02:37:47 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return updateTransport | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-23 23:03:31 +08:00
										 |  |  | func getLatestReleaseTime(u *url.URL, timeout time.Duration, mode string) (sha256Sum []byte, releaseTime time.Time, err error) { | 
					
						
							|  |  |  | 	data, err := downloadReleaseURL(u, timeout, mode) | 
					
						
							| 
									
										
										
										
											2016-08-19 23:09:05 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2020-07-23 23:03:31 +08:00
										 |  |  | 		return sha256Sum, releaseTime, err | 
					
						
							| 
									
										
										
										
											2016-03-25 08:20:49 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-08-19 23:09:05 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-09 00:51:11 +08:00
										 |  |  | 	sha256Sum, releaseTime, _, err = parseReleaseData(data) | 
					
						
							|  |  |  | 	return | 
					
						
							| 
									
										
										
										
											2017-02-15 16:31:00 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-13 08:33:21 +08:00
										 |  |  | const ( | 
					
						
							|  |  |  | 	// Kubernetes deployment doc link.
 | 
					
						
							| 
									
										
										
										
											2022-09-29 12:28:45 +08:00
										 |  |  | 	kubernetesDeploymentDoc = "https://min.io/docs/minio/kubernetes/upstream/index.html#quickstart-for-kubernetes" | 
					
						
							| 
									
										
										
										
											2017-06-13 08:33:21 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Mesos deployment doc link.
 | 
					
						
							| 
									
										
										
										
											2022-09-29 12:28:45 +08:00
										 |  |  | 	mesosDeploymentDoc = "https://min.io/docs/minio/kubernetes/upstream/index.html#quickstart-for-kubernetes" | 
					
						
							| 
									
										
										
										
											2017-06-13 08:33:21 +08:00
										 |  |  | ) | 
					
						
							| 
									
										
										
										
											2017-06-09 17:42:12 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-10 07:12:13 +08:00
										 |  |  | func getDownloadURL(releaseTag string) (downloadURL string) { | 
					
						
							| 
									
										
										
										
											2017-06-13 08:33:21 +08:00
										 |  |  | 	// Check if we are in DCOS environment, return
 | 
					
						
							|  |  |  | 	// deployment guide for update procedures.
 | 
					
						
							|  |  |  | 	if IsDCOS() { | 
					
						
							|  |  |  | 		return mesosDeploymentDoc | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-09 17:42:12 +08:00
										 |  |  | 	// Check if we are in kubernetes environment, return
 | 
					
						
							|  |  |  | 	// deployment guide for update procedures.
 | 
					
						
							|  |  |  | 	if IsKubernetes() { | 
					
						
							|  |  |  | 		return kubernetesDeploymentDoc | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Check if we are docker environment, return docker update command
 | 
					
						
							| 
									
										
										
										
											2017-02-15 16:31:00 +08:00
										 |  |  | 	if IsDocker() { | 
					
						
							| 
									
										
										
										
											2017-06-09 17:42:12 +08:00
										 |  |  | 		// Construct release tag name.
 | 
					
						
							| 
									
										
										
										
											2021-09-02 09:48:26 +08:00
										 |  |  | 		return fmt.Sprintf("podman pull quay.io/minio/minio:%s", releaseTag) | 
					
						
							| 
									
										
										
										
											2017-02-15 16:31:00 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-10 07:12:13 +08:00
										 |  |  | 	// For binary only installations, we return link to the latest binary.
 | 
					
						
							| 
									
										
										
										
											2017-02-15 16:31:00 +08:00
										 |  |  | 	if runtime.GOOS == "windows" { | 
					
						
							|  |  |  | 		return minioReleaseURL + "minio.exe" | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return minioReleaseURL + "minio" | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-10-18 06:03:46 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-23 23:03:31 +08:00
										 |  |  | func getUpdateReaderFromURL(u *url.URL, transport http.RoundTripper, mode string) (io.ReadCloser, error) { | 
					
						
							| 
									
										
										
										
											2020-06-04 04:18:54 +08:00
										 |  |  | 	clnt := &http.Client{ | 
					
						
							| 
									
										
										
										
											2020-07-23 23:03:31 +08:00
										 |  |  | 		Transport: transport, | 
					
						
							| 
									
										
										
										
											2020-06-04 04:18:54 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-07-23 23:03:31 +08:00
										 |  |  | 	req, err := http.NewRequest(http.MethodGet, u.String(), nil) | 
					
						
							| 
									
										
										
										
											2019-08-28 02:37:47 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2020-07-23 23:03:31 +08:00
										 |  |  | 		return nil, AdminError{ | 
					
						
							| 
									
										
										
										
											2019-08-28 02:37:47 +08:00
										 |  |  | 			Code:       AdminUpdateUnexpectedFailure, | 
					
						
							|  |  |  | 			Message:    err.Error(), | 
					
						
							|  |  |  | 			StatusCode: http.StatusInternalServerError, | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-12-16 04:33:42 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-28 02:37:47 +08:00
										 |  |  | 	req.Header.Set("User-Agent", getUserAgent(mode)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	resp, err := clnt.Do(req) | 
					
						
							| 
									
										
										
										
											2017-12-16 04:33:42 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2020-10-30 00:52:11 +08:00
										 |  |  | 		if xnet.IsNetworkOrHostDown(err, false) { | 
					
						
							| 
									
										
										
										
											2020-07-23 23:03:31 +08:00
										 |  |  | 			return nil, AdminError{ | 
					
						
							| 
									
										
										
										
											2019-08-28 02:37:47 +08:00
										 |  |  | 				Code:       AdminUpdateURLNotReachable, | 
					
						
							|  |  |  | 				Message:    err.Error(), | 
					
						
							|  |  |  | 				StatusCode: http.StatusServiceUnavailable, | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-07-23 23:03:31 +08:00
										 |  |  | 		return nil, AdminError{ | 
					
						
							| 
									
										
										
										
											2019-08-28 02:37:47 +08:00
										 |  |  | 			Code:       AdminUpdateUnexpectedFailure, | 
					
						
							|  |  |  | 			Message:    err.Error(), | 
					
						
							|  |  |  | 			StatusCode: http.StatusInternalServerError, | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-12-16 04:33:42 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-07-23 23:03:31 +08:00
										 |  |  | 	return resp.Body, nil | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2017-12-16 04:33:42 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-20 21:18:21 +08:00
										 |  |  | var updateInProgress uint32 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-29 23:34:30 +08:00
										 |  |  | // Function to get the reader from an architecture
 | 
					
						
							|  |  |  | func downloadBinary(u *url.URL, mode string) (readerReturn []byte, err error) { | 
					
						
							| 
									
										
										
										
											2020-07-23 23:03:31 +08:00
										 |  |  | 	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 { | 
					
						
							| 
									
										
										
										
											2022-07-29 23:34:30 +08:00
										 |  |  | 			return nil, err | 
					
						
							| 
									
										
										
										
											2020-07-23 23:03:31 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2022-10-05 22:58:27 +08:00
										 |  |  | 		return nil, fmt.Errorf("unsupported protocol scheme: %s", u.Scheme) | 
					
						
							| 
									
										
										
										
											2020-07-23 23:03:31 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-11-04 23:22:38 +08:00
										 |  |  | 	defer xhttp.DrainBody(reader) | 
					
						
							| 
									
										
										
										
											2022-07-29 23:34:30 +08:00
										 |  |  | 	// convert a Reader to bytes
 | 
					
						
							| 
									
										
										
										
											2022-09-20 02:05:16 +08:00
										 |  |  | 	binaryFile, err := io.ReadAll(reader) | 
					
						
							| 
									
										
										
										
											2022-07-29 23:34:30 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return binaryFile, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-21 04:16:18 +08:00
										 |  |  | const ( | 
					
						
							|  |  |  | 	// Update this whenever the official minisign pubkey is rotated.
 | 
					
						
							|  |  |  | 	defaultMinisignPubkey = "RWTx5Zr1tiHQLwG9keckT0c45M3AGeHD6IvimQHpyRywVWGbP1aVSGav" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-04 03:30:51 +08:00
										 |  |  | func verifyBinary(u *url.URL, sha256Sum []byte, releaseInfo, mode string, reader []byte) (err error) { | 
					
						
							| 
									
										
										
										
											2022-07-29 23:34:30 +08:00
										 |  |  | 	if !atomic.CompareAndSwapUint32(&updateInProgress, 0, 1) { | 
					
						
							|  |  |  | 		return errors.New("update already in progress") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer atomic.StoreUint32(&updateInProgress, 0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	transport := getUpdateTransport(30 * time.Second) | 
					
						
							| 
									
										
										
										
											2020-07-23 23:03:31 +08:00
										 |  |  | 	opts := selfupdate.Options{ | 
					
						
							|  |  |  | 		Hash:     crypto.SHA256, | 
					
						
							|  |  |  | 		Checksum: sha256Sum, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-24 03:57:21 +08:00
										 |  |  | 	if err := opts.CheckPermissions(); err != nil { | 
					
						
							|  |  |  | 		return AdminError{ | 
					
						
							|  |  |  | 			Code:       AdminUpdateApplyFailure, | 
					
						
							|  |  |  | 			Message:    fmt.Sprintf("server update failed with: %s, do not restart the servers yet", err), | 
					
						
							|  |  |  | 			StatusCode: http.StatusInternalServerError, | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-21 04:16:18 +08:00
										 |  |  | 	minisignPubkey := env.Get(envMinisignPubKey, defaultMinisignPubkey) | 
					
						
							| 
									
										
										
										
											2020-07-23 23:03:31 +08:00
										 |  |  | 	if minisignPubkey != "" { | 
					
						
							|  |  |  | 		v := selfupdate.NewVerifier() | 
					
						
							| 
									
										
										
										
											2021-04-09 00:51:11 +08:00
										 |  |  | 		u.Path = path.Dir(u.Path) + slashSeparator + releaseInfo + ".minisig" | 
					
						
							| 
									
										
										
										
											2020-07-23 23:03:31 +08:00
										 |  |  | 		if err = v.LoadFromURL(u.String(), minisignPubkey, transport); err != nil { | 
					
						
							|  |  |  | 			return AdminError{ | 
					
						
							|  |  |  | 				Code:       AdminUpdateApplyFailure, | 
					
						
							|  |  |  | 				Message:    fmt.Sprintf("signature loading failed for %v with %v", u, err), | 
					
						
							|  |  |  | 				StatusCode: http.StatusInternalServerError, | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		opts.Verifier = v | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-29 23:34:30 +08:00
										 |  |  | 	if err = selfupdate.PrepareAndCheckBinary(bytes.NewReader(reader), opts); err != nil { | 
					
						
							| 
									
										
										
										
											2022-07-26 08:49:47 +08:00
										 |  |  | 		var pathErr *os.PathError | 
					
						
							|  |  |  | 		if errors.As(err, &pathErr) { | 
					
						
							|  |  |  | 			return AdminError{ | 
					
						
							|  |  |  | 				Code: AdminUpdateApplyFailure, | 
					
						
							|  |  |  | 				Message: fmt.Sprintf("Unable to update the binary at %s: %v", | 
					
						
							|  |  |  | 					filepath.Dir(pathErr.Path), pathErr.Err), | 
					
						
							|  |  |  | 				StatusCode: http.StatusForbidden, | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return AdminError{ | 
					
						
							|  |  |  | 			Code:       AdminUpdateApplyFailure, | 
					
						
							|  |  |  | 			Message:    err.Error(), | 
					
						
							|  |  |  | 			StatusCode: http.StatusInternalServerError, | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func commitBinary() (err error) { | 
					
						
							|  |  |  | 	if !atomic.CompareAndSwapUint32(&updateInProgress, 0, 1) { | 
					
						
							|  |  |  | 		return errors.New("update already in progress") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer atomic.StoreUint32(&updateInProgress, 0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	opts := selfupdate.Options{} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if err = selfupdate.CommitBinary(opts); err != nil { | 
					
						
							| 
									
										
										
										
											2020-07-23 23:03:31 +08:00
										 |  |  | 		if rerr := selfupdate.RollbackError(err); rerr != nil { | 
					
						
							| 
									
										
										
										
											2019-08-28 02:37:47 +08:00
										 |  |  | 			return AdminError{ | 
					
						
							|  |  |  | 				Code:       AdminUpdateApplyFailure, | 
					
						
							| 
									
										
										
										
											2019-09-13 04:03:42 +08:00
										 |  |  | 				Message:    fmt.Sprintf("Failed to rollback from bad update: %v", rerr), | 
					
						
							|  |  |  | 				StatusCode: http.StatusInternalServerError, | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		var pathErr *os.PathError | 
					
						
							|  |  |  | 		if errors.As(err, &pathErr) { | 
					
						
							|  |  |  | 			return AdminError{ | 
					
						
							|  |  |  | 				Code: AdminUpdateApplyFailure, | 
					
						
							|  |  |  | 				Message: fmt.Sprintf("Unable to update the binary at %s: %v", | 
					
						
							|  |  |  | 					filepath.Dir(pathErr.Path), pathErr.Err), | 
					
						
							| 
									
										
										
										
											2019-08-28 02:37:47 +08:00
										 |  |  | 				StatusCode: http.StatusForbidden, | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2019-07-09 08:46:04 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-08-28 02:37:47 +08:00
										 |  |  | 		return AdminError{ | 
					
						
							|  |  |  | 			Code:       AdminUpdateApplyFailure, | 
					
						
							|  |  |  | 			Message:    err.Error(), | 
					
						
							|  |  |  | 			StatusCode: http.StatusInternalServerError, | 
					
						
							| 
									
										
										
										
											2017-12-16 04:33:42 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-08-28 02:37:47 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2015-10-18 06:03:46 +08:00
										 |  |  | } |