| 
									
										
										
										
											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-12-16 14:26:15 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | package cmd | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2017-01-18 02:02:58 +08:00
										 |  |  | 	"bytes" | 
					
						
							| 
									
										
										
										
											2020-04-15 08:52:38 +08:00
										 |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | 	"encoding/json" | 
					
						
							| 
									
										
										
										
											2017-03-18 00:25:49 +08:00
										 |  |  | 	"io" | 
					
						
							| 
									
										
										
										
											2017-01-18 06:25:59 +08:00
										 |  |  | 	"io/ioutil" | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | 	"net/http" | 
					
						
							|  |  |  | 	"net/http/httptest" | 
					
						
							| 
									
										
										
										
											2017-01-04 15:39:22 +08:00
										 |  |  | 	"net/url" | 
					
						
							| 
									
										
										
										
											2018-09-28 08:16:30 +08:00
										 |  |  | 	"sync" | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | 	"testing" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-22 10:23:54 +08:00
										 |  |  | 	"github.com/gorilla/mux" | 
					
						
							| 
									
										
										
										
											2021-05-06 23:52:02 +08:00
										 |  |  | 	"github.com/minio/madmin-go" | 
					
						
							| 
									
										
										
										
											2021-06-02 05:59:40 +08:00
										 |  |  | 	"github.com/minio/minio/internal/auth" | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | // adminErasureTestBed - encapsulates subsystems that need to be setup for
 | 
					
						
							| 
									
										
										
										
											2017-01-23 16:32:55 +08:00
										 |  |  | // admin-handler unit tests.
 | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | type adminErasureTestBed struct { | 
					
						
							|  |  |  | 	erasureDirs []string | 
					
						
							|  |  |  | 	objLayer    ObjectLayer | 
					
						
							|  |  |  | 	router      *mux.Router | 
					
						
							| 
									
										
										
										
											2017-01-23 16:32:55 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | // prepareAdminErasureTestBed - helper function that setups a single-node
 | 
					
						
							|  |  |  | // Erasure backend for admin-handler tests.
 | 
					
						
							|  |  |  | func prepareAdminErasureTestBed(ctx context.Context) (*adminErasureTestBed, error) { | 
					
						
							| 
									
										
										
										
											2020-04-15 08:52:38 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-23 16:32:55 +08:00
										 |  |  | 	// reset global variables to start afresh.
 | 
					
						
							|  |  |  | 	resetTestGlobals() | 
					
						
							| 
									
										
										
										
											2017-02-08 04:51:43 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 	// Set globalIsErasure to indicate that the setup uses an erasure
 | 
					
						
							| 
									
										
										
										
											2020-01-16 10:30:32 +08:00
										 |  |  | 	// code backend.
 | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 	globalIsErasure = true | 
					
						
							| 
									
										
										
										
											2020-01-16 10:30:32 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-23 16:32:55 +08:00
										 |  |  | 	// Initializing objectLayer for HealFormatHandler.
 | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 	objLayer, erasureDirs, xlErr := initTestErasureObjLayer(ctx) | 
					
						
							| 
									
										
										
										
											2017-01-23 16:32:55 +08:00
										 |  |  | 	if xlErr != nil { | 
					
						
							|  |  |  | 		return nil, xlErr | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-15 12:41:47 +08:00
										 |  |  | 	// Initialize minio server config.
 | 
					
						
							|  |  |  | 	if err := newTestConfig(globalMinioDefaultRegion, objLayer); err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-08 16:13:02 +08:00
										 |  |  | 	// Initialize boot time
 | 
					
						
							| 
									
										
										
										
											2017-03-19 02:28:41 +08:00
										 |  |  | 	globalBootTime = UTCNow() | 
					
						
							| 
									
										
										
										
											2017-02-08 16:13:02 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-27 12:47:42 +08:00
										 |  |  | 	globalEndpoints = mustGetPoolEndpoints(erasureDirs...) | 
					
						
							| 
									
										
										
										
											2017-01-23 16:32:55 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-21 01:18:15 +08:00
										 |  |  | 	newAllSubsystems() | 
					
						
							| 
									
										
										
										
											2019-02-12 17:25:52 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-10 10:19:03 +08:00
										 |  |  | 	initAllSubsystems(ctx, objLayer) | 
					
						
							| 
									
										
										
										
											2018-04-25 06:53:30 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-09 23:14:19 +08:00
										 |  |  | 	globalIAMSys.InitStore(objLayer) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-23 16:32:55 +08:00
										 |  |  | 	// Setup admin mgmt REST API handlers.
 | 
					
						
							| 
									
										
										
										
											2018-04-22 10:23:54 +08:00
										 |  |  | 	adminRouter := mux.NewRouter() | 
					
						
							| 
									
										
										
										
											2021-07-10 23:32:52 +08:00
										 |  |  | 	registerAdminRouter(adminRouter, true) | 
					
						
							| 
									
										
										
										
											2017-01-23 16:32:55 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 	return &adminErasureTestBed{ | 
					
						
							|  |  |  | 		erasureDirs: erasureDirs, | 
					
						
							|  |  |  | 		objLayer:    objLayer, | 
					
						
							|  |  |  | 		router:      adminRouter, | 
					
						
							| 
									
										
										
										
											2017-01-23 16:32:55 +08:00
										 |  |  | 	}, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // TearDown - method that resets the test bed for subsequent unit
 | 
					
						
							|  |  |  | // tests to start afresh.
 | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | func (atb *adminErasureTestBed) TearDown() { | 
					
						
							|  |  |  | 	removeRoots(atb.erasureDirs) | 
					
						
							| 
									
										
										
										
											2017-01-23 16:32:55 +08:00
										 |  |  | 	resetTestGlobals() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | // initTestObjLayer - Helper function to initialize an Erasure-based object
 | 
					
						
							| 
									
										
										
										
											2017-01-23 16:32:55 +08:00
										 |  |  | // layer and set globalObjectAPI.
 | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | func initTestErasureObjLayer(ctx context.Context) (ObjectLayer, []string, error) { | 
					
						
							|  |  |  | 	erasureDirs, err := getRandomDisks(16) | 
					
						
							| 
									
										
										
										
											2018-02-16 09:45:57 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-01-27 12:47:42 +08:00
										 |  |  | 	endpoints := mustGetPoolEndpoints(erasureDirs...) | 
					
						
							| 
									
										
										
										
											2018-06-07 03:52:56 +08:00
										 |  |  | 	globalPolicySys = NewPolicySys() | 
					
						
							| 
									
										
										
										
											2021-01-17 04:08:02 +08:00
										 |  |  | 	objLayer, err := newErasureServerPools(ctx, endpoints) | 
					
						
							| 
									
										
										
										
											2018-02-16 09:45:57 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-23 16:32:55 +08:00
										 |  |  | 	// Make objLayer available to all internal services via globalObjectAPI.
 | 
					
						
							|  |  |  | 	globalObjLayerMutex.Lock() | 
					
						
							|  |  |  | 	globalObjectAPI = objLayer | 
					
						
							|  |  |  | 	globalObjLayerMutex.Unlock() | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 	return objLayer, erasureDirs, nil | 
					
						
							| 
									
										
										
										
											2017-01-23 16:32:55 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-04 15:39:22 +08:00
										 |  |  | // cmdType - Represents different service subcomands like status, stop
 | 
					
						
							|  |  |  | // and restart.
 | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | type cmdType int | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const ( | 
					
						
							| 
									
										
										
										
											2019-08-29 06:04:43 +08:00
										 |  |  | 	restartCmd cmdType = iota | 
					
						
							| 
									
										
										
										
											2018-01-23 06:54:55 +08:00
										 |  |  | 	stopCmd | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-04 15:39:22 +08:00
										 |  |  | // toServiceSignal - Helper function that translates a given cmdType
 | 
					
						
							|  |  |  | // value to its corresponding serviceSignal value.
 | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | func (c cmdType) toServiceSignal() serviceSignal { | 
					
						
							|  |  |  | 	switch c { | 
					
						
							|  |  |  | 	case restartCmd: | 
					
						
							|  |  |  | 		return serviceRestart | 
					
						
							| 
									
										
										
										
											2018-01-23 06:54:55 +08:00
										 |  |  | 	case stopCmd: | 
					
						
							|  |  |  | 		return serviceStop | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-08-29 06:04:43 +08:00
										 |  |  | 	return serviceRestart | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-28 02:37:47 +08:00
										 |  |  | func (c cmdType) toServiceAction() madmin.ServiceAction { | 
					
						
							| 
									
										
										
										
											2018-01-23 06:54:55 +08:00
										 |  |  | 	switch c { | 
					
						
							|  |  |  | 	case restartCmd: | 
					
						
							| 
									
										
										
										
											2019-08-28 02:37:47 +08:00
										 |  |  | 		return madmin.ServiceActionRestart | 
					
						
							| 
									
										
										
										
											2018-01-23 06:54:55 +08:00
										 |  |  | 	case stopCmd: | 
					
						
							| 
									
										
										
										
											2019-08-28 02:37:47 +08:00
										 |  |  | 		return madmin.ServiceActionStop | 
					
						
							| 
									
										
										
										
											2018-01-23 06:54:55 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-08-29 06:04:43 +08:00
										 |  |  | 	return madmin.ServiceActionRestart | 
					
						
							| 
									
										
										
										
											2018-01-23 06:54:55 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-04 15:39:22 +08:00
										 |  |  | // testServiceSignalReceiver - Helper function that simulates a
 | 
					
						
							|  |  |  | // go-routine waiting on service signal.
 | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | func testServiceSignalReceiver(cmd cmdType, t *testing.T) { | 
					
						
							|  |  |  | 	expectedCmd := cmd.toServiceSignal() | 
					
						
							|  |  |  | 	serviceCmd := <-globalServiceSignalCh | 
					
						
							|  |  |  | 	if serviceCmd != expectedCmd { | 
					
						
							|  |  |  | 		t.Errorf("Expected service command %v but received %v", expectedCmd, serviceCmd) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-04 15:39:22 +08:00
										 |  |  | // getServiceCmdRequest - Constructs a management REST API request for service
 | 
					
						
							|  |  |  | // subcommands for a given cmdType value.
 | 
					
						
							| 
									
										
										
										
											2019-08-28 02:37:47 +08:00
										 |  |  | func getServiceCmdRequest(cmd cmdType, cred auth.Credentials) (*http.Request, error) { | 
					
						
							|  |  |  | 	queryVal := url.Values{} | 
					
						
							|  |  |  | 	queryVal.Set("action", string(cmd.toServiceAction())) | 
					
						
							| 
									
										
										
										
											2019-11-05 01:30:59 +08:00
										 |  |  | 	resource := adminPathPrefix + adminAPIVersionPrefix + "/service?" + queryVal.Encode() | 
					
						
							| 
									
										
										
										
											2019-08-28 02:37:47 +08:00
										 |  |  | 	req, err := newTestRequest(http.MethodPost, resource, 0, nil) | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-01-04 15:39:22 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// management REST API uses signature V4 for authentication.
 | 
					
						
							| 
									
										
										
										
											2016-12-27 02:21:23 +08:00
										 |  |  | 	err = signRequestV4(req, cred.AccessKey, cred.SecretKey) | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return req, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-04 15:39:22 +08:00
										 |  |  | // testServicesCmdHandler - parametrizes service subcommand tests on
 | 
					
						
							|  |  |  | // cmdType value.
 | 
					
						
							| 
									
										
										
										
											2017-01-25 00:08:36 +08:00
										 |  |  | func testServicesCmdHandler(cmd cmdType, t *testing.T) { | 
					
						
							| 
									
										
										
										
											2020-04-15 08:52:38 +08:00
										 |  |  | 	ctx, cancel := context.WithCancel(context.Background()) | 
					
						
							|  |  |  | 	defer cancel() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 	adminTestBed, err := prepareAdminErasureTestBed(ctx) | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2021-08-04 04:26:57 +08:00
										 |  |  | 		t.Fatal("Failed to initialize a single node Erasure backend for admin handler tests.", err) | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-01-23 16:32:55 +08:00
										 |  |  | 	defer adminTestBed.TearDown() | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-04 15:39:22 +08:00
										 |  |  | 	// Initialize admin peers to make admin RPC calls. Note: In a
 | 
					
						
							|  |  |  | 	// single node setup, this degenerates to a simple function
 | 
					
						
							|  |  |  | 	// call under the hood.
 | 
					
						
							| 
									
										
										
										
											2017-04-12 06:44:27 +08:00
										 |  |  | 	globalMinioAddr = "127.0.0.1:9000" | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-28 08:16:30 +08:00
										 |  |  | 	var wg sync.WaitGroup | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-22 10:23:54 +08:00
										 |  |  | 	// Setting up a go routine to simulate ServerRouter's
 | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | 	// handleServiceSignals for stop and restart commands.
 | 
					
						
							| 
									
										
										
										
											2017-01-18 06:25:59 +08:00
										 |  |  | 	if cmd == restartCmd { | 
					
						
							| 
									
										
										
										
											2018-09-28 08:16:30 +08:00
										 |  |  | 		wg.Add(1) | 
					
						
							|  |  |  | 		go func() { | 
					
						
							|  |  |  | 			defer wg.Done() | 
					
						
							|  |  |  | 			testServiceSignalReceiver(cmd, t) | 
					
						
							|  |  |  | 		}() | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | 	credentials := globalActiveCred | 
					
						
							| 
									
										
										
										
											2018-01-23 06:54:55 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-28 02:37:47 +08:00
										 |  |  | 	req, err := getServiceCmdRequest(cmd, credentials) | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("Failed to build service status request %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-01-18 06:25:59 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	rec := httptest.NewRecorder() | 
					
						
							| 
									
										
										
										
											2018-04-22 10:23:54 +08:00
										 |  |  | 	adminTestBed.router.ServeHTTP(rec, req) | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-28 02:37:47 +08:00
										 |  |  | 	if rec.Code != http.StatusOK { | 
					
						
							|  |  |  | 		resp, _ := ioutil.ReadAll(rec.Body) | 
					
						
							|  |  |  | 		t.Errorf("Expected to receive %d status code but received %d. Body (%s)", | 
					
						
							|  |  |  | 			http.StatusOK, rec.Code, string(resp)) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-28 08:16:30 +08:00
										 |  |  | 	// Wait until testServiceSignalReceiver() called in a goroutine quits.
 | 
					
						
							|  |  |  | 	wg.Wait() | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-04 15:39:22 +08:00
										 |  |  | // Test for service restart management REST API.
 | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | func TestServiceRestartHandler(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2017-01-25 00:08:36 +08:00
										 |  |  | 	testServicesCmdHandler(restartCmd, t) | 
					
						
							| 
									
										
										
										
											2017-01-18 06:25:59 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-18 00:25:49 +08:00
										 |  |  | // buildAdminRequest - helper function to build an admin API request.
 | 
					
						
							| 
									
										
										
										
											2018-01-23 06:54:55 +08:00
										 |  |  | func buildAdminRequest(queryVal url.Values, method, path string, | 
					
						
							| 
									
										
										
										
											2017-03-18 00:25:49 +08:00
										 |  |  | 	contentLength int64, bodySeeker io.ReadSeeker) (*http.Request, error) { | 
					
						
							| 
									
										
										
										
											2018-01-23 06:54:55 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	req, err := newTestRequest(method, | 
					
						
							| 
									
										
										
										
											2019-11-05 01:30:59 +08:00
										 |  |  | 		adminPathPrefix+adminAPIVersionPrefix+path+"?"+queryVal.Encode(), | 
					
						
							| 
									
										
										
										
											2018-01-23 06:54:55 +08:00
										 |  |  | 		contentLength, bodySeeker) | 
					
						
							| 
									
										
										
										
											2017-03-18 00:25:49 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2018-04-06 06:04:40 +08:00
										 |  |  | 		return nil, err | 
					
						
							| 
									
										
										
										
											2017-03-18 00:25:49 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | 	cred := globalActiveCred | 
					
						
							| 
									
										
										
										
											2017-03-18 00:25:49 +08:00
										 |  |  | 	err = signRequestV4(req, cred.AccessKey, cred.SecretKey) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2018-04-06 06:04:40 +08:00
										 |  |  | 		return nil, err | 
					
						
							| 
									
										
										
										
											2017-03-18 00:25:49 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return req, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-07 14:08:33 +08:00
										 |  |  | func TestAdminServerInfo(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2020-04-15 08:52:38 +08:00
										 |  |  | 	ctx, cancel := context.WithCancel(context.Background()) | 
					
						
							|  |  |  | 	defer cancel() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 	adminTestBed, err := prepareAdminErasureTestBed(ctx) | 
					
						
							| 
									
										
										
										
											2017-04-07 14:08:33 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2021-08-04 04:26:57 +08:00
										 |  |  | 		t.Fatal("Failed to initialize a single node Erasure backend for admin handler tests.", err) | 
					
						
							| 
									
										
										
										
											2017-04-07 14:08:33 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-03-03 08:29:30 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-07 14:08:33 +08:00
										 |  |  | 	defer adminTestBed.TearDown() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Initialize admin peers to make admin RPC calls.
 | 
					
						
							| 
									
										
										
										
											2017-04-12 06:44:27 +08:00
										 |  |  | 	globalMinioAddr = "127.0.0.1:9000" | 
					
						
							| 
									
										
										
										
											2017-04-07 14:08:33 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Prepare query params for set-config mgmt REST API.
 | 
					
						
							|  |  |  | 	queryVal := url.Values{} | 
					
						
							|  |  |  | 	queryVal.Set("info", "") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-23 06:54:55 +08:00
										 |  |  | 	req, err := buildAdminRequest(queryVal, http.MethodGet, "/info", 0, nil) | 
					
						
							| 
									
										
										
										
											2017-04-07 14:08:33 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("Failed to construct get-config object request - %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	rec := httptest.NewRecorder() | 
					
						
							| 
									
										
										
										
											2018-04-22 10:23:54 +08:00
										 |  |  | 	adminTestBed.router.ServeHTTP(rec, req) | 
					
						
							| 
									
										
										
										
											2017-04-07 14:08:33 +08:00
										 |  |  | 	if rec.Code != http.StatusOK { | 
					
						
							|  |  |  | 		t.Errorf("Expected to succeed but failed with %d", rec.Code) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-14 03:33:11 +08:00
										 |  |  | 	results := madmin.InfoMessage{} | 
					
						
							| 
									
										
										
										
											2017-04-21 22:15:53 +08:00
										 |  |  | 	err = json.NewDecoder(rec.Body).Decode(&results) | 
					
						
							| 
									
										
										
										
											2017-04-07 14:08:33 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("Failed to decode set config result json %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-14 03:33:11 +08:00
										 |  |  | 	if results.Region != globalMinioDefaultRegion { | 
					
						
							|  |  |  | 		t.Errorf("Expected %s, got %s", globalMinioDefaultRegion, results.Region) | 
					
						
							| 
									
										
										
										
											2017-04-07 14:08:33 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-12 17:25:52 +08:00
										 |  |  | // TestToAdminAPIErrCode - test for toAdminAPIErrCode helper function.
 | 
					
						
							|  |  |  | func TestToAdminAPIErrCode(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2017-02-28 03:40:27 +08:00
										 |  |  | 	testCases := []struct { | 
					
						
							|  |  |  | 		err            error | 
					
						
							|  |  |  | 		expectedAPIErr APIErrorCode | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		// 1. Server not in quorum.
 | 
					
						
							|  |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 			err:            errErasureWriteQuorum, | 
					
						
							| 
									
										
										
										
											2017-02-28 03:40:27 +08:00
										 |  |  | 			expectedAPIErr: ErrAdminConfigNoQuorum, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		// 2. No error.
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			err:            nil, | 
					
						
							|  |  |  | 			expectedAPIErr: ErrNone, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		// 3. Non-admin API specific error.
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			err:            errDiskNotFound, | 
					
						
							| 
									
										
										
										
											2020-04-10 00:30:02 +08:00
										 |  |  | 			expectedAPIErr: toAPIErrorCode(GlobalContext, errDiskNotFound), | 
					
						
							| 
									
										
										
										
											2017-02-28 03:40:27 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for i, test := range testCases { | 
					
						
							| 
									
										
										
										
											2020-04-10 00:30:02 +08:00
										 |  |  | 		actualErr := toAdminAPIErrCode(GlobalContext, test.err) | 
					
						
							| 
									
										
										
										
											2017-02-28 03:40:27 +08:00
										 |  |  | 		if actualErr != test.expectedAPIErr { | 
					
						
							|  |  |  | 			t.Errorf("Test %d: Expected %v but received %v", | 
					
						
							|  |  |  | 				i+1, test.expectedAPIErr, actualErr) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-08-30 04:53:27 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | func TestExtractHealInitParams(t *testing.T) { | 
					
						
							|  |  |  | 	mkParams := func(clientToken string, forceStart, forceStop bool) url.Values { | 
					
						
							|  |  |  | 		v := url.Values{} | 
					
						
							|  |  |  | 		if clientToken != "" { | 
					
						
							| 
									
										
										
										
											2020-09-24 23:40:21 +08:00
										 |  |  | 			v.Add(mgmtClientToken, clientToken) | 
					
						
							| 
									
										
										
										
											2019-08-30 04:53:27 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		if forceStart { | 
					
						
							| 
									
										
										
										
											2020-09-24 23:40:21 +08:00
										 |  |  | 			v.Add(mgmtForceStart, "") | 
					
						
							| 
									
										
										
										
											2019-08-30 04:53:27 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		if forceStop { | 
					
						
							| 
									
										
										
										
											2020-09-24 23:40:21 +08:00
										 |  |  | 			v.Add(mgmtForceStop, "") | 
					
						
							| 
									
										
										
										
											2019-08-30 04:53:27 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		return v | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	qParmsArr := []url.Values{ | 
					
						
							|  |  |  | 		// Invalid cases
 | 
					
						
							|  |  |  | 		mkParams("", true, true), | 
					
						
							|  |  |  | 		mkParams("111", true, true), | 
					
						
							|  |  |  | 		mkParams("111", true, false), | 
					
						
							|  |  |  | 		mkParams("111", false, true), | 
					
						
							|  |  |  | 		// Valid cases follow
 | 
					
						
							|  |  |  | 		mkParams("", true, false), | 
					
						
							|  |  |  | 		mkParams("", false, true), | 
					
						
							|  |  |  | 		mkParams("", false, false), | 
					
						
							|  |  |  | 		mkParams("111", false, false), | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	varsArr := []map[string]string{ | 
					
						
							|  |  |  | 		// Invalid cases
 | 
					
						
							| 
									
										
										
										
											2020-09-24 23:40:21 +08:00
										 |  |  | 		{mgmtPrefix: "objprefix"}, | 
					
						
							| 
									
										
										
										
											2019-08-30 04:53:27 +08:00
										 |  |  | 		// Valid cases
 | 
					
						
							|  |  |  | 		{}, | 
					
						
							| 
									
										
										
										
											2020-09-24 23:40:21 +08:00
										 |  |  | 		{mgmtBucket: "bucket"}, | 
					
						
							|  |  |  | 		{mgmtBucket: "bucket", mgmtPrefix: "objprefix"}, | 
					
						
							| 
									
										
										
										
											2019-08-30 04:53:27 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Body is always valid - we do not test JSON decoding.
 | 
					
						
							|  |  |  | 	body := `{"recursive": false, "dryRun": true, "remove": false, "scanMode": 0}` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Test all combinations!
 | 
					
						
							|  |  |  | 	for pIdx, parms := range qParmsArr { | 
					
						
							|  |  |  | 		for vIdx, vars := range varsArr { | 
					
						
							| 
									
										
										
										
											2020-12-27 14:58:06 +08:00
										 |  |  | 			_, err := extractHealInitParams(vars, parms, bytes.NewReader([]byte(body))) | 
					
						
							| 
									
										
										
										
											2019-08-30 04:53:27 +08:00
										 |  |  | 			isErrCase := false | 
					
						
							|  |  |  | 			if pIdx < 4 || vIdx < 1 { | 
					
						
							|  |  |  | 				isErrCase = true | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if err != ErrNone && !isErrCase { | 
					
						
							|  |  |  | 				t.Errorf("Got unexpected error: %v %v %v", pIdx, vIdx, err) | 
					
						
							|  |  |  | 			} else if err == ErrNone && isErrCase { | 
					
						
							|  |  |  | 				t.Errorf("Got no error but expected one: %v %v", pIdx, vIdx) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } |