Add madmin package context support (#9172)

This is to improve responsiveness for all
admin API operations and allowing callers
to cancel any on-going admin operations,
if they happen to be waiting too long.
This commit is contained in:
Harshavardhana 2020-03-20 15:00:44 -07:00 committed by GitHub
parent 1ffa983a9d
commit ae654831aa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
47 changed files with 398 additions and 213 deletions

View File

@ -1436,7 +1436,7 @@ func (a adminAPIHandlers) ServerInfoHandler(w http.ResponseWriter, r *http.Reque
OffDisks += v
}
backend = madmin.XlBackend{
backend = madmin.XLBackend{
Type: madmin.ErasureType,
OnlineDisks: OnDisks,
OfflineDisks: OffDisks,
@ -1446,7 +1446,7 @@ func (a adminAPIHandlers) ServerInfoHandler(w http.ResponseWriter, r *http.Reque
RRSCParity: storageInfo.Backend.RRSCParity,
}
} else {
backend = madmin.FsBackend{
backend = madmin.FSBackend{
Type: madmin.FsType,
}
}

View File

@ -118,12 +118,12 @@ func (sys *HTTPConsoleLoggerSys) Subscribe(subCh chan interface{}, doneCh chan s
// Send log message 'e' to console and publish to console
// log pubsub system
func (sys *HTTPConsoleLoggerSys) Send(e interface{}, logKind string) error {
var lg madmin.LogInfo
var lg log.Info
switch e := e.(type) {
case log.Entry:
lg = madmin.LogInfo{Entry: e, NodeName: sys.nodeName}
lg = log.Info{Entry: e, NodeName: sys.nodeName}
case string:
lg = madmin.LogInfo{ConsoleMsg: e, NodeName: sys.nodeName}
lg = log.Info{ConsoleMsg: e, NodeName: sys.nodeName}
}
sys.pubsub.Publish(lg)

View File

@ -50,3 +50,11 @@ type Entry struct {
Message string `json:"message,omitempty"`
Trace *Trace `json:"error,omitempty"`
}
// Info holds console log messages
type Info struct {
Entry
ConsoleMsg string
NodeName string `json:"node"`
Err error `json:"-"`
}

View File

@ -0,0 +1,52 @@
/*
* MinIO Cloud Storage, (C) 2020 MinIO, Inc.
*
* 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 madmin
// Args - defines the arguments for the API.
type logArgs struct {
Bucket string `json:"bucket,omitempty"`
Object string `json:"object,omitempty"`
Metadata map[string]string `json:"metadata,omitempty"`
}
// Trace - defines the trace.
type logTrace struct {
Message string `json:"message,omitempty"`
Source []string `json:"source,omitempty"`
Variables map[string]string `json:"variables,omitempty"`
}
// API - defines the api type and its args.
type logAPI struct {
Name string `json:"name,omitempty"`
Args *logArgs `json:"args,omitempty"`
}
// Entry - defines fields and values of each log entry.
type logEntry struct {
DeploymentID string `json:"deploymentid,omitempty"`
Level string `json:"level"`
LogKind string `json:"errKind"`
Time string `json:"time"`
API *logAPI `json:"api,omitempty"`
RemoteHost string `json:"remotehost,omitempty"`
Host string `json:"host,omitempty"`
RequestID string `json:"requestID,omitempty"`
UserAgent string `json:"userAgent,omitempty"`
Message string `json:"message,omitempty"`
Trace *logTrace `json:"error,omitempty"`
}

View File

@ -17,18 +17,17 @@
package madmin
import (
"context"
"encoding/json"
"net/http"
"net/url"
"strconv"
"strings"
"github.com/minio/minio/cmd/logger/message/log"
)
// LogInfo holds console log messages
type LogInfo struct {
log.Entry
logEntry
ConsoleMsg string
NodeName string `json:"node"`
Err error `json:"-"`
@ -42,7 +41,7 @@ func (l LogInfo) SendLog(node, logKind string) bool {
}
// GetLogs - listen on console log messages.
func (adm AdminClient) GetLogs(node string, lineCnt int, logKind string, doneCh <-chan struct{}) <-chan LogInfo {
func (adm AdminClient) GetLogs(ctx context.Context, node string, lineCnt int, logKind string) <-chan LogInfo {
logCh := make(chan LogInfo, 1)
// Only success, start a routine to start reading line by line.
@ -58,7 +57,7 @@ func (adm AdminClient) GetLogs(node string, lineCnt int, logKind string, doneCh
queryValues: urlValues,
}
// Execute GET to call log handler
resp, err := adm.executeMethod("GET", reqData)
resp, err := adm.executeMethod(ctx, http.MethodGet, reqData)
if err != nil {
closeResponse(resp)
return
@ -75,7 +74,7 @@ func (adm AdminClient) GetLogs(node string, lineCnt int, logKind string, doneCh
break
}
select {
case <-doneCh:
case <-ctx.Done():
return
case logCh <- info:
}

View File

@ -18,7 +18,9 @@ package madmin
import (
"bytes"
"context"
"encoding/hex"
"errors"
"fmt"
"io"
"io/ioutil"
@ -109,7 +111,7 @@ func privateNew(endpoint, accessKeyID, secretAccessKey string, secure bool) (*Ad
endpointURL: *endpointURL,
// Instantiate http client and bucket location cache.
httpClient: &http.Client{
Transport: http.DefaultTransport,
Transport: DefaultTransport(secure),
},
// Introduce a new locked random seed.
random: rand.New(&lockedRandSource{src: rand.NewSource(time.Now().UTC().UnixNano())}),
@ -263,38 +265,19 @@ func (adm AdminClient) dumpHTTP(req *http.Request, resp *http.Response) error {
// do - execute http request.
func (adm AdminClient) do(req *http.Request) (*http.Response, error) {
var resp *http.Response
var err error
// Do the request in a loop in case of 307 http is met since golang still doesn't
// handle properly this situation (https://github.com/golang/go/issues/7912)
for {
resp, err = adm.httpClient.Do(req)
if err != nil {
// Close idle connections upon error.
adm.httpClient.CloseIdleConnections()
// Handle this specifically for now until future Golang
// versions fix this issue properly.
urlErr, ok := err.(*url.Error)
if ok && strings.Contains(urlErr.Err.Error(), "EOF") {
resp, err := adm.httpClient.Do(req)
if err != nil {
// Handle this specifically for now until future Golang versions fix this issue properly.
if urlErr, ok := err.(*url.Error); ok {
if strings.Contains(urlErr.Err.Error(), "EOF") {
return nil, &url.Error{
Op: urlErr.Op,
URL: urlErr.URL,
Err: fmt.Errorf("Connection closed by foreign host %s", urlErr.URL),
Err: errors.New("Connection closed by foreign host " + urlErr.URL + ". Retry again."),
}
}
return nil, err
}
// Redo the request with the new redirect url if http 307 is returned, quit the loop otherwise
if resp != nil && resp.StatusCode == http.StatusTemporaryRedirect {
newURL, uErr := url.Parse(resp.Header.Get("Location"))
if uErr != nil {
break
}
req.URL = newURL
} else {
break
}
return nil, err
}
// Response cannot be non-nil, report if its the case.
@ -323,16 +306,23 @@ var successStatus = []int{
// executeMethod - instantiates a given method, and retries the
// request upon any error up to maxRetries attempts in a binomially
// delayed manner using a standard back off algorithm.
func (adm AdminClient) executeMethod(method string, reqData requestData) (res *http.Response, err error) {
func (adm AdminClient) executeMethod(ctx context.Context, method string, reqData requestData) (res *http.Response, err error) {
var reqRetry = MaxRetry // Indicates how many times we can retry the request
// Create a done channel to control 'ListObjects' go routine.
doneCh := make(chan struct{}, 1)
defer func() {
if err != nil {
// close idle connections before returning, upon error.
adm.httpClient.CloseIdleConnections()
}
}()
// Create cancel context to control 'newRetryTimer' go routine.
retryCtx, cancel := context.WithCancel(ctx)
// Indicate to our routine to exit cleanly upon return.
defer close(doneCh)
defer cancel()
for range adm.newRetryTimer(reqRetry, DefaultRetryUnit, DefaultRetryCap, MaxJitter, doneCh) {
for range adm.newRetryTimer(retryCtx, reqRetry, DefaultRetryUnit, DefaultRetryCap, MaxJitter) {
// Instantiate a new request.
var req *http.Request
req, err = adm.newRequest(method, reqData)
@ -340,6 +330,9 @@ func (adm AdminClient) executeMethod(method string, reqData requestData) (res *h
return nil, err
}
// Add context to request
req = req.WithContext(ctx)
// Initiate the request.
res, err = adm.do(req)
if err != nil {

View File

@ -19,14 +19,16 @@ package madmin
import (
"bytes"
"context"
"io"
"net/http"
)
// GetConfig - returns the config.json of a minio setup, incoming data is encrypted.
func (adm *AdminClient) GetConfig() ([]byte, error) {
func (adm *AdminClient) GetConfig(ctx context.Context) ([]byte, error) {
// Execute GET on /minio/admin/v2/config to get config of a setup.
resp, err := adm.executeMethod(http.MethodGet,
resp, err := adm.executeMethod(ctx,
http.MethodGet,
requestData{relPath: adminAPIPrefix + "/config"})
defer closeResponse(resp)
if err != nil {
@ -41,7 +43,7 @@ func (adm *AdminClient) GetConfig() ([]byte, error) {
}
// SetConfig - set config supplied as config.json for the setup.
func (adm *AdminClient) SetConfig(config io.Reader) (err error) {
func (adm *AdminClient) SetConfig(ctx context.Context, config io.Reader) (err error) {
const maxConfigJSONSize = 256 * 1024 // 256KiB
// Read configuration bytes
@ -65,7 +67,7 @@ func (adm *AdminClient) SetConfig(config io.Reader) (err error) {
}
// Execute PUT on /minio/admin/v2/config to set config.
resp, err := adm.executeMethod(http.MethodPut, reqData)
resp, err := adm.executeMethod(ctx, http.MethodPut, reqData)
defer closeResponse(resp)
if err != nil {

View File

@ -18,6 +18,7 @@
package madmin
import (
"context"
"encoding/json"
"net/http"
"net/url"
@ -45,7 +46,7 @@ type HelpKV struct {
type HelpKVS []HelpKV
// HelpConfigKV - return help for a given sub-system.
func (adm *AdminClient) HelpConfigKV(subSys, key string, envOnly bool) (Help, error) {
func (adm *AdminClient) HelpConfigKV(ctx context.Context, subSys, key string, envOnly bool) (Help, error) {
v := url.Values{}
v.Set("subSys", subSys)
v.Set("key", key)
@ -59,7 +60,7 @@ func (adm *AdminClient) HelpConfigKV(subSys, key string, envOnly bool) (Help, er
}
// Execute GET on /minio/admin/v2/help-config-kv
resp, err := adm.executeMethod(http.MethodGet, reqData)
resp, err := adm.executeMethod(ctx, http.MethodGet, reqData)
if err != nil {
return Help{}, err
}

View File

@ -18,6 +18,7 @@
package madmin
import (
"context"
"encoding/json"
"net/http"
"net/url"
@ -28,7 +29,7 @@ import (
// ClearConfigHistoryKV - clears the config entry represented by restoreID.
// optionally allows setting `all` as a special keyword to automatically
// erase all config set history entires.
func (adm *AdminClient) ClearConfigHistoryKV(restoreID string) (err error) {
func (adm *AdminClient) ClearConfigHistoryKV(ctx context.Context, restoreID string) (err error) {
v := url.Values{}
v.Set("restoreId", restoreID)
reqData := requestData{
@ -37,7 +38,7 @@ func (adm *AdminClient) ClearConfigHistoryKV(restoreID string) (err error) {
}
// Execute DELETE on /minio/admin/v2/clear-config-history-kv
resp, err := adm.executeMethod(http.MethodDelete, reqData)
resp, err := adm.executeMethod(ctx, http.MethodDelete, reqData)
defer closeResponse(resp)
if err != nil {
@ -53,7 +54,7 @@ func (adm *AdminClient) ClearConfigHistoryKV(restoreID string) (err error) {
// RestoreConfigHistoryKV - Restore a previous config set history.
// Input is a unique id which represents the previous setting.
func (adm *AdminClient) RestoreConfigHistoryKV(restoreID string) (err error) {
func (adm *AdminClient) RestoreConfigHistoryKV(ctx context.Context, restoreID string) (err error) {
v := url.Values{}
v.Set("restoreId", restoreID)
reqData := requestData{
@ -62,7 +63,7 @@ func (adm *AdminClient) RestoreConfigHistoryKV(restoreID string) (err error) {
}
// Execute PUT on /minio/admin/v2/set-config-kv to set config key/value.
resp, err := adm.executeMethod(http.MethodPut, reqData)
resp, err := adm.executeMethod(ctx, http.MethodPut, reqData)
defer closeResponse(resp)
if err != nil {
@ -90,7 +91,7 @@ func (ch ConfigHistoryEntry) CreateTimeFormatted() string {
}
// ListConfigHistoryKV - lists a slice of ConfigHistoryEntries sorted by createTime.
func (adm *AdminClient) ListConfigHistoryKV(count int) ([]ConfigHistoryEntry, error) {
func (adm *AdminClient) ListConfigHistoryKV(ctx context.Context, count int) ([]ConfigHistoryEntry, error) {
if count == 0 {
count = 10
}
@ -98,7 +99,8 @@ func (adm *AdminClient) ListConfigHistoryKV(count int) ([]ConfigHistoryEntry, er
v.Set("count", strconv.Itoa(count))
// Execute GET on /minio/admin/v2/list-config-history-kv
resp, err := adm.executeMethod(http.MethodGet,
resp, err := adm.executeMethod(ctx,
http.MethodGet,
requestData{
relPath: adminAPIPrefix + "/list-config-history-kv",
queryValues: v,

View File

@ -18,12 +18,13 @@
package madmin
import (
"context"
"net/http"
"net/url"
)
// DelConfigKV - delete key from server config.
func (adm *AdminClient) DelConfigKV(k string) (err error) {
func (adm *AdminClient) DelConfigKV(ctx context.Context, k string) (err error) {
econfigBytes, err := EncryptData(adm.secretAccessKey, []byte(k))
if err != nil {
return err
@ -35,7 +36,7 @@ func (adm *AdminClient) DelConfigKV(k string) (err error) {
}
// Execute DELETE on /minio/admin/v2/del-config-kv to delete config key.
resp, err := adm.executeMethod(http.MethodDelete, reqData)
resp, err := adm.executeMethod(ctx, http.MethodDelete, reqData)
defer closeResponse(resp)
if err != nil {
@ -50,7 +51,7 @@ func (adm *AdminClient) DelConfigKV(k string) (err error) {
}
// SetConfigKV - set key value config to server.
func (adm *AdminClient) SetConfigKV(kv string) (err error) {
func (adm *AdminClient) SetConfigKV(ctx context.Context, kv string) (err error) {
econfigBytes, err := EncryptData(adm.secretAccessKey, []byte(kv))
if err != nil {
return err
@ -62,7 +63,7 @@ func (adm *AdminClient) SetConfigKV(kv string) (err error) {
}
// Execute PUT on /minio/admin/v2/set-config-kv to set config key/value.
resp, err := adm.executeMethod(http.MethodPut, reqData)
resp, err := adm.executeMethod(ctx, http.MethodPut, reqData)
defer closeResponse(resp)
if err != nil {
@ -77,12 +78,13 @@ func (adm *AdminClient) SetConfigKV(kv string) (err error) {
}
// GetConfigKV - returns the key, value of the requested key, incoming data is encrypted.
func (adm *AdminClient) GetConfigKV(key string) (Targets, error) {
func (adm *AdminClient) GetConfigKV(ctx context.Context, key string) (Targets, error) {
v := url.Values{}
v.Set("key", key)
// Execute GET on /minio/admin/v2/get-config-kv?key={key} to get value of key.
resp, err := adm.executeMethod(http.MethodGet,
resp, err := adm.executeMethod(ctx,
http.MethodGet,
requestData{
relPath: adminAPIPrefix + "/get-config-kv",
queryValues: v,

View File

@ -20,6 +20,7 @@
package main
import (
"context"
"log"
"github.com/minio/minio/pkg/madmin"
@ -36,7 +37,7 @@ func main() {
log.Fatalln(err)
}
accountingUsageInfo, err := madmClnt.AccountingUsageInfo()
accountingUsageInfo, err := madmClnt.AccountingUsageInfo(context.Background())
if err != nil {
log.Fatalln(err)
}

View File

@ -20,6 +20,7 @@
package main
import (
"context"
"fmt"
"log"
@ -43,7 +44,7 @@ func main() {
// Create policy
policy := `{"Version": "2012-10-17","Statement": [{"Action": ["s3:GetObject"],"Effect": "Allow","Resource": ["arn:aws:s3:::testbucket/*"],"Sid": ""}]}`
creds, err := madmClnt.AddServiceAccount("parentuser", policy)
creds, err := madmClnt.AddServiceAccount(context.Background(), "parentuser", policy)
if err != nil {
log.Fatalln(err)
}

View File

@ -20,6 +20,7 @@
package main
import (
"context"
"log"
"github.com/minio/minio/pkg/madmin"
@ -39,18 +40,18 @@ func main() {
log.Fatalln(err)
}
if err = madmClnt.AddUser("newuser", "newstrongpassword"); err != nil {
if err = madmClnt.AddUser(context.Background(), "newuser", "newstrongpassword"); err != nil {
log.Fatalln(err)
}
// Create policy
policy := `{"Version": "2012-10-17","Statement": [{"Action": ["s3:GetObject"],"Effect": "Allow","Resource": ["arn:aws:s3:::my-bucketname/*"],"Sid": ""}]}`
if err = madmClnt.AddCannedPolicy("get-only", policy); err != nil {
if err = madmClnt.AddCannedPolicy(context.Background(), "get-only", policy); err != nil {
log.Fatalln(err)
}
if err = madmClnt.SetUserPolicy("newuser", "get-only"); err != nil {
if err = madmClnt.SetUserPolicy(context.Background(), "newuser", "get-only"); err != nil {
log.Fatalln(err)
}
}

View File

@ -20,6 +20,7 @@
package main
import (
"context"
"log"
"github.com/minio/minio/pkg/madmin"
@ -36,7 +37,7 @@ func main() {
log.Fatalln(err)
}
st, err := madmClnt.ServerCPULoadInfo()
st, err := madmClnt.ServerCPULoadInfo(context.Background())
if err != nil {
log.Fatalln(err)
}

View File

@ -20,6 +20,7 @@
package main
import (
"context"
"log"
"github.com/minio/minio/pkg/madmin"
@ -36,7 +37,7 @@ func main() {
log.Fatalln(err)
}
dataUsageInfo, err := madmClnt.DataUsageInfo()
dataUsageInfo, err := madmClnt.DataUsageInfo(context.Background())
if err != nil {
log.Fatalln(err)
}

View File

@ -20,6 +20,7 @@
package main
import (
"context"
"log"
"github.com/minio/minio/pkg/madmin"
@ -36,7 +37,7 @@ func main() {
log.Fatalln(err)
}
st, err := madmClnt.ServerDrivesPerfInfo(madmin.DefaultDrivePerfSize)
st, err := madmClnt.ServerDrivesPerfInfo(context.Background(), madmin.DefaultDrivePerfSize)
if err != nil {
log.Fatalln(err)
}

View File

@ -20,6 +20,7 @@
package main
import (
"context"
"fmt"
"log"
@ -40,7 +41,7 @@ func main() {
log.Fatalln(err)
}
creds, err := madmClnt.GetServiceAccount("service-account-access-key")
creds, err := madmClnt.GetServiceAccount(context.Background(), "service-account-access-key")
if err != nil {
log.Fatalln(err)
}

View File

@ -20,6 +20,7 @@
package main
import (
"context"
"log"
"github.com/minio/minio/pkg/madmin"
@ -38,7 +39,7 @@ func main() {
// Heal bucket mybucket - dry run
isDryRun := true
err = madmClnt.HealBucket("mybucket", isDryRun)
err = madmClnt.HealBucket(context.Background(), "mybucket", isDryRun)
if err != nil {
log.Fatalln(err)
@ -46,7 +47,7 @@ func main() {
// Heal bucket mybucket - for real this time.
isDryRun := false
err = madmClnt.HealBucket("mybucket", isDryRun)
err = madmClnt.HealBucket(context.Background(), "mybucket", isDryRun)
if err != nil {
log.Fatalln(err)
}

View File

@ -20,6 +20,7 @@ package main
*/
import (
"context"
"fmt"
"log"
@ -39,7 +40,7 @@ func main() {
}
// List buckets that need healing
healBucketsList, err := madmClnt.ListBucketsHeal()
healBucketsList, err := madmClnt.ListBucketsHeal(context.Background())
if err != nil {
log.Fatalln(err)
}

View File

@ -20,6 +20,7 @@
package main
import (
"context"
"log"
"github.com/minio/minio/pkg/madmin"
@ -41,14 +42,14 @@ func main() {
// Attempt healing format in dry-run mode.
isDryRun := true
err = madmClnt.HealFormat(isDryRun)
err = madmClnt.HealFormat(context.Background(), isDryRun)
if err != nil {
log.Fatalln(err)
}
// Perform actual healing of format.
isDryRun = false
err = madmClnt.HealFormat(isDryRun)
err = madmClnt.HealFormat(context.Background(), isDryRun)
if err != nil {
log.Fatalln(err)
}

View File

@ -20,6 +20,7 @@
package main
import (
"context"
"log"
"github.com/minio/minio/pkg/madmin"
@ -41,14 +42,14 @@ func main() {
// Heal object mybucket/myobject - dry run.
isDryRun := true
_, err = madmClnt.HealObject("mybucket", "myobject", isDryRun)
_, err = madmClnt.HealObject(context.Background(), "mybucket", "myobject", isDryRun)
if err != nil {
log.Fatalln(err)
}
// Heal object mybucket/myobject - this time for real.
isDryRun = false
healResult, err := madmClnt.HealObject("mybucket", "myobject", isDryRun)
healResult, err := madmClnt.HealObject(context.Background(), "mybucket", "myobject", isDryRun)
if err != nil {
log.Fatalln(err)
}

View File

@ -20,6 +20,7 @@
package main
import (
"context"
"log"
"github.com/minio/minio/pkg/madmin"
@ -36,7 +37,7 @@ func main() {
log.Fatalln(err)
}
healStatusResult, err := madmClnt.BackgroundHealStatus()
healStatusResult, err := madmClnt.BackgroundHealStatus(context.Background())
if err != nil {
log.Fatalln(err)
}

View File

@ -20,6 +20,7 @@
package main
import (
"context"
"log"
"github.com/minio/minio/pkg/madmin"
@ -35,7 +36,7 @@ func main() {
if err != nil {
log.Fatalln(err)
}
st, err := madmClnt.ServerCPUHardwareInfo()
st, err := madmClnt.ServerCPUHardwareInfo(context.Background())
if err != nil {
log.Fatalln(err)
}

View File

@ -20,6 +20,7 @@
package main
import (
"context"
"log"
"github.com/minio/minio/pkg/madmin"
@ -35,7 +36,7 @@ func main() {
if err != nil {
log.Fatalln(err)
}
st, err := madmClnt.ServerNetworkHardwareInfo()
st, err := madmClnt.ServerNetworkHardwareInfo(context.Background())
if err != nil {
log.Fatalln(err)
}

View File

@ -20,6 +20,7 @@
package main
import (
"context"
"log"
"github.com/minio/minio/pkg/madmin"
@ -36,7 +37,7 @@ func main() {
log.Fatalln(err)
}
status, err := madmClnt.GetKeyStatus("") // empty string refers to the default master key
status, err := madmClnt.GetKeyStatus(context.Background(), "") // empty string refers to the default master key
if err != nil {
log.Fatalln(err)
}

View File

@ -20,6 +20,7 @@
package main
import (
"context"
"log"
"time"
@ -39,7 +40,7 @@ func main() {
// Clear locks held on mybucket/myprefix for longer than 30s.
olderThan := time.Duration(30 * time.Second)
locksCleared, err := madmClnt.ClearLocks("mybucket", "myprefix", olderThan)
locksCleared, err := madmClnt.ClearLocks(context.Background(), "mybucket", "myprefix", olderThan)
if err != nil {
log.Fatalln(err)
}

View File

@ -20,6 +20,7 @@
package main
import (
"context"
"log"
"github.com/minio/minio/pkg/madmin"
@ -36,7 +37,7 @@ func main() {
log.Fatalln(err)
}
st, err := madmClnt.ServerMemUsageInfo()
st, err := madmClnt.ServerMemUsageInfo(context.Background())
if err != nil {
log.Fatalln(err)
}

View File

@ -20,6 +20,7 @@
package main
import (
"context"
"log"
"github.com/minio/minio/pkg/madmin"
@ -36,7 +37,7 @@ func main() {
log.Fatalln(err)
}
st, err := madmClnt.NetPerfInfo(madmin.DefaultNetPerfSize)
st, err := madmClnt.NetPerfInfo(context.Background(), madmin.DefaultNetPerfSize)
if err != nil {
log.Fatalln(err)
}

View File

@ -20,6 +20,7 @@
package main
import (
"context"
"io"
"log"
"os"
@ -45,7 +46,7 @@ func main() {
profiler := madmin.ProfilerCPU
log.Println("Starting " + profiler + " profiling..")
startResults, err := madmClnt.StartProfiling(profiler)
startResults, err := madmClnt.StartProfiling(context.Background(), profiler)
if err != nil {
log.Fatalln(err)
}
@ -63,7 +64,7 @@ func main() {
log.Println("Stopping profiling..")
profilingData, err := madmClnt.DownloadProfilingData()
profilingData, err := madmClnt.DownloadProfilingData(context.Background())
if err != nil {
log.Fatalln(err)
}

View File

@ -20,6 +20,7 @@
package main
import (
"context"
"log"
"github.com/minio/minio/pkg/madmin"
@ -36,7 +37,7 @@ func main() {
log.Fatalln(err)
}
st, err := madmClnt.ServerInfo()
st, err := madmClnt.ServerInfo(context.Background())
if err != nil {
log.Fatalln(err)
}

View File

@ -20,6 +20,7 @@
package main
import (
"context"
"log"
"github.com/minio/minio/pkg/madmin"
@ -36,7 +37,7 @@ func main() {
log.Fatalln(err)
}
err = madmClnt.ServiceRestart()
err = madmClnt.ServiceRestart(context.Background())
if err != nil {
log.Fatalln(err)
}

View File

@ -20,6 +20,7 @@
package main
import (
"context"
"fmt"
"log"
@ -43,7 +44,7 @@ func main() {
// in the minio cluster.
allTrace := false
errTrace := false
traceCh := madmClnt.ServiceTrace(allTrace, errTrace, doneCh)
traceCh := madmClnt.ServiceTrace(context.Background(), allTrace, errTrace, doneCh)
for traceInfo := range traceCh {
if traceInfo.Err != nil {
fmt.Println(traceInfo.Err)

View File

@ -20,6 +20,7 @@
package main
import (
"context"
"log"
"github.com/minio/minio/pkg/madmin"
@ -36,7 +37,7 @@ func main() {
log.Fatalln(err)
}
st, err := madmClnt.StorageInfo()
st, err := madmClnt.StorageInfo(context.Background())
if err != nil {
log.Fatalln(err)
}

View File

@ -20,6 +20,7 @@
package main
import (
"context"
"encoding/json"
"log"
@ -37,7 +38,7 @@ func main() {
log.Fatalln(err)
}
locks, err := madmClnt.TopLocks()
locks, err := madmClnt.TopLocks(context.Background())
if err != nil {
log.Fatalf("failed due to: %v", err)
}

View File

@ -18,6 +18,7 @@
package madmin
import (
"context"
"encoding/json"
"io/ioutil"
"net/http"
@ -34,7 +35,7 @@ type GroupAddRemove struct {
// UpdateGroupMembers - adds/removes users to/from a group. Server
// creates the group as needed. Group is removed if remove request is
// made on empty group.
func (adm *AdminClient) UpdateGroupMembers(g GroupAddRemove) error {
func (adm *AdminClient) UpdateGroupMembers(ctx context.Context, g GroupAddRemove) error {
data, err := json.Marshal(g)
if err != nil {
return err
@ -46,7 +47,7 @@ func (adm *AdminClient) UpdateGroupMembers(g GroupAddRemove) error {
}
// Execute PUT on /minio/admin/v2/update-group-members
resp, err := adm.executeMethod("PUT", reqData)
resp, err := adm.executeMethod(ctx, http.MethodPut, reqData)
defer closeResponse(resp)
if err != nil {
@ -70,7 +71,7 @@ type GroupDesc struct {
}
// GetGroupDescription - fetches information on a group.
func (adm *AdminClient) GetGroupDescription(group string) (*GroupDesc, error) {
func (adm *AdminClient) GetGroupDescription(ctx context.Context, group string) (*GroupDesc, error) {
v := url.Values{}
v.Set("group", group)
reqData := requestData{
@ -78,7 +79,7 @@ func (adm *AdminClient) GetGroupDescription(group string) (*GroupDesc, error) {
queryValues: v,
}
resp, err := adm.executeMethod("GET", reqData)
resp, err := adm.executeMethod(ctx, http.MethodGet, reqData)
defer closeResponse(resp)
if err != nil {
return nil, err
@ -102,12 +103,12 @@ func (adm *AdminClient) GetGroupDescription(group string) (*GroupDesc, error) {
}
// ListGroups - lists all groups names present on the server.
func (adm *AdminClient) ListGroups() ([]string, error) {
func (adm *AdminClient) ListGroups(ctx context.Context) ([]string, error) {
reqData := requestData{
relPath: adminAPIPrefix + "/groups",
}
resp, err := adm.executeMethod("GET", reqData)
resp, err := adm.executeMethod(ctx, http.MethodGet, reqData)
defer closeResponse(resp)
if err != nil {
return nil, err
@ -140,7 +141,7 @@ const (
)
// SetGroupStatus - sets the status of a group.
func (adm *AdminClient) SetGroupStatus(group string, status GroupStatus) error {
func (adm *AdminClient) SetGroupStatus(ctx context.Context, group string, status GroupStatus) error {
v := url.Values{}
v.Set("group", group)
v.Set("status", string(status))
@ -150,7 +151,7 @@ func (adm *AdminClient) SetGroupStatus(group string, status GroupStatus) error {
queryValues: v,
}
resp, err := adm.executeMethod("PUT", reqData)
resp, err := adm.executeMethod(ctx, http.MethodPut, reqData)
defer closeResponse(resp)
if err != nil {
return err

View File

@ -18,6 +18,7 @@
package madmin
import (
"context"
"encoding/json"
"io/ioutil"
"net"
@ -47,13 +48,15 @@ type ServerCPUHardwareInfo struct {
}
// ServerCPUHardwareInfo - Returns cpu hardware information
func (adm *AdminClient) ServerCPUHardwareInfo() ([]ServerCPUHardwareInfo, error) {
func (adm *AdminClient) ServerCPUHardwareInfo(ctx context.Context) ([]ServerCPUHardwareInfo, error) {
v := url.Values{}
v.Set(HARDWARE, string(CPU))
resp, err := adm.executeMethod("GET", requestData{
relPath: adminAPIPrefix + "/hardware",
queryValues: v,
})
resp, err := adm.executeMethod(ctx,
http.MethodGet, requestData{
relPath: adminAPIPrefix + "/hardware",
queryValues: v,
},
)
defer closeResponse(resp)
if err != nil {
@ -88,13 +91,15 @@ type ServerNetworkHardwareInfo struct {
}
// ServerNetworkHardwareInfo - Returns network hardware information
func (adm *AdminClient) ServerNetworkHardwareInfo() ([]ServerNetworkHardwareInfo, error) {
func (adm *AdminClient) ServerNetworkHardwareInfo(ctx context.Context) ([]ServerNetworkHardwareInfo, error) {
v := url.Values{}
v.Set(HARDWARE, string(NETWORK))
resp, err := adm.executeMethod("GET", requestData{
relPath: "/v1/hardware",
queryValues: v,
})
resp, err := adm.executeMethod(ctx,
http.MethodGet, requestData{
relPath: "/v1/hardware",
queryValues: v,
},
)
defer closeResponse(resp)
if err != nil {

View File

@ -18,6 +18,7 @@
package madmin
import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
@ -195,8 +196,8 @@ func (hri *HealResultItem) GetOnlineCounts() (b, a int) {
// forceStart and forceStop are mutually exclusive, you can either
// set one of them to 'true'. If both are set 'forceStart' will be
// honored.
func (adm *AdminClient) Heal(bucket, prefix string, healOpts HealOpts,
clientToken string, forceStart, forceStop bool) (
func (adm *AdminClient) Heal(ctx context.Context, bucket, prefix string,
healOpts HealOpts, clientToken string, forceStart, forceStop bool) (
healStart HealStartSuccess, healTaskStatus HealTaskStatus, err error) {
if forceStart && forceStop {
@ -227,11 +228,12 @@ func (adm *AdminClient) Heal(bucket, prefix string, healOpts HealOpts,
queryVals.Set("forceStop", "true")
}
resp, err := adm.executeMethod("POST", requestData{
relPath: path,
content: body,
queryValues: queryVals,
})
resp, err := adm.executeMethod(ctx,
http.MethodPost, requestData{
relPath: path,
content: body,
queryValues: queryVals,
})
defer closeResponse(resp)
if err != nil {
return healStart, healTaskStatus, err
@ -279,9 +281,11 @@ type BgHealState struct {
// BackgroundHealStatus returns the background heal status of the
// current server or cluster.
func (adm *AdminClient) BackgroundHealStatus() (BgHealState, error) {
func (adm *AdminClient) BackgroundHealStatus(ctx context.Context) (BgHealState, error) {
// Execute POST request to background heal status api
resp, err := adm.executeMethod("POST", requestData{relPath: adminAPIPrefix + "/background-heal/status"})
resp, err := adm.executeMethod(ctx,
http.MethodPost,
requestData{relPath: adminAPIPrefix + "/background-heal/status"})
if err != nil {
return BgHealState{}, err
}

View File

@ -18,6 +18,7 @@
package madmin
import (
"context"
"encoding/json"
"errors"
"io/ioutil"
@ -114,8 +115,8 @@ func (d1 BackendDisks) Merge(d2 BackendDisks) BackendDisks {
// StorageInfo - Connect to a minio server and call Storage Info Management API
// to fetch server's information represented by StorageInfo structure
func (adm *AdminClient) StorageInfo() (StorageInfo, error) {
resp, err := adm.executeMethod("GET", requestData{relPath: adminAPIPrefix + "/storageinfo"})
func (adm *AdminClient) StorageInfo(ctx context.Context) (StorageInfo, error) {
resp, err := adm.executeMethod(ctx, http.MethodGet, requestData{relPath: adminAPIPrefix + "/storageinfo"})
defer closeResponse(resp)
if err != nil {
return StorageInfo{}, err
@ -178,8 +179,8 @@ type DataUsageInfo struct {
}
// DataUsageInfo - returns data usage of the current object API
func (adm *AdminClient) DataUsageInfo() (DataUsageInfo, error) {
resp, err := adm.executeMethod("GET", requestData{relPath: adminAPIPrefix + "/datausageinfo"})
func (adm *AdminClient) DataUsageInfo(ctx context.Context) (DataUsageInfo, error) {
resp, err := adm.executeMethod(ctx, http.MethodGet, requestData{relPath: adminAPIPrefix + "/datausageinfo"})
defer closeResponse(resp)
if err != nil {
return DataUsageInfo{}, err
@ -222,8 +223,8 @@ type BucketAccountingUsage struct {
// AccountingUsageInfo returns the accounting usage info, currently it returns
// the type of access of different accounts to the different buckets.
func (adm *AdminClient) AccountingUsageInfo() (map[string]BucketAccountingUsage, error) {
resp, err := adm.executeMethod(http.MethodGet, requestData{relPath: adminAPIPrefix + "/accountingusageinfo"})
func (adm *AdminClient) AccountingUsageInfo(ctx context.Context) (map[string]BucketAccountingUsage, error) {
resp, err := adm.executeMethod(ctx, http.MethodGet, requestData{relPath: adminAPIPrefix + "/accountingusageinfo"})
defer closeResponse(resp)
if err != nil {
return nil, err
@ -260,16 +261,18 @@ type ServerDrivesPerfInfo struct {
}
// ServerDrivesPerfInfo - Returns drive's read and write performance information
func (adm *AdminClient) ServerDrivesPerfInfo(size int64) ([]ServerDrivesPerfInfo, error) {
func (adm *AdminClient) ServerDrivesPerfInfo(ctx context.Context, size int64) ([]ServerDrivesPerfInfo, error) {
v := url.Values{}
v.Set("perfType", string("drive"))
v.Set("size", strconv.FormatInt(size, 10))
resp, err := adm.executeMethod("GET", requestData{
relPath: adminAPIPrefix + "/performance",
queryValues: v,
})
resp, err := adm.executeMethod(ctx, http.MethodGet,
requestData{
relPath: adminAPIPrefix + "/performance",
queryValues: v,
},
)
defer closeResponse(resp)
if err != nil {
@ -307,13 +310,15 @@ type ServerCPULoadInfo struct {
}
// ServerCPULoadInfo - Returns cpu utilization information
func (adm *AdminClient) ServerCPULoadInfo() ([]ServerCPULoadInfo, error) {
func (adm *AdminClient) ServerCPULoadInfo(ctx context.Context) ([]ServerCPULoadInfo, error) {
v := url.Values{}
v.Set("perfType", string("cpu"))
resp, err := adm.executeMethod("GET", requestData{
relPath: adminAPIPrefix + "/performance",
queryValues: v,
})
resp, err := adm.executeMethod(ctx,
http.MethodGet, requestData{
relPath: adminAPIPrefix + "/performance",
queryValues: v,
},
)
defer closeResponse(resp)
if err != nil {
@ -351,13 +356,16 @@ type ServerMemUsageInfo struct {
}
// ServerMemUsageInfo - Returns mem utilization information
func (adm *AdminClient) ServerMemUsageInfo() ([]ServerMemUsageInfo, error) {
func (adm *AdminClient) ServerMemUsageInfo(ctx context.Context) ([]ServerMemUsageInfo, error) {
v := url.Values{}
v.Set("perfType", string("mem"))
resp, err := adm.executeMethod("GET", requestData{
relPath: adminAPIPrefix + "/performance",
queryValues: v,
})
resp, err := adm.executeMethod(ctx,
http.MethodGet,
requestData{
relPath: adminAPIPrefix + "/performance",
queryValues: v,
},
)
defer closeResponse(resp)
if err != nil {
@ -393,16 +401,19 @@ type NetPerfInfo struct {
}
// NetPerfInfo - Returns network performance information of all cluster nodes.
func (adm *AdminClient) NetPerfInfo(size int) (map[string][]NetPerfInfo, error) {
func (adm *AdminClient) NetPerfInfo(ctx context.Context, size int) (map[string][]NetPerfInfo, error) {
v := url.Values{}
v.Set("perfType", "net")
if size > 0 {
v.Set("size", strconv.Itoa(size))
}
resp, err := adm.executeMethod("GET", requestData{
relPath: adminAPIPrefix + "/performance",
queryValues: v,
})
resp, err := adm.executeMethod(ctx,
http.MethodGet,
requestData{
relPath: adminAPIPrefix + "/performance",
queryValues: v,
},
)
defer closeResponse(resp)
if err != nil {
@ -509,13 +520,13 @@ const (
ErasureType = backendType("Erasure")
)
// FsBackend contains specific FS storage information
type FsBackend struct {
// FSBackend contains specific FS storage information
type FSBackend struct {
Type backendType `json:"backendType,omitempty"`
}
// XlBackend contains specific erasure storage information
type XlBackend struct {
// XLBackend contains specific erasure storage information
type XLBackend struct {
Type backendType `json:"backendType,omitempty"`
OnlineDisks int `json:"onlineDisks,omitempty"`
OfflineDisks int `json:"offlineDisks,omitempty"`
@ -557,9 +568,11 @@ type Disk struct {
// ServerInfo - Connect to a minio server and call Server Admin Info Management API
// to fetch server's information represented by infoMessage structure
func (adm *AdminClient) ServerInfo() (InfoMessage, error) {
resp, err := adm.executeMethod("GET", requestData{relPath: adminAPIPrefix + "/info"})
func (adm *AdminClient) ServerInfo(ctx context.Context) (InfoMessage, error) {
resp, err := adm.executeMethod(ctx,
http.MethodGet,
requestData{relPath: adminAPIPrefix + "/info"},
)
defer closeResponse(resp)
if err != nil {
return InfoMessage{}, err

View File

@ -17,6 +17,7 @@
package madmin
import (
"context"
"encoding/json"
"net/http"
"net/url"
@ -25,7 +26,7 @@ import (
// GetKeyStatus requests status information about the key referenced by keyID
// from the KMS connected to a MinIO by performing a Admin-API request.
// It basically hits the `/minio/admin/v2/kms/key/status` API endpoint.
func (adm *AdminClient) GetKeyStatus(keyID string) (*KMSKeyStatus, error) {
func (adm *AdminClient) GetKeyStatus(ctx context.Context, keyID string) (*KMSKeyStatus, error) {
// GET /minio/admin/v2/kms/key/status?key-id=<keyID>
qv := url.Values{}
qv.Set("key-id", keyID)
@ -34,7 +35,7 @@ func (adm *AdminClient) GetKeyStatus(keyID string) (*KMSKeyStatus, error) {
queryValues: qv,
}
resp, err := adm.executeMethod("GET", reqData)
resp, err := adm.executeMethod(ctx, http.MethodGet, reqData)
if err != nil {
return nil, err
}

View File

@ -18,6 +18,7 @@
package madmin
import (
"context"
"encoding/json"
"io/ioutil"
"net/http"
@ -25,7 +26,7 @@ import (
)
// InfoCannedPolicy - expand canned policy into JSON structure.
func (adm *AdminClient) InfoCannedPolicy(policyName string) ([]byte, error) {
func (adm *AdminClient) InfoCannedPolicy(ctx context.Context, policyName string) ([]byte, error) {
queryValues := url.Values{}
queryValues.Set("name", policyName)
@ -35,7 +36,7 @@ func (adm *AdminClient) InfoCannedPolicy(policyName string) ([]byte, error) {
}
// Execute GET on /minio/admin/v2/info-canned-policy
resp, err := adm.executeMethod("GET", reqData)
resp, err := adm.executeMethod(ctx, http.MethodGet, reqData)
defer closeResponse(resp)
if err != nil {
@ -50,13 +51,13 @@ func (adm *AdminClient) InfoCannedPolicy(policyName string) ([]byte, error) {
}
// ListCannedPolicies - list all configured canned policies.
func (adm *AdminClient) ListCannedPolicies() (map[string][]byte, error) {
func (adm *AdminClient) ListCannedPolicies(ctx context.Context) (map[string][]byte, error) {
reqData := requestData{
relPath: adminAPIPrefix + "/list-canned-policies",
}
// Execute GET on /minio/admin/v2/list-canned-policies
resp, err := adm.executeMethod("GET", reqData)
resp, err := adm.executeMethod(ctx, http.MethodGet, reqData)
defer closeResponse(resp)
if err != nil {
@ -81,7 +82,7 @@ func (adm *AdminClient) ListCannedPolicies() (map[string][]byte, error) {
}
// RemoveCannedPolicy - remove a policy for a canned.
func (adm *AdminClient) RemoveCannedPolicy(policyName string) error {
func (adm *AdminClient) RemoveCannedPolicy(ctx context.Context, policyName string) error {
queryValues := url.Values{}
queryValues.Set("name", policyName)
@ -91,7 +92,7 @@ func (adm *AdminClient) RemoveCannedPolicy(policyName string) error {
}
// Execute DELETE on /minio/admin/v2/remove-canned-policy to remove policy.
resp, err := adm.executeMethod("DELETE", reqData)
resp, err := adm.executeMethod(ctx, http.MethodDelete, reqData)
defer closeResponse(resp)
if err != nil {
@ -106,7 +107,7 @@ func (adm *AdminClient) RemoveCannedPolicy(policyName string) error {
}
// AddCannedPolicy - adds a policy for a canned.
func (adm *AdminClient) AddCannedPolicy(policyName, policy string) error {
func (adm *AdminClient) AddCannedPolicy(ctx context.Context, policyName, policy string) error {
queryValues := url.Values{}
queryValues.Set("name", policyName)
@ -117,7 +118,7 @@ func (adm *AdminClient) AddCannedPolicy(policyName, policy string) error {
}
// Execute PUT on /minio/admin/v2/add-canned-policy to set policy.
resp, err := adm.executeMethod("PUT", reqData)
resp, err := adm.executeMethod(ctx, http.MethodPut, reqData)
defer closeResponse(resp)
if err != nil {
@ -132,7 +133,7 @@ func (adm *AdminClient) AddCannedPolicy(policyName, policy string) error {
}
// SetPolicy - sets the policy for a user or a group.
func (adm *AdminClient) SetPolicy(policyName, entityName string, isGroup bool) error {
func (adm *AdminClient) SetPolicy(ctx context.Context, policyName, entityName string, isGroup bool) error {
queryValues := url.Values{}
queryValues.Set("policyName", policyName)
queryValues.Set("userOrGroup", entityName)
@ -148,7 +149,7 @@ func (adm *AdminClient) SetPolicy(policyName, entityName string, isGroup bool) e
}
// Execute PUT on /minio/admin/v2/set-user-or-group-policy to set policy.
resp, err := adm.executeMethod("PUT", reqData)
resp, err := adm.executeMethod(ctx, http.MethodPut, reqData)
defer closeResponse(resp)
if err != nil {
return err

View File

@ -18,6 +18,7 @@
package madmin
import (
"context"
"encoding/json"
"errors"
"fmt"
@ -52,13 +53,15 @@ type StartProfilingResult struct {
// StartProfiling makes an admin call to remotely start profiling on a standalone
// server or the whole cluster in case of a distributed setup.
func (adm *AdminClient) StartProfiling(profiler ProfilerType) ([]StartProfilingResult, error) {
func (adm *AdminClient) StartProfiling(ctx context.Context, profiler ProfilerType) ([]StartProfilingResult, error) {
v := url.Values{}
v.Set("profilerType", string(profiler))
resp, err := adm.executeMethod("POST", requestData{
relPath: adminAPIPrefix + "/profiling/start",
queryValues: v,
})
resp, err := adm.executeMethod(ctx,
http.MethodPost, requestData{
relPath: adminAPIPrefix + "/profiling/start",
queryValues: v,
},
)
defer closeResponse(resp)
if err != nil {
return nil, err
@ -84,11 +87,13 @@ func (adm *AdminClient) StartProfiling(profiler ProfilerType) ([]StartProfilingR
// DownloadProfilingData makes an admin call to download profiling data of a standalone
// server or of the whole cluster in case of a distributed setup.
func (adm *AdminClient) DownloadProfilingData() (io.ReadCloser, error) {
func (adm *AdminClient) DownloadProfilingData(ctx context.Context) (io.ReadCloser, error) {
path := fmt.Sprintf(adminAPIPrefix + "/profiling/download")
resp, err := adm.executeMethod("GET", requestData{
relPath: path,
})
resp, err := adm.executeMethod(ctx,
http.MethodGet, requestData{
relPath: path,
},
)
if err != nil {
closeResponse(resp)

View File

@ -18,6 +18,7 @@
package madmin
import (
"context"
"math/rand"
"net"
"net/http"
@ -68,7 +69,7 @@ func (r *lockedRandSource) Seed(seed int64) {
// newRetryTimer creates a timer with exponentially increasing
// delays until the maximum retry attempts are reached.
func (adm AdminClient) newRetryTimer(maxRetry int, unit time.Duration, cap time.Duration, jitter float64, doneCh chan struct{}) <-chan int {
func (adm AdminClient) newRetryTimer(ctx context.Context, maxRetry int, unit time.Duration, cap time.Duration, jitter float64) <-chan int {
attemptCh := make(chan int)
// computes the exponential backoff duration according to
@ -96,14 +97,15 @@ func (adm AdminClient) newRetryTimer(maxRetry int, unit time.Duration, cap time.
go func() {
defer close(attemptCh)
for i := 0; i < maxRetry; i++ {
select {
// Attempts start from 1.
case attemptCh <- i + 1:
case <-doneCh:
attemptCh <- i + 1
select {
case <-time.After(exponentialBackoffWait(i)):
case <-ctx.Done():
// Stop the routine.
return
}
time.Sleep(exponentialBackoffWait(i))
}
}()
return attemptCh

View File

@ -18,6 +18,7 @@
package madmin
import (
"context"
"encoding/json"
"net/http"
"net/url"
@ -27,13 +28,13 @@ import (
)
// ServiceRestart - restarts the MinIO cluster
func (adm *AdminClient) ServiceRestart() error {
return adm.serviceCallAction(ServiceActionRestart)
func (adm *AdminClient) ServiceRestart(ctx context.Context) error {
return adm.serviceCallAction(ctx, ServiceActionRestart)
}
// ServiceStop - stops the MinIO cluster
func (adm *AdminClient) ServiceStop() error {
return adm.serviceCallAction(ServiceActionStop)
func (adm *AdminClient) ServiceStop(ctx context.Context) error {
return adm.serviceCallAction(ctx, ServiceActionStop)
}
// ServiceAction - type to restrict service-action values
@ -47,15 +48,17 @@ const (
)
// serviceCallAction - call service restart/update/stop API.
func (adm *AdminClient) serviceCallAction(action ServiceAction) error {
func (adm *AdminClient) serviceCallAction(ctx context.Context, action ServiceAction) error {
queryValues := url.Values{}
queryValues.Set("action", string(action))
// Request API to Restart server
resp, err := adm.executeMethod("POST", requestData{
relPath: adminAPIPrefix + "/service",
queryValues: queryValues,
})
resp, err := adm.executeMethod(ctx,
http.MethodPost, requestData{
relPath: adminAPIPrefix + "/service",
queryValues: queryValues,
},
)
defer closeResponse(resp)
if err != nil {
return err
@ -75,7 +78,7 @@ type ServiceTraceInfo struct {
}
// ServiceTrace - listen on http trace notifications.
func (adm AdminClient) ServiceTrace(allTrace, errTrace bool, doneCh <-chan struct{}) <-chan ServiceTraceInfo {
func (adm AdminClient) ServiceTrace(ctx context.Context, allTrace, errTrace bool) <-chan ServiceTraceInfo {
traceInfoCh := make(chan ServiceTraceInfo)
// Only success, start a routine to start reading line by line.
go func(traceInfoCh chan<- ServiceTraceInfo) {
@ -89,7 +92,7 @@ func (adm AdminClient) ServiceTrace(allTrace, errTrace bool, doneCh <-chan struc
queryValues: urlValues,
}
// Execute GET to call trace handler
resp, err := adm.executeMethod("GET", reqData)
resp, err := adm.executeMethod(ctx, http.MethodGet, reqData)
if err != nil {
closeResponse(resp)
return
@ -107,7 +110,7 @@ func (adm AdminClient) ServiceTrace(allTrace, errTrace bool, doneCh <-chan struc
break
}
select {
case <-doneCh:
case <-ctx.Done():
return
case traceInfoCh <- ServiceTraceInfo{Trace: info}:
}

View File

@ -18,6 +18,7 @@
package madmin
import (
"context"
"encoding/json"
"io/ioutil"
"net/http"
@ -53,11 +54,13 @@ func (l LockEntries) Swap(i, j int) {
}
// TopLocks - returns the oldest locks in a minio setup.
func (adm *AdminClient) TopLocks() (LockEntries, error) {
func (adm *AdminClient) TopLocks(ctx context.Context) (LockEntries, error) {
// Execute GET on /minio/admin/v2/top/locks
// to get the oldest locks in a minio setup.
resp, err := adm.executeMethod("GET",
requestData{relPath: adminAPIPrefix + "/top/locks"})
resp, err := adm.executeMethod(ctx,
http.MethodGet,
requestData{relPath: adminAPIPrefix + "/top/locks"},
)
defer closeResponse(resp)
if err != nil {
return nil, err

60
pkg/madmin/transport.go Normal file
View File

@ -0,0 +1,60 @@
/*
* MinIO Cloud Storage, (C) 2020 MinIO, Inc.
*
* 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 madmin
import (
"crypto/tls"
"net"
"net/http"
"time"
)
// DefaultTransport - this default transport is similar to
// http.DefaultTransport but with additional param DisableCompression
// is set to true to avoid decompressing content with 'gzip' encoding.
var DefaultTransport = func(secure bool) http.RoundTripper {
tr := &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 5 * time.Second,
KeepAlive: 15 * time.Second,
}).DialContext,
MaxIdleConns: 1024,
MaxIdleConnsPerHost: 1024,
ResponseHeaderTimeout: 60 * time.Second,
IdleConnTimeout: 60 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
// Set this value so that the underlying transport round-tripper
// doesn't try to auto decode the body of objects with
// content-encoding set to `gzip`.
//
// Refer:
// https://golang.org/src/net/http/transport.go?h=roundTrip#L1843
DisableCompression: true,
}
if secure {
tr.TLSClientConfig = &tls.Config{
// Can't use SSLv3 because of POODLE and BEAST
// Can't use TLSv1.0 because of POODLE and BEAST using CBC cipher
// Can't use TLSv1.1 because of RC4 cipher usage
MinVersion: tls.VersionTLS12,
}
}
return tr
}

View File

@ -18,6 +18,7 @@
package madmin
import (
"context"
"encoding/json"
"io/ioutil"
"net/http"
@ -32,15 +33,17 @@ type ServerUpdateStatus struct {
// ServerUpdate - updates and restarts the MinIO cluster to latest version.
// optionally takes an input URL to specify a custom update binary link
func (adm *AdminClient) ServerUpdate(updateURL string) (us ServerUpdateStatus, err error) {
func (adm *AdminClient) ServerUpdate(ctx context.Context, updateURL string) (us ServerUpdateStatus, err error) {
queryValues := url.Values{}
queryValues.Set("updateURL", updateURL)
// Request API to Restart server
resp, err := adm.executeMethod("POST", requestData{
relPath: adminAPIPrefix + "/update",
queryValues: queryValues,
})
resp, err := adm.executeMethod(ctx,
http.MethodPost, requestData{
relPath: adminAPIPrefix + "/update",
queryValues: queryValues,
},
)
defer closeResponse(resp)
if err != nil {
return us, err

View File

@ -18,6 +18,7 @@
package madmin
import (
"context"
"encoding/json"
"io/ioutil"
"net/http"
@ -44,7 +45,7 @@ type UserInfo struct {
}
// RemoveUser - remove a user.
func (adm *AdminClient) RemoveUser(accessKey string) error {
func (adm *AdminClient) RemoveUser(ctx context.Context, accessKey string) error {
queryValues := url.Values{}
queryValues.Set("accessKey", accessKey)
@ -54,7 +55,7 @@ func (adm *AdminClient) RemoveUser(accessKey string) error {
}
// Execute DELETE on /minio/admin/v2/remove-user to remove a user.
resp, err := adm.executeMethod("DELETE", reqData)
resp, err := adm.executeMethod(ctx, http.MethodDelete, reqData)
defer closeResponse(resp)
if err != nil {
@ -69,13 +70,13 @@ func (adm *AdminClient) RemoveUser(accessKey string) error {
}
// ListUsers - list all users.
func (adm *AdminClient) ListUsers() (map[string]UserInfo, error) {
func (adm *AdminClient) ListUsers(ctx context.Context) (map[string]UserInfo, error) {
reqData := requestData{
relPath: adminAPIPrefix + "/list-users",
}
// Execute GET on /minio/admin/v2/list-users
resp, err := adm.executeMethod("GET", reqData)
resp, err := adm.executeMethod(ctx, http.MethodGet, reqData)
defer closeResponse(resp)
if err != nil {
@ -100,7 +101,7 @@ func (adm *AdminClient) ListUsers() (map[string]UserInfo, error) {
}
// GetUserInfo - get info on a user
func (adm *AdminClient) GetUserInfo(name string) (u UserInfo, err error) {
func (adm *AdminClient) GetUserInfo(ctx context.Context, name string) (u UserInfo, err error) {
queryValues := url.Values{}
queryValues.Set("accessKey", name)
@ -110,7 +111,7 @@ func (adm *AdminClient) GetUserInfo(name string) (u UserInfo, err error) {
}
// Execute GET on /minio/admin/v2/user-info
resp, err := adm.executeMethod("GET", reqData)
resp, err := adm.executeMethod(ctx, http.MethodGet, reqData)
defer closeResponse(resp)
if err != nil {
@ -134,7 +135,7 @@ func (adm *AdminClient) GetUserInfo(name string) (u UserInfo, err error) {
}
// SetUser - sets a user info.
func (adm *AdminClient) SetUser(accessKey, secretKey string, status AccountStatus) error {
func (adm *AdminClient) SetUser(ctx context.Context, accessKey, secretKey string, status AccountStatus) error {
if !auth.IsAccessKeyValid(accessKey) {
return auth.ErrInvalidAccessKeyLength
@ -166,7 +167,7 @@ func (adm *AdminClient) SetUser(accessKey, secretKey string, status AccountStatu
}
// Execute PUT on /minio/admin/v2/add-user to set a user.
resp, err := adm.executeMethod("PUT", reqData)
resp, err := adm.executeMethod(ctx, http.MethodPut, reqData)
defer closeResponse(resp)
if err != nil {
@ -181,12 +182,12 @@ func (adm *AdminClient) SetUser(accessKey, secretKey string, status AccountStatu
}
// AddUser - adds a user.
func (adm *AdminClient) AddUser(accessKey, secretKey string) error {
return adm.SetUser(accessKey, secretKey, AccountEnabled)
func (adm *AdminClient) AddUser(ctx context.Context, accessKey, secretKey string) error {
return adm.SetUser(ctx, accessKey, secretKey, AccountEnabled)
}
// SetUserStatus - adds a status for a user.
func (adm *AdminClient) SetUserStatus(accessKey string, status AccountStatus) error {
func (adm *AdminClient) SetUserStatus(ctx context.Context, accessKey string, status AccountStatus) error {
queryValues := url.Values{}
queryValues.Set("accessKey", accessKey)
queryValues.Set("status", string(status))
@ -197,7 +198,7 @@ func (adm *AdminClient) SetUserStatus(accessKey string, status AccountStatus) er
}
// Execute PUT on /minio/admin/v2/set-user-status to set status.
resp, err := adm.executeMethod("PUT", reqData)
resp, err := adm.executeMethod(ctx, http.MethodPut, reqData)
defer closeResponse(resp)
if err != nil {
@ -224,7 +225,7 @@ type AddServiceAccountResp struct {
// AddServiceAccount - creates a new service account belonging to the given parent user
// while restricting the service account permission by the given policy document.
func (adm *AdminClient) AddServiceAccount(parentUser string, policy string) (auth.Credentials, error) {
func (adm *AdminClient) AddServiceAccount(ctx context.Context, parentUser string, policy string) (auth.Credentials, error) {
if !auth.IsAccessKeyValid(parentUser) {
return auth.Credentials{}, auth.ErrInvalidAccessKeyLength
@ -249,7 +250,7 @@ func (adm *AdminClient) AddServiceAccount(parentUser string, policy string) (aut
}
// Execute PUT on /minio/admin/v2/add-service-account to set a user.
resp, err := adm.executeMethod("PUT", reqData)
resp, err := adm.executeMethod(ctx, http.MethodPut, reqData)
defer closeResponse(resp)
if err != nil {
return auth.Credentials{}, err
@ -272,7 +273,7 @@ func (adm *AdminClient) AddServiceAccount(parentUser string, policy string) (aut
}
// GetServiceAccount returns the credential of the service account
func (adm *AdminClient) GetServiceAccount(serviceAccountAccessKey string) (auth.Credentials, error) {
func (adm *AdminClient) GetServiceAccount(ctx context.Context, serviceAccountAccessKey string) (auth.Credentials, error) {
if !auth.IsAccessKeyValid(serviceAccountAccessKey) {
return auth.Credentials{}, auth.ErrInvalidAccessKeyLength
@ -287,7 +288,7 @@ func (adm *AdminClient) GetServiceAccount(serviceAccountAccessKey string) (auth.
}
// Execute GET on /minio/admin/v2/get-service-account to set a user.
resp, err := adm.executeMethod("GET", reqData)
resp, err := adm.executeMethod(ctx, http.MethodGet, reqData)
defer closeResponse(resp)
if err != nil {
return auth.Credentials{}, err