diff --git a/cmd/admin-main.go b/cmd/admin-main.go
index 143bbd7951..387722031c 100644
--- a/cmd/admin-main.go
+++ b/cmd/admin-main.go
@@ -37,6 +37,7 @@ var adminCmd = cli.Command{
adminCredsCmd,
adminConfigCmd,
adminHealCmd,
+ adminProfilingCmd,
},
}
diff --git a/cmd/admin-profiling-start.go b/cmd/admin-profiling-start.go
new file mode 100644
index 0000000000..14da04bbc3
--- /dev/null
+++ b/cmd/admin-profiling-start.go
@@ -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
+}
diff --git a/cmd/admin-profiling-stop.go b/cmd/admin-profiling-stop.go
new file mode 100644
index 0000000000..0ab4b3dbdb
--- /dev/null
+++ b/cmd/admin-profiling-stop.go
@@ -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
+}
diff --git a/cmd/admin-profiling.go b/cmd/admin-profiling.go
new file mode 100644
index 0000000000..6fe7d59e10
--- /dev/null
+++ b/cmd/admin-profiling.go
@@ -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
+}
diff --git a/cmd/error.go b/cmd/error.go
index 30c4976bb2..f4572e42c3 100644
--- a/cmd/error.go
+++ b/cmd/error.go
@@ -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,
diff --git a/vendor/github.com/minio/minio/pkg/madmin/API.md b/vendor/github.com/minio/minio/pkg/madmin/API.md
index 75469df5c5..23aa8e989c 100644
--- a/vendor/github.com/minio/minio/pkg/madmin/API.md
+++ b/vendor/github.com/minio/minio/pkg/madmin/API.md
@@ -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__
### GetConfig() ([]byte, error)
-Get current `config.json` of a Minio server.
+Get config.json of a minio setup.
__Example__
@@ -295,17 +295,37 @@ __Example__
-### 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()))
```
@@ -347,72 +367,18 @@ __Example__
log.Println("New configuration successfully set")
```
-## 8. IAM operations
-
-
-### AddCannedPolicy(policyName string, policy string) error
-Create a new canned policy on Minio server.
-
-__Example__
-
-```
- 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)
- }
-```
-
-
-### 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)
- }
-```
-
-
-### 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)
- }
-```
-
-
-### 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
+## 8. Misc operations
-
-### SetAdminCredentials() error
+
+### 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)
}
diff --git a/vendor/vendor.json b/vendor/vendor.json
index 419e9d6f6a..0b4bda1ffb 100644
--- a/vendor/vendor.json
+++ b/vendor/vendor.json
@@ -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=",