Skip to content

Commit

Permalink
Add admin bucket quota command to manage quota
Browse files Browse the repository at this point in the history
  • Loading branch information
Poorna Krishnamoorthy committed Apr 24, 2020
1 parent 20dd701 commit 73b9817
Show file tree
Hide file tree
Showing 5 changed files with 266 additions and 0 deletions.
188 changes: 188 additions & 0 deletions cmd/admin-bucket-quota.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
/*
* MinIO Client (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 cmd

import (
"fmt"

humanize "github.com/dustin/go-humanize"
"github.com/fatih/color"
"github.com/minio/cli"
json "github.com/minio/mc/pkg/colorjson"
"github.com/minio/mc/pkg/probe"
"github.com/minio/minio/pkg/console"
"github.com/minio/minio/pkg/madmin"
)

var adminQuotaFlags = []cli.Flag{
cli.StringFlag{
Name: "fifo",
Usage: "Set fifo quota, allowing automatic deletion of older content",
},
cli.StringFlag{
Name: "hard",
Usage: "Set a hard quota, disallowing writes after quota is reached",
},
cli.BoolFlag{
Name: "clear",
Usage: "Clears bucket quota configured for bucket",
},
}

// quotaMessage container for content message structure
type quotaMessage struct {
op string
Status string `json:"status"`
Bucket string `json:"bucket"`
Quota uint64 `json:"quota,omitempty"`
QuotaType string `json:"type,omitempty"`
}

func (q quotaMessage) String() string {
if q.op == "set" {
return console.Colorize("QuotaMessage",
fmt.Sprintf("Successfully set bucket quota of %s with %s type on `%s`", humanize.IBytes(q.Quota), q.QuotaType, q.Bucket))
}
if q.op == "unset" {
return console.Colorize("QuotaMessage",
fmt.Sprintf("Successfully cleared bucket quota configured on `%s`", q.Bucket))
}
return console.Colorize("QuotaInfo",
fmt.Sprintf("Bucket `%s` has %s quota of %s", q.Bucket, q.QuotaType, humanize.IBytes(q.Quota)))
}

func (q quotaMessage) JSON() string {
q.Status = "success"
jsonMessageBytes, e := json.MarshalIndent(q, "", " ")
fatalIf(probe.NewError(e), "Unable to marshal into JSON.")

return string(jsonMessageBytes)
}

var adminBucketQuotaCmd = cli.Command{
Name: "quota",
Usage: "Manage bucket quota",
Action: mainAdminBucketQuota,
Before: setGlobalsFromContext,
Flags: append(adminQuotaFlags, globalFlags...),
CustomHelpTemplate: `NAME:
{{.HelpName}} - {{.Usage}}
USAGE:
{{.HelpName}} TARGET [--fifo | --hard] [QUOTA]
QUOTA
quota accepts human-readable case-insensitive number
suffixes such as "k", "m", "g" and "t" referring to the metric units KB,
MB, GB and TB respectively. Adding an "i" to these prefixes, uses the IEC
units, so that "gi" refers to "gibibyte" or "GiB". A "b" at the end is
also accepted. Without suffixes the unit is bytes.
FLAGS:
{{range .VisibleFlags}}{{.}}
{{end}}
EXAMPLES:
1. Display bucket quota configured for "mybucket" on MinIO.
{{.Prompt}} {{.HelpName}} myminio/mybucket
2. Set FIFO quota for a bucket "mybucket" on MinIO.
{{.Prompt}} {{.HelpName}} myminio/mybucket --fifo 64kB
3. Set hard quota of 1gb for a bucket "mybucket" on MinIO.
{{.Prompt}} {{.HelpName}} myminio/mybucket --hard 1gb
4. Clear bucket quota configured for bucket "mybucket" on MinIO.
{{.Prompt}} {{.HelpName}} myminio/mybucket --clear
`,
}

// checkAdminBucketQuotaSyntax - validate all the passed arguments
func checkAdminBucketQuotaSyntax(ctx *cli.Context) {
if len(ctx.Args()) == 0 || len(ctx.Args()) > 1 {
cli.ShowCommandHelpAndExit(ctx, "quota", 1) // last argument is exit code
}

if ctx.IsSet("hard") && ctx.IsSet("fifo") {
fatalIf(errInvalidArgument(), "Only one of --hard or --fifo flags can be set")
}
if (ctx.IsSet("hard") || ctx.IsSet("fifo")) && len(ctx.Args()) == 0 {
fatalIf(errInvalidArgument().Trace(ctx.Args()...), "please specify bucket and quota")
}
if ctx.IsSet("clear") && len(ctx.Args()) == 0 {
fatalIf(errInvalidArgument().Trace(ctx.Args()...), "clear flag must be passed with target alone")
}
}

// mainAdminBucketQuota is the handler for "mc admin bucket quota" command.
func mainAdminBucketQuota(ctx *cli.Context) error {
checkAdminBucketQuotaSyntax(ctx)

console.SetColor("QuotaMessage", color.New(color.FgGreen))
console.SetColor("QuotaInfo", color.New(color.FgBlue))

// Get the alias parameter from cli
args := ctx.Args()
aliasedURL := args.Get(0)

// Create a new MinIO Admin Client
client, err := newAdminClient(aliasedURL)
fatalIf(err, "Unable to initialize admin connection.")
quotaStr := ctx.String("fifo")
if ctx.IsSet("hard") {
quotaStr = ctx.String("hard")
}
_, targetURL := url2Alias(args[0])
if ctx.IsSet("fifo") || ctx.IsSet("hard") && len(args) == 1 {
qType := madmin.FIFOQuota
if ctx.IsSet("hard") {
qType = madmin.HardQuota
}
quota, err := humanize.ParseBytes(quotaStr)
fatalIf(probe.NewError(err).Trace(quotaStr), "Unable to parse quota")
if err = client.SetBucketQuota(globalContext, targetURL, quota, qType); err != nil {
fatalIf(probe.NewError(err).Trace(args...), "Cannot set bucket quota")

}
printMsg(quotaMessage{
op: "set",
Bucket: targetURL,
Quota: quota,
QuotaType: string(qType),
})
} else if ctx.Bool("clear") && len(args) == 1 {
if err := client.RemoveBucketQuota(globalContext, targetURL); err != nil {
fatalIf(probe.NewError(err).Trace(args...), "Cannot clear bucket quota config")
}
printMsg(quotaMessage{
op: "unset",
Bucket: targetURL,
})

} else {
qCfg, e := client.GetBucketQuota(globalContext, targetURL)
fatalIf(probe.NewError(e).Trace(args...), "Cannot get bucket quota")
printMsg(quotaMessage{
op: "get",
Bucket: targetURL,
Quota: qCfg.Quota,
QuotaType: string(qCfg.Type),
})
}

return nil
}
38 changes: 38 additions & 0 deletions cmd/admin-bucket.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* MinIO Client (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 cmd

import "github.com/minio/cli"

var adminBucketCmd = cli.Command{
Name: "bucket",
Usage: "manage buckets defined in the MinIO server",
Action: mainAdminBucket,
Before: setGlobalsFromContext,
Flags: globalFlags,
Subcommands: []cli.Command{
adminBucketQuotaCmd,
},
HideHelpCommand: true,
}

// mainAdminBucket is the handle for "mc admin bucket" command.
func mainAdminBucket(ctx *cli.Context) error {
cli.ShowCommandHelp(ctx, ctx.Args().First())
return nil
// Sub-commands like "quota", "usage" have their own main.
}
1 change: 1 addition & 0 deletions cmd/admin-main.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ var adminCmd = cli.Command{
adminPrometheusCmd,
adminKMSCmd,
adminOBDCmd,
adminBucketCmd,
},
}

Expand Down
37 changes: 37 additions & 0 deletions docs/minio-admin-complete-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -852,3 +852,40 @@ Key: test-key-1
• Encryption ✔
• Decryption ✔
```

<a name="quota"></a>
### Command `quota` - Set/Get bucket quota
`quota` command to set or get bucket quota on MinIO server.

```
NAME:
mc admin bucket quota - manage bucket quota
USAGE:
mc admin bucket quota TARGET [--fifo | --hard] [QUOTA]
QUOTA
quota accepts human-readable case-insensitive number
suffixes such as "k", "m", "g" and "t" referring to the metric units KB,
MB, GB and TB respectively. Adding an "i" to these prefixes, uses the IEC
units, so that "gi" refers to "gibibyte" or "GiB". A "b" at the end is
also accepted. Without suffixes the unit is bytes.
```
*Example: List bucket quota on bucket 'mybucket' on MinIO.*

```
mc admin bucket quota myminio/mybucket
```

*Example: Set a hard bucket quota of 64Mb for bucket 'mybucket' on MinIO.*

```
mc admin bucket quota myminio/mybucket --hard 64MB
```

*Example: Reset bucket quota configured for bucket 'mybucket' on MinIO.*

```
mc admin bucket quota myminio/mybucket --clear
```
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,5 @@ require (
gopkg.in/ini.v1 v1.55.0 // indirect
gopkg.in/yaml.v2 v2.2.4
)

replace github.com/minio/minio => ../minio

0 comments on commit 73b9817

Please sign in to comment.