mirror of
https://github.com/minio/mc.git
synced 2025-11-12 01:02:26 +03:00
Add admin profiling command (#2557)
Implement profiling command to start & download profiling data of a standalone or all nodes of a cluster. ``` 1. Start CPU profiling $ mc admin profiling start --type "cpu" myminio/ 2. Download latest profiling data under save under profiling.zip $ mc admin profiling stop myminio/ ```
This commit is contained in:
@@ -37,6 +37,7 @@ var adminCmd = cli.Command{
|
||||
adminCredsCmd,
|
||||
adminConfigCmd,
|
||||
adminHealCmd,
|
||||
adminProfilingCmd,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
111
cmd/admin-profiling-start.go
Normal file
111
cmd/admin-profiling-start.go
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Minio Client (C) 2018 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 cmd
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/minio/cli"
|
||||
"github.com/minio/mc/pkg/console"
|
||||
"github.com/minio/mc/pkg/probe"
|
||||
"github.com/minio/minio/pkg/madmin"
|
||||
)
|
||||
|
||||
var adminProfilingStartFlags = []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "type",
|
||||
Usage: "Profiler type, possible values are: `cpu`, `mem`, `block`, `mutex` and `trace`",
|
||||
Value: "mem",
|
||||
},
|
||||
}
|
||||
|
||||
var adminProfilingStartCmd = cli.Command{
|
||||
Name: "start",
|
||||
Usage: "Start recording profiling data",
|
||||
Action: mainAdminProfilingStart,
|
||||
Before: setGlobalsFromContext,
|
||||
Flags: append(adminProfilingStartFlags, globalFlags...),
|
||||
HideHelpCommand: true,
|
||||
CustomHelpTemplate: `NAME:
|
||||
{{.HelpName}} - {{.Usage}}
|
||||
|
||||
USAGE:
|
||||
{{.HelpName}} [FLAGS] TARGET
|
||||
|
||||
FLAGS:
|
||||
{{range .VisibleFlags}}{{.}}
|
||||
{{end}}
|
||||
EXAMPLES:
|
||||
1. Start CPU profiling
|
||||
$ {{.HelpName}} --type cpu myminio/
|
||||
|
||||
`,
|
||||
}
|
||||
|
||||
func checkAdminProfilingStartSyntax(ctx *cli.Context) {
|
||||
// Check flags combinations
|
||||
if len(ctx.Args()) != 1 {
|
||||
cli.ShowCommandHelpAndExit(ctx, "start", 1) // last argument is exit code
|
||||
}
|
||||
|
||||
profilerTypes := []madmin.ProfilerType{
|
||||
madmin.ProfilerCPU,
|
||||
madmin.ProfilerMEM,
|
||||
madmin.ProfilerBlock,
|
||||
madmin.ProfilerMutex,
|
||||
madmin.ProfilerTrace,
|
||||
}
|
||||
|
||||
// Check if the provided profiler type is known and supported
|
||||
supportedProfiler := false
|
||||
profilerType := strings.ToLower(ctx.String("type"))
|
||||
for _, profiler := range profilerTypes {
|
||||
if profilerType == string(profiler) {
|
||||
supportedProfiler = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !supportedProfiler {
|
||||
fatalIf(errDummy(), "Profiler type unrecognized. Possible values are: %v.", profilerTypes)
|
||||
}
|
||||
}
|
||||
|
||||
// mainAdminProfilingStart - the entry function of profiling command
|
||||
func mainAdminProfilingStart(ctx *cli.Context) error {
|
||||
// Check for command syntax
|
||||
checkAdminProfilingStartSyntax(ctx)
|
||||
|
||||
// Get the alias parameter from cli
|
||||
args := ctx.Args()
|
||||
aliasedURL := args.Get(0)
|
||||
|
||||
profilerType := ctx.String("type")
|
||||
|
||||
// Create a new Minio Admin Client
|
||||
client, err := newAdminClient(aliasedURL)
|
||||
if err != nil {
|
||||
fatalIf(err.Trace(aliasedURL), "Cannot initialize admin client.")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Start profiling
|
||||
_, cmdErr := client.StartProfiling(madmin.ProfilerType(profilerType))
|
||||
fatalIf(probe.NewError(cmdErr), "Unable to start profiling.")
|
||||
|
||||
console.Infoln("Profiling data successfully started.")
|
||||
return nil
|
||||
}
|
||||
106
cmd/admin-profiling-stop.go
Normal file
106
cmd/admin-profiling-stop.go
Normal file
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Minio Client (C) 2018 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 cmd
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/minio/cli"
|
||||
"github.com/minio/mc/pkg/console"
|
||||
"github.com/minio/mc/pkg/probe"
|
||||
)
|
||||
|
||||
var adminProfilingStopCmd = cli.Command{
|
||||
Name: "stop",
|
||||
Usage: "Stop and download profiling data",
|
||||
Action: mainAdminProfilingStop,
|
||||
Before: setGlobalsFromContext,
|
||||
Flags: globalFlags,
|
||||
HideHelpCommand: true,
|
||||
CustomHelpTemplate: `NAME:
|
||||
{{.HelpName}} - {{.Usage}}
|
||||
|
||||
USAGE:
|
||||
{{.HelpName}} [FLAGS] TARGET
|
||||
|
||||
FLAGS:
|
||||
{{range .VisibleFlags}}{{.}}
|
||||
{{end}}
|
||||
EXAMPLES:
|
||||
2. Download latest profiling data in the current directory
|
||||
$ {{.HelpName}} myminio/
|
||||
`,
|
||||
}
|
||||
|
||||
func checkAdminProfilingStopSyntax(ctx *cli.Context) {
|
||||
if len(ctx.Args()) != 1 {
|
||||
cli.ShowCommandHelpAndExit(ctx, "stop", 1) // last argument is exit code
|
||||
}
|
||||
}
|
||||
|
||||
// mainAdminProfilingStop - the entry function of profiling stop command
|
||||
func mainAdminProfilingStop(ctx *cli.Context) error {
|
||||
// Check for command syntax
|
||||
checkAdminProfilingStopSyntax(ctx)
|
||||
|
||||
// Get the alias parameter from cli
|
||||
args := ctx.Args()
|
||||
aliasedURL := args.Get(0)
|
||||
|
||||
// Create a new Minio Admin Client
|
||||
client, err := newAdminClient(aliasedURL)
|
||||
if err != nil {
|
||||
fatalIf(err.Trace(aliasedURL), "Cannot initialize admin client.")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Create profiling zip file
|
||||
tmpFile, e := ioutil.TempFile("", "mc-profiling-")
|
||||
fatalIf(probe.NewError(e), "Unable to download profiling data.")
|
||||
|
||||
// Ask for profiling data, which will come compressed with zip format
|
||||
zippedData, adminErr := client.DownloadProfilingData()
|
||||
fatalIf(probe.NewError(adminErr), "Unable to download profiling data.")
|
||||
|
||||
// Copy zip content to target download file
|
||||
_, e = io.Copy(tmpFile, zippedData)
|
||||
fatalIf(probe.NewError(e), "Unable to download profiling data.")
|
||||
|
||||
// Close everything
|
||||
zippedData.Close()
|
||||
tmpFile.Close()
|
||||
|
||||
downloadPath := "profiling.zip"
|
||||
|
||||
fi, e := os.Stat(downloadPath)
|
||||
if e == nil && !fi.IsDir() {
|
||||
e = os.Rename(downloadPath, downloadPath+"."+time.Now().Format("2006-01-02T15:04:05.999999-07:00"))
|
||||
fatalIf(probe.NewError(e), "Unable to create a backup of profiling.zip")
|
||||
} else {
|
||||
if !os.IsNotExist(e) {
|
||||
fatal(probe.NewError(e), "Unable to download profiling data.")
|
||||
}
|
||||
}
|
||||
|
||||
fatalIf(probe.NewError(os.Rename(tmpFile.Name(), downloadPath)), "Unable to download profiling data.")
|
||||
|
||||
console.Infof("Profiling data successfully downloaded as %s\n", downloadPath)
|
||||
return nil
|
||||
}
|
||||
40
cmd/admin-profiling.go
Normal file
40
cmd/admin-profiling.go
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Minio Client (C) 2018 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 cmd
|
||||
|
||||
import (
|
||||
"github.com/minio/cli"
|
||||
)
|
||||
|
||||
var adminProfilingCmd = cli.Command{
|
||||
Name: "profiling",
|
||||
Usage: "Generate profiling data for debugging purposes",
|
||||
Action: mainAdminProfiling,
|
||||
Before: setGlobalsFromContext,
|
||||
Flags: globalFlags,
|
||||
Subcommands: []cli.Command{
|
||||
adminProfilingStartCmd,
|
||||
adminProfilingStopCmd,
|
||||
},
|
||||
HideHelpCommand: true,
|
||||
}
|
||||
|
||||
// mainAdminProfiling is the handle for "mc admin profiling" command.
|
||||
func mainAdminProfiling(ctx *cli.Context) error {
|
||||
cli.ShowCommandHelp(ctx, ctx.Args().First())
|
||||
return nil
|
||||
}
|
||||
@@ -45,6 +45,10 @@ func fatalIf(err *probe.Error, msg string, data ...interface{}) {
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
fatal(err, msg, data...)
|
||||
}
|
||||
|
||||
func fatal(err *probe.Error, msg string, data ...interface{}) {
|
||||
if globalJSON {
|
||||
errorMsg := errorMessage{
|
||||
Message: msg,
|
||||
|
||||
104
vendor/github.com/minio/minio/pkg/madmin/API.md
generated
vendored
104
vendor/github.com/minio/minio/pkg/madmin/API.md
generated
vendored
@@ -36,12 +36,12 @@ func main() {
|
||||
|
||||
```
|
||||
|
||||
| Service operations | Info operations | Healing operations | Config operations | IAM operations | Misc |
|
||||
|:----------------------------|:----------------------------|:--------------------------------------|:--------------------------|:------------------------------------|:------------------------------------|
|
||||
| [`ServiceStatus`](#ServiceStatus) | [`ServerInfo`](#ServerInfo) | [`Heal`](#Heal) | [`GetConfig`](#GetConfig) | [`AddUser`](#AddUser) | [`SetAdminCredentials`](#SetAdminCredentials) |
|
||||
| [`ServiceSendAction`](#ServiceSendAction) | | | [`SetConfig`](#SetConfig) | [`SetUserPolicy`](#SetUserPolicy) | [`StartProfiling`](#StartProfiling) |
|
||||
| | | | [`GetConfigKeys`](#GetConfigKeys) | [`ListUsers`](#ListUsers) | [`DownloadProfilingData`](#DownloadProfilingData) |
|
||||
| | | | [`SetConfigKeys`](#SetConfigKeys) | [`AddCannedPolicy`](#AddCannedPolicy) | |
|
||||
| Service operations | Info operations | Healing operations | Config operations | Misc |
|
||||
|:----------------------------|:----------------------------|:--------------------------------------|:--------------------------|:------------------------------------|
|
||||
| [`ServiceStatus`](#ServiceStatus) | [`ServerInfo`](#ServerInfo) | [`Heal`](#Heal) | [`GetConfig`](#GetConfig) | [`SetCredentials`](#SetCredentials) |
|
||||
| [`ServiceSendAction`](#ServiceSendAction) | | | [`SetConfig`](#SetConfig) | [`StartProfiling`](#StartProfiling) |
|
||||
| | | | [`GetConfigKeys`](#GetConfigKeys) | [`DownloadProfilingData`](#DownloadProfilingData) |
|
||||
| | | | [`SetConfigKeys`](#SetConfigKeys) | |
|
||||
|
||||
|
||||
## 1. Constructor
|
||||
@@ -273,7 +273,7 @@ __Example__
|
||||
|
||||
<a name="GetConfig"></a>
|
||||
### GetConfig() ([]byte, error)
|
||||
Get current `config.json` of a Minio server.
|
||||
Get config.json of a minio setup.
|
||||
|
||||
__Example__
|
||||
|
||||
@@ -295,17 +295,37 @@ __Example__
|
||||
|
||||
|
||||
<a name="SetConfig"></a>
|
||||
### SetConfig(config io.Reader) error
|
||||
Set a new `config.json` for a Minio server.
|
||||
### SetConfig(config io.Reader) (SetConfigResult, error)
|
||||
Set config.json of a minio setup and restart setup for configuration
|
||||
change to take effect.
|
||||
|
||||
|
||||
| Param | Type | Description |
|
||||
|---|---|---|
|
||||
|`st.Status` | _bool_ | true if set-config succeeded, false otherwise. |
|
||||
|`st.NodeSummary.Name` | _string_ | Network address of the node. |
|
||||
|`st.NodeSummary.ErrSet` | _bool_ | Bool representation indicating if an error is encountered with the node.|
|
||||
|`st.NodeSummary.ErrMsg` | _string_ | String representation of the error (if any) on the node.|
|
||||
|
||||
|
||||
__Example__
|
||||
|
||||
``` go
|
||||
config := bytes.NewReader([]byte(`config.json contents go here`))
|
||||
if err := madmClnt.SetConfig(config); err != nil {
|
||||
result, err := madmClnt.SetConfig(config)
|
||||
if err != nil {
|
||||
log.Fatalf("failed due to: %v", err)
|
||||
}
|
||||
log.Println("SetConfig was successful")
|
||||
|
||||
var buf bytes.Buffer
|
||||
enc := json.NewEncoder(&buf)
|
||||
enc.SetEscapeHTML(false)
|
||||
enc.SetIndent("", "\t")
|
||||
err = enc.Encode(result)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
log.Println("SetConfig: ", string(buf.Bytes()))
|
||||
```
|
||||
|
||||
<a name="GetConfigKeys"></a>
|
||||
@@ -347,72 +367,18 @@ __Example__
|
||||
log.Println("New configuration successfully set")
|
||||
```
|
||||
|
||||
## 8. IAM operations
|
||||
|
||||
<a name="AddCannedPolicy"></a>
|
||||
### AddCannedPolicy(policyName string, policy string) error
|
||||
Create a new canned policy on Minio server.
|
||||
|
||||
__Example__
|
||||
## 8. Misc operations
|
||||
|
||||
```
|
||||
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 {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
```
|
||||
|
||||
<a name="AddUser"></a>
|
||||
### AddUser(user string, secret string) error
|
||||
Add a new user on a Minio server.
|
||||
|
||||
__Example__
|
||||
|
||||
``` go
|
||||
if err = madmClnt.AddUser("newuser", "newstrongpassword"); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
```
|
||||
|
||||
<a name="SetUserPolicy"></a>
|
||||
### SetUserPolicy(user string, policyName string) error
|
||||
Enable a canned policy `get-only` for a given user on Minio server.
|
||||
|
||||
__Example__
|
||||
|
||||
``` go
|
||||
if err = madmClnt.SetUserPolicy("newuser", "get-only"); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
```
|
||||
|
||||
<a name="ListUsers"></a>
|
||||
### ListUsers() (map[string]UserInfo, error)
|
||||
Lists all users on Minio server.
|
||||
|
||||
__Example__
|
||||
|
||||
``` go
|
||||
users, err := madmClnt.ListUsers();
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
for k, v := range users {
|
||||
fmt.Printf("User %s Status %s\n", k, v.Status)
|
||||
}
|
||||
```
|
||||
|
||||
## 9. Misc operations
|
||||
|
||||
<a name="SetAdminCredentials"></a>
|
||||
### SetAdminCredentials() error
|
||||
<a name="SetCredentials"></a>
|
||||
### SetCredentials() error
|
||||
Set new credentials of a Minio setup.
|
||||
|
||||
__Example__
|
||||
|
||||
``` go
|
||||
err = madmClnt.SetAdminCredentials("YOUR-NEW-ACCESSKEY", "YOUR-NEW-SECRETKEY")
|
||||
err = madmClnt.SetCredentials("YOUR-NEW-ACCESSKEY", "YOUR-NEW-SECRETKEY")
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
6
vendor/vendor.json
vendored
6
vendor/vendor.json
vendored
@@ -134,10 +134,10 @@
|
||||
"revisionTime": "2018-09-25T09:12:15Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "/5zp4gweRyx0NTrMTEwhCqdMaDA=",
|
||||
"checksumSHA1": "/OdvNthJAc6DQQ7waRjvzAc7Q3c=",
|
||||
"path": "github.com/minio/minio/pkg/madmin",
|
||||
"revision": "79e0add0e50323873b5d30fb41ef70584a9b6f22",
|
||||
"revisionTime": "2018-10-16T19:47:06Z"
|
||||
"revision": "aebfceeafb410452d1c03edfa69b7bc5509cc1bc",
|
||||
"revisionTime": "2018-09-29T08:17:01Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "flg07CqTxM9togozKRQiJugao4s=",
|
||||
|
||||
Reference in New Issue
Block a user