| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | /* | 
					
						
							| 
									
										
										
										
											2019-08-28 02:37:47 +08:00
										 |  |  |  * MinIO Cloud Storage, (C) 2016-2019 MinIO, Inc. | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
					
						
							|  |  |  |  * you may not use this file except in compliance with the License. | 
					
						
							|  |  |  |  * You may obtain a copy of the License at | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *     http://www.apache.org/licenses/LICENSE-2.0
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Unless required by applicable law or agreed to in writing, software | 
					
						
							|  |  |  |  * distributed under the License is distributed on an "AS IS" BASIS, | 
					
						
							|  |  |  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
					
						
							|  |  |  |  * See the License for the specific language governing permissions and | 
					
						
							|  |  |  |  * limitations under the License. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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" | 
					
						
							| 
									
										
										
										
											2017-11-01 02:54:32 +08:00
										 |  |  | 	"github.com/minio/minio/pkg/auth" | 
					
						
							| 
									
										
										
										
											2018-01-23 06:54:55 +08:00
										 |  |  | 	"github.com/minio/minio/pkg/madmin" | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 	globalEndpoints = mustGetZoneEndpoints(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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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() | 
					
						
							| 
									
										
										
										
											2020-05-25 15:17:52 +08:00
										 |  |  | 	registerAdminRouter(adminRouter, true, 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 | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 	endpoints := mustGetNewEndpoints(erasureDirs...) | 
					
						
							|  |  |  | 	storageDisks, format, err := waitForFormatErasure(true, endpoints, 1, 1, 16, "") | 
					
						
							| 
									
										
										
										
											2018-02-16 09:45:57 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 		removeRoots(erasureDirs) | 
					
						
							| 
									
										
										
										
											2018-02-16 09:45:57 +08:00
										 |  |  | 		return nil, nil, err | 
					
						
							| 
									
										
										
										
											2017-01-23 16:32:55 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-02-16 09:45:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-07 03:52:56 +08:00
										 |  |  | 	globalPolicySys = NewPolicySys() | 
					
						
							| 
									
										
										
										
											2020-12-02 05:50:33 +08:00
										 |  |  | 	objLayer := &erasureServerPools{serverPools: make([]*erasureSets, 1)} | 
					
						
							|  |  |  | 	objLayer.serverPools[0], err = newErasureSets(ctx, endpoints, storageDisks, format) | 
					
						
							| 
									
										
										
										
											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 { | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 		t.Fatal("Failed to initialize a single node Erasure backend for admin handler tests.") | 
					
						
							| 
									
										
										
										
											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 { | 
					
						
							| 
									
										
										
										
											2020-06-13 11:04:01 +08:00
										 |  |  | 		t.Fatal("Failed to initialize a single node Erasure backend for admin handler tests.") | 
					
						
							| 
									
										
										
										
											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) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } |