| 
									
										
										
										
											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/>.
 | 
					
						
							| 
									
										
										
										
											2016-08-31 10:22:27 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | package cmd | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2020-08-05 05:55:53 +08:00
										 |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2022-01-25 03:28:45 +08:00
										 |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2017-06-18 02:20:12 +08:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2020-01-15 10:45:17 +08:00
										 |  |  | 	"net/http" | 
					
						
							|  |  |  | 	"net/url" | 
					
						
							| 
									
										
										
										
											2023-07-27 02:31:40 +08:00
										 |  |  | 	"path/filepath" | 
					
						
							| 
									
										
										
										
											2019-10-30 15:04:39 +08:00
										 |  |  | 	"sync" | 
					
						
							| 
									
										
										
										
											2016-08-31 10:22:27 +08:00
										 |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-14 11:25:29 +08:00
										 |  |  | 	"github.com/dustin/go-humanize" | 
					
						
							| 
									
										
										
										
											2021-06-02 05:59:40 +08:00
										 |  |  | 	xhttp "github.com/minio/minio/internal/http" | 
					
						
							|  |  |  | 	"github.com/minio/minio/internal/logger" | 
					
						
							| 
									
										
										
										
											2016-08-31 10:22:27 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-18 01:08:04 +08:00
										 |  |  | var printEndpointError = func() func(Endpoint, error, bool) { | 
					
						
							| 
									
										
										
										
											2019-10-30 15:04:39 +08:00
										 |  |  | 	var mutex sync.Mutex | 
					
						
							| 
									
										
										
										
											2020-07-18 01:08:04 +08:00
										 |  |  | 	printOnce := make(map[Endpoint]map[string]int) | 
					
						
							| 
									
										
										
										
											2018-02-16 09:45:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-18 01:08:04 +08:00
										 |  |  | 	return func(endpoint Endpoint, err error, once bool) { | 
					
						
							| 
									
										
										
										
											2018-09-14 12:42:50 +08:00
										 |  |  | 		reqInfo := (&logger.ReqInfo{}).AppendTags("endpoint", endpoint.String()) | 
					
						
							| 
									
										
										
										
											2020-04-10 00:30:02 +08:00
										 |  |  | 		ctx := logger.SetReqInfo(GlobalContext, reqInfo) | 
					
						
							| 
									
										
										
										
											2019-10-30 15:04:39 +08:00
										 |  |  | 		mutex.Lock() | 
					
						
							|  |  |  | 		defer mutex.Unlock() | 
					
						
							| 
									
										
										
										
											2020-07-18 01:08:04 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-16 09:45:57 +08:00
										 |  |  | 		m, ok := printOnce[endpoint] | 
					
						
							|  |  |  | 		if !ok { | 
					
						
							| 
									
										
										
										
											2020-07-18 01:08:04 +08:00
										 |  |  | 			m = make(map[string]int) | 
					
						
							| 
									
										
										
										
											2018-02-16 09:45:57 +08:00
										 |  |  | 			printOnce[endpoint] = m | 
					
						
							| 
									
										
										
										
											2020-07-18 01:08:04 +08:00
										 |  |  | 			if once { | 
					
						
							| 
									
										
										
										
											2023-05-13 01:41:54 +08:00
										 |  |  | 				m[err.Error()]++ | 
					
						
							| 
									
										
										
										
											2024-04-04 20:04:40 +08:00
										 |  |  | 				peersLogAlwaysIf(ctx, err) | 
					
						
							| 
									
										
										
										
											2020-07-18 01:08:04 +08:00
										 |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-12-29 01:32:48 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-07-18 01:08:04 +08:00
										 |  |  | 		// Once is set and we are here means error was already
 | 
					
						
							|  |  |  | 		// printed once.
 | 
					
						
							|  |  |  | 		if once { | 
					
						
							| 
									
										
										
										
											2018-02-16 09:45:57 +08:00
										 |  |  | 			return | 
					
						
							| 
									
										
										
										
											2017-12-29 01:32:48 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-07-18 01:08:04 +08:00
										 |  |  | 		// once not set, check if same error occurred 3 times in
 | 
					
						
							|  |  |  | 		// a row, then make sure we print it to call attention.
 | 
					
						
							|  |  |  | 		if m[err.Error()] > 2 { | 
					
						
							| 
									
										
										
										
											2024-04-04 20:04:40 +08:00
										 |  |  | 			peersLogAlwaysIf(ctx, fmt.Errorf("Following error has been printed %d times.. %w", m[err.Error()], err)) | 
					
						
							| 
									
										
										
										
											2020-07-18 01:08:04 +08:00
										 |  |  | 			// Reduce the count to introduce further delay in printing
 | 
					
						
							|  |  |  | 			// but let it again print after the 2th attempt
 | 
					
						
							|  |  |  | 			m[err.Error()]-- | 
					
						
							|  |  |  | 			m[err.Error()]-- | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		m[err.Error()]++ | 
					
						
							| 
									
										
										
										
											2017-12-29 01:32:48 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-02-16 09:45:57 +08:00
										 |  |  | }() | 
					
						
							| 
									
										
										
										
											2016-08-31 10:22:27 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-06 00:10:32 +08:00
										 |  |  | // Cleans up tmp directory of the local disk.
 | 
					
						
							| 
									
										
										
										
											2022-05-13 06:24:58 +08:00
										 |  |  | func bgFormatErasureCleanupTmp(diskPath string) { | 
					
						
							| 
									
										
										
										
											2021-06-06 00:10:32 +08:00
										 |  |  | 	// Need to move temporary objects left behind from previous run of minio
 | 
					
						
							| 
									
										
										
										
											2021-06-17 07:19:18 +08:00
										 |  |  | 	// server to a unique directory under `minioMetaTmpBucket-old` to clean
 | 
					
						
							| 
									
										
										
										
											2021-06-06 00:10:32 +08:00
										 |  |  | 	// up `minioMetaTmpBucket` for the current run.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2021-06-17 07:19:18 +08:00
										 |  |  | 	// /disk1/.minio.sys/tmp-old/
 | 
					
						
							| 
									
										
										
										
											2021-06-06 00:10:32 +08:00
										 |  |  | 	//  |__ 33a58b40-aecc-4c9f-a22f-ff17bfa33b62
 | 
					
						
							|  |  |  | 	//  |__ e870a2c1-d09c-450c-a69c-6eaa54a89b3e
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// In this example, `33a58b40-aecc-4c9f-a22f-ff17bfa33b62` directory contains
 | 
					
						
							|  |  |  | 	// temporary objects from one of the previous runs of minio server.
 | 
					
						
							| 
									
										
										
										
											2022-01-25 03:28:45 +08:00
										 |  |  | 	tmpID := mustGetUUID() | 
					
						
							|  |  |  | 	tmpOld := pathJoin(diskPath, minioMetaTmpBucket+"-old", tmpID) | 
					
						
							| 
									
										
										
										
											2021-06-06 00:10:32 +08:00
										 |  |  | 	if err := renameAll(pathJoin(diskPath, minioMetaTmpBucket), | 
					
						
							| 
									
										
										
										
											2023-09-13 23:14:36 +08:00
										 |  |  | 		tmpOld, diskPath); err != nil && !errors.Is(err, errFileNotFound) { | 
					
						
							| 
									
										
										
										
											2024-04-04 20:04:40 +08:00
										 |  |  | 		storageLogIf(GlobalContext, fmt.Errorf("unable to rename (%s -> %s) %w, drive may be faulty, please investigate", | 
					
						
							| 
									
										
										
										
											2021-06-06 00:10:32 +08:00
										 |  |  | 			pathJoin(diskPath, minioMetaTmpBucket), | 
					
						
							|  |  |  | 			tmpOld, | 
					
						
							|  |  |  | 			osErrToFileErr(err))) | 
					
						
							| 
									
										
										
										
											2016-11-24 07:48:10 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-01-26 05:33:28 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-13 23:14:36 +08:00
										 |  |  | 	if err := mkdirAll(pathJoin(diskPath, minioMetaTmpDeletedBucket), 0o777, diskPath); err != nil { | 
					
						
							| 
									
										
										
										
											2024-04-04 20:04:40 +08:00
										 |  |  | 		storageLogIf(GlobalContext, fmt.Errorf("unable to create (%s) %w, drive may be faulty, please investigate", | 
					
						
							| 
									
										
										
										
											2021-06-06 00:10:32 +08:00
										 |  |  | 			pathJoin(diskPath, minioMetaTmpBucket), | 
					
						
							|  |  |  | 			err)) | 
					
						
							| 
									
										
										
										
											2018-03-16 04:55:23 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-01-25 03:28:45 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-27 02:31:40 +08:00
										 |  |  | 	// Delete all temporary files created for DirectIO write check
 | 
					
						
							|  |  |  | 	files, _ := filepath.Glob(filepath.Join(diskPath, ".writable-check-*.tmp")) | 
					
						
							|  |  |  | 	for _, file := range files { | 
					
						
							| 
									
										
										
										
											2023-08-02 01:54:26 +08:00
										 |  |  | 		go removeAll(file) | 
					
						
							| 
									
										
										
										
											2023-07-27 02:31:40 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-31 22:27:50 +08:00
										 |  |  | 	// Remove the entire folder in case there are leftovers that didn't get cleaned up before restart.
 | 
					
						
							|  |  |  | 	go removeAll(pathJoin(diskPath, minioMetaTmpBucket+"-old")) | 
					
						
							| 
									
										
										
										
											2023-08-02 01:54:26 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-25 03:28:45 +08:00
										 |  |  | 	// Renames and schedules for purging all bucket metacache.
 | 
					
						
							| 
									
										
										
										
											2022-05-13 06:24:58 +08:00
										 |  |  | 	go renameAllBucketMetacache(diskPath) | 
					
						
							| 
									
										
										
										
											2018-03-16 04:55:23 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-04 12:58:48 +08:00
										 |  |  | // Following error message is added to fix a regression in release
 | 
					
						
							|  |  |  | // RELEASE.2018-03-16T22-52-12Z after migrating v1 to v2 to v3. This
 | 
					
						
							|  |  |  | // migration failed to capture '.This' field properly which indicates
 | 
					
						
							|  |  |  | // the disk UUID association. Below error message is returned when
 | 
					
						
							|  |  |  | // we see this situation in format.json, for more info refer
 | 
					
						
							|  |  |  | // https://github.com/minio/minio/issues/5667
 | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | var errErasureV3ThisEmpty = fmt.Errorf("Erasure format version 3 has This field empty") | 
					
						
							| 
									
										
										
										
											2018-04-04 12:58:48 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-08 11:16:18 +08:00
										 |  |  | // isServerResolvable - checks if the endpoint is resolvable
 | 
					
						
							| 
									
										
										
										
											2020-01-15 10:45:17 +08:00
										 |  |  | // by sending a naked HTTP request with liveness checks.
 | 
					
						
							| 
									
										
										
										
											2021-01-26 02:01:27 +08:00
										 |  |  | func isServerResolvable(endpoint Endpoint, timeout time.Duration) error { | 
					
						
							| 
									
										
										
										
											2020-01-15 10:45:17 +08:00
										 |  |  | 	serverURL := &url.URL{ | 
					
						
							|  |  |  | 		Scheme: endpoint.Scheme, | 
					
						
							|  |  |  | 		Host:   endpoint.Host, | 
					
						
							| 
									
										
										
										
											2020-10-31 03:20:28 +08:00
										 |  |  | 		Path:   pathJoin(healthCheckPathPrefix, healthCheckLivenessPath), | 
					
						
							| 
									
										
										
										
											2020-01-15 10:45:17 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	httpClient := &http.Client{ | 
					
						
							| 
									
										
										
										
											2022-03-18 07:20:10 +08:00
										 |  |  | 		Transport: globalInternodeTransport, | 
					
						
							| 
									
										
										
										
											2020-01-15 10:45:17 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-26 02:01:27 +08:00
										 |  |  | 	ctx, cancel := context.WithTimeout(GlobalContext, timeout) | 
					
						
							| 
									
										
										
										
											2023-05-05 02:28:33 +08:00
										 |  |  | 	defer cancel() | 
					
						
							| 
									
										
										
										
											2020-08-05 05:55:53 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-09 05:22:04 +08:00
										 |  |  | 	req, err := http.NewRequestWithContext(ctx, http.MethodGet, serverURL.String(), nil) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-07-28 16:16:53 +08:00
										 |  |  | 	// Indicate that the liveness check for a peer call
 | 
					
						
							|  |  |  | 	req.Header.Set(xhttp.MinIOPeerCall, "true") | 
					
						
							| 
									
										
										
										
											2023-05-05 02:28:33 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-09 05:22:04 +08:00
										 |  |  | 	resp, err := httpClient.Do(req) | 
					
						
							| 
									
										
										
										
											2020-01-15 10:45:17 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-10-31 03:20:28 +08:00
										 |  |  | 	xhttp.DrainBody(resp.Body) | 
					
						
							| 
									
										
										
										
											2020-01-15 10:45:17 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | // connect to list of endpoints and load all Erasure disk formats, validate the formats are correct
 | 
					
						
							| 
									
										
										
										
											2018-04-04 12:58:48 +08:00
										 |  |  | // and are in quorum, if no formats are found attempt to initialize all of them for the first
 | 
					
						
							|  |  |  | // time. additionally make sure to close all the disks used in this attempt.
 | 
					
						
							| 
									
										
										
										
											2024-05-19 16:06:49 +08:00
										 |  |  | func connectLoadInitFormats(verboseLogging bool, firstDisk bool, storageDisks []StorageAPI, endpoints Endpoints, poolCount, setCount, setDriveCount int, deploymentID string) (format *formatErasureV3, err error) { | 
					
						
							|  |  |  | 	// Attempt to load all `format.json` from all disks.
 | 
					
						
							|  |  |  | 	formatConfigs, sErrs := loadFormatErasureAll(storageDisks, false) | 
					
						
							| 
									
										
										
										
											2020-01-15 10:45:17 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-19 16:06:49 +08:00
										 |  |  | 	if err := checkDiskFatalErrs(sErrs); err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-04-04 09:06:31 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-19 16:06:49 +08:00
										 |  |  | 	for i, err := range sErrs { | 
					
						
							|  |  |  | 		if err != nil && !errors.Is(err, errXLBackend) && !errors.Is(err, errUnformattedDisk) { | 
					
						
							| 
									
										
										
										
											2022-05-31 01:58:37 +08:00
										 |  |  | 			if errors.Is(err, errDiskNotFound) && verboseLogging { | 
					
						
							| 
									
										
										
										
											2022-10-29 05:11:20 +08:00
										 |  |  | 				if globalEndpoints.NEndpoints() > 1 { | 
					
						
							| 
									
										
										
										
											2024-07-13 04:51:54 +08:00
										 |  |  | 					logger.Info("Unable to connect to %s: %v, will be retried", endpoints[i], isServerResolvable(endpoints[i], time.Second)) | 
					
						
							| 
									
										
										
										
											2022-10-29 05:11:20 +08:00
										 |  |  | 				} else { | 
					
						
							|  |  |  | 					logger.Fatal(err, "Unable to connect to %s: %v", endpoints[i], isServerResolvable(endpoints[i], time.Second)) | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2021-05-16 03:56:58 +08:00
										 |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2022-10-29 05:11:20 +08:00
										 |  |  | 				if globalEndpoints.NEndpoints() > 1 { | 
					
						
							| 
									
										
										
										
											2024-07-13 04:51:54 +08:00
										 |  |  | 					logger.Info("Unable to use the drive %s: %v, will be retried", endpoints[i], err) | 
					
						
							| 
									
										
										
										
											2022-10-29 05:11:20 +08:00
										 |  |  | 				} else { | 
					
						
							|  |  |  | 					logger.Fatal(errInvalidArgument, "Unable to use the drive %s: %v", endpoints[i], err) | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2020-01-15 10:45:17 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2019-09-28 07:47:12 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-04-04 12:58:48 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Pre-emptively check if one of the formatted disks
 | 
					
						
							|  |  |  | 	// is invalid. This function returns success for the
 | 
					
						
							|  |  |  | 	// most part unless one of the formats is not consistent
 | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 	// with expected Erasure format. For example if a user is
 | 
					
						
							|  |  |  | 	// trying to pool FS backend into an Erasure set.
 | 
					
						
							| 
									
										
										
										
											2021-01-30 03:40:55 +08:00
										 |  |  | 	if err = checkFormatErasureValues(formatConfigs, storageDisks, setDriveCount); err != nil { | 
					
						
							| 
									
										
										
										
											2024-05-19 16:06:49 +08:00
										 |  |  | 		return nil, err | 
					
						
							| 
									
										
										
										
											2018-04-04 12:58:48 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-13 06:43:38 +08:00
										 |  |  | 	// All disks report unformatted we should initialized everyone.
 | 
					
						
							| 
									
										
										
										
											2024-02-15 02:37:34 +08:00
										 |  |  | 	if shouldInitErasureDisks(sErrs) && firstDisk { | 
					
						
							| 
									
										
										
										
											2021-01-07 01:35:47 +08:00
										 |  |  | 		logger.Info("Formatting %s pool, %v set(s), %v drives per set.", | 
					
						
							|  |  |  | 			humanize.Ordinal(poolCount), setCount, setDriveCount) | 
					
						
							| 
									
										
										
										
											2020-01-18 07:39:07 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-03 01:50:13 +08:00
										 |  |  | 		// Initialize erasure code format on disks
 | 
					
						
							| 
									
										
										
										
											2024-02-12 15:21:56 +08:00
										 |  |  | 		format, err = initFormatErasure(GlobalContext, storageDisks, setCount, setDriveCount, deploymentID, sErrs) | 
					
						
							| 
									
										
										
										
											2019-04-03 01:50:13 +08:00
										 |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2024-05-19 16:06:49 +08:00
										 |  |  | 			return nil, err | 
					
						
							| 
									
										
										
										
											2019-04-03 01:50:13 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-05-14 11:25:29 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-19 16:06:49 +08:00
										 |  |  | 		return format, nil | 
					
						
							| 
									
										
										
										
											2019-12-24 08:31:03 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-15 02:37:34 +08:00
										 |  |  | 	// Return error when quorum unformatted disks - indicating we are
 | 
					
						
							|  |  |  | 	// waiting for first server to be online.
 | 
					
						
							|  |  |  | 	unformattedDisks := quorumUnformattedDisks(sErrs) | 
					
						
							|  |  |  | 	if unformattedDisks && !firstDisk { | 
					
						
							| 
									
										
										
										
											2024-05-19 16:06:49 +08:00
										 |  |  | 		return nil, errNotFirstDisk | 
					
						
							| 
									
										
										
										
											2024-02-15 02:37:34 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Return error when quorum unformatted disks but waiting for rest
 | 
					
						
							|  |  |  | 	// of the servers to be online.
 | 
					
						
							|  |  |  | 	if unformattedDisks && firstDisk { | 
					
						
							| 
									
										
										
										
											2024-05-19 16:06:49 +08:00
										 |  |  | 		return nil, errFirstDiskWait | 
					
						
							| 
									
										
										
										
											2024-02-15 02:37:34 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 	format, err = getFormatErasureInQuorum(formatConfigs) | 
					
						
							| 
									
										
										
										
											2018-04-04 12:58:48 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2024-05-19 16:06:49 +08:00
										 |  |  | 		var drivesNotFound int | 
					
						
							|  |  |  | 		for _, format := range formatConfigs { | 
					
						
							|  |  |  | 			if format != nil { | 
					
						
							|  |  |  | 				continue | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			drivesNotFound++ | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return nil, fmt.Errorf("%w (offline-drives=%d/%d)", err, drivesNotFound, len(formatConfigs)) | 
					
						
							| 
									
										
										
										
											2018-04-04 12:58:48 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-19 11:17:35 +08:00
										 |  |  | 	if format.ID == "" { | 
					
						
							| 
									
										
										
										
											2024-05-19 16:06:49 +08:00
										 |  |  | 		return nil, errors.New("deployment ID missing from disk format, unable to start the server") | 
					
						
							| 
									
										
										
										
											2018-07-19 11:17:35 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-19 16:06:49 +08:00
										 |  |  | 	return format, nil | 
					
						
							| 
									
										
										
										
											2018-04-04 12:58:48 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-16 09:45:57 +08:00
										 |  |  | // Format disks before initialization of object layer.
 | 
					
						
							| 
									
										
										
										
											2024-05-19 16:06:49 +08:00
										 |  |  | func waitForFormatErasure(firstDisk bool, endpoints Endpoints, poolCount, setCount, setDriveCount int, deploymentID string) (storageDisks []StorageAPI, format *formatErasureV3, err error) { | 
					
						
							| 
									
										
										
										
											2020-08-27 10:29:35 +08:00
										 |  |  | 	if len(endpoints) == 0 || setCount == 0 || setDriveCount == 0 { | 
					
						
							| 
									
										
										
										
											2020-03-28 05:48:30 +08:00
										 |  |  | 		return nil, nil, errInvalidArgument | 
					
						
							| 
									
										
										
										
											2016-11-02 23:51:06 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-02-16 09:45:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-08 02:22:00 +08:00
										 |  |  | 	// prepare getElapsedTime() to calculate elapsed time since we started trying formatting disks.
 | 
					
						
							|  |  |  | 	// All times are rounded to avoid showing milli, micro and nano seconds
 | 
					
						
							|  |  |  | 	formatStartTime := time.Now().Round(time.Second) | 
					
						
							|  |  |  | 	getElapsedTime := func() string { | 
					
						
							|  |  |  | 		return time.Now().Round(time.Second).Sub(formatStartTime).String() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-26 04:45:46 +08:00
										 |  |  | 	var ( | 
					
						
							|  |  |  | 		tries   int | 
					
						
							|  |  |  | 		verbose bool | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-19 16:06:49 +08:00
										 |  |  | 	// Initialize all storage disks
 | 
					
						
							|  |  |  | 	storageDisks, errs := initStorageDisksWithErrors(endpoints, storageOpts{cleanUp: true, healthCheck: true}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if err := checkDiskFatalErrs(errs); err != nil { | 
					
						
							|  |  |  | 		return nil, nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	defer func() { | 
					
						
							|  |  |  | 		if err == nil && format != nil { | 
					
						
							|  |  |  | 			// Assign globalDeploymentID() on first run for the
 | 
					
						
							|  |  |  | 			// minio server managing the first disk
 | 
					
						
							|  |  |  | 			globalDeploymentIDPtr.Store(&format.ID) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Set the deployment ID here to avoid races.
 | 
					
						
							|  |  |  | 			xhttp.SetDeploymentID(format.ID) | 
					
						
							|  |  |  | 			xhttp.SetMinIOVersion(Version) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	format, err = connectLoadInitFormats(verbose, firstDisk, storageDisks, endpoints, poolCount, setCount, setDriveCount, deploymentID) | 
					
						
							| 
									
										
										
										
											2022-01-21 05:03:15 +08:00
										 |  |  | 	if err == nil { | 
					
						
							|  |  |  | 		return storageDisks, format, nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tries++ // tried already once
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-09 05:36:54 +08:00
										 |  |  | 	// Wait on each try for an update.
 | 
					
						
							| 
									
										
										
										
											2023-05-12 08:41:33 +08:00
										 |  |  | 	ticker := time.NewTicker(1 * time.Second) | 
					
						
							| 
									
										
										
										
											2020-01-09 05:36:54 +08:00
										 |  |  | 	defer ticker.Stop() | 
					
						
							| 
									
										
										
										
											2022-01-21 05:03:15 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-03 06:27:36 +08:00
										 |  |  | 	for { | 
					
						
							| 
									
										
										
										
											2023-05-12 08:41:33 +08:00
										 |  |  | 		// Only log once every 10 iterations, then reset the tries count.
 | 
					
						
							| 
									
										
										
										
											2024-01-26 04:45:46 +08:00
										 |  |  | 		verbose = tries >= 10 | 
					
						
							|  |  |  | 		if verbose { | 
					
						
							| 
									
										
										
										
											2023-05-12 08:41:33 +08:00
										 |  |  | 			tries = 1 | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-02-05 04:21:21 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-19 16:06:49 +08:00
										 |  |  | 		format, err = connectLoadInitFormats(verbose, firstDisk, storageDisks, endpoints, poolCount, setCount, setDriveCount, deploymentID) | 
					
						
							| 
									
										
										
										
											2023-05-12 08:41:33 +08:00
										 |  |  | 		if err == nil { | 
					
						
							| 
									
										
										
										
											2020-03-28 05:48:30 +08:00
										 |  |  | 			return storageDisks, format, nil | 
					
						
							| 
									
										
										
										
											2023-05-12 08:41:33 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		tries++ | 
					
						
							| 
									
										
										
										
											2024-05-19 16:06:49 +08:00
										 |  |  | 		switch { | 
					
						
							|  |  |  | 		case errors.Is(err, errNotFirstDisk): | 
					
						
							| 
									
										
										
										
											2023-05-12 08:41:33 +08:00
										 |  |  | 			// Fresh setup, wait for first server to be up.
 | 
					
						
							|  |  |  | 			logger.Info("Waiting for the first server to format the drives (elapsed %s)\n", getElapsedTime()) | 
					
						
							| 
									
										
										
										
											2024-05-19 16:06:49 +08:00
										 |  |  | 		case errors.Is(err, errFirstDiskWait): | 
					
						
							| 
									
										
										
										
											2023-05-12 08:41:33 +08:00
										 |  |  | 			// Fresh setup, wait for other servers to come up.
 | 
					
						
							|  |  |  | 			logger.Info("Waiting for all other servers to be online to format the drives (elapses %s)\n", getElapsedTime()) | 
					
						
							| 
									
										
										
										
											2024-05-19 16:06:49 +08:00
										 |  |  | 		case errors.Is(err, errErasureReadQuorum): | 
					
						
							| 
									
										
										
										
											2023-05-12 08:41:33 +08:00
										 |  |  | 			// no quorum available continue to wait for minimum number of servers.
 | 
					
						
							|  |  |  | 			logger.Info("Waiting for a minimum of %d drives to come online (elapsed %s)\n", | 
					
						
							|  |  |  | 				len(endpoints)/2, getElapsedTime()) | 
					
						
							| 
									
										
										
										
											2024-05-19 16:06:49 +08:00
										 |  |  | 		case errors.Is(err, errErasureWriteQuorum): | 
					
						
							| 
									
										
										
										
											2023-05-12 08:41:33 +08:00
										 |  |  | 			// no quorum available continue to wait for minimum number of servers.
 | 
					
						
							|  |  |  | 			logger.Info("Waiting for a minimum of %d drives to come online (elapsed %s)\n", | 
					
						
							|  |  |  | 				(len(endpoints)/2)+1, getElapsedTime()) | 
					
						
							| 
									
										
										
										
											2024-05-19 16:06:49 +08:00
										 |  |  | 		case errors.Is(err, errErasureV3ThisEmpty): | 
					
						
							| 
									
										
										
										
											2023-05-12 08:41:33 +08:00
										 |  |  | 			// need to wait for this error to be healed, so continue.
 | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			// For all other unhandled errors we exit and fail.
 | 
					
						
							|  |  |  | 			return nil, nil, err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		select { | 
					
						
							|  |  |  | 		case <-ticker.C: | 
					
						
							| 
									
										
										
										
											2018-02-07 07:07:17 +08:00
										 |  |  | 		case <-globalOSSignalCh: | 
					
						
							| 
									
										
										
										
											2020-03-28 05:48:30 +08:00
										 |  |  | 			return nil, nil, fmt.Errorf("Initializing data volumes gracefully stopped") | 
					
						
							| 
									
										
										
										
											2016-11-03 06:27:36 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-08-31 10:22:27 +08:00
										 |  |  | } |