1
0
mirror of https://github.com/minio/mc.git synced 2025-07-30 07:23:03 +03:00

Remove/deprecate admin lock commands (#2503)

This commit is contained in:
Harshavardhana
2018-08-06 12:59:13 -07:00
committed by Dee Koder
parent 9998e077df
commit 26f5102eae
11 changed files with 25 additions and 590 deletions

View File

@ -1,153 +0,0 @@
/*
* Minio Client (C) 2016 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 (
"encoding/json"
"fmt"
"path/filepath"
"time"
"github.com/minio/cli"
"github.com/minio/mc/pkg/probe"
"github.com/minio/minio/pkg/madmin"
)
var (
adminLockClearFlags = []cli.Flag{
cli.StringFlag{
Name: "duration, d",
Usage: "Only clear locks held for longer than NN[h|m|s]",
Value: "0s",
},
cli.BoolFlag{
Name: "force",
Usage: "Force a clear lock operation",
},
}
)
var adminLockClearCmd = cli.Command{
Name: "clear",
Usage: "Clear locks held in a given Minio server",
Before: setGlobalsFromContext,
Action: mainAdminLockClear,
Flags: append(adminLockClearFlags, globalFlags...),
CustomHelpTemplate: `NAME:
{{.HelpName}} - {{.Usage}}
USAGE:
{{.HelpName}} [FLAGS] TARGET
FLAGS:
{{range .VisibleFlags}}{{.}}
{{end}}
EXAMPLES:
1. Clear all locks held on 'testbucket' in a Minio server with alias 'play'.
$ {{.HelpName}} --force play/testbucket
2. Clear all 'testbucket' locks older than 15 minutes.
$ {{.HelpName}} --force --duration 15m play/testbucket/
3. Clear all locks held on all objects under prefix 'dir'.
$ {{.HelpName}} --force play/testbucket/dir/
`,
}
// lockClearMessage container to hold locks information.
type lockClearMessage struct {
Status string `json:"status"`
madmin.VolumeLockInfo
}
// String colorized service status message.
func (u lockClearMessage) String() string {
msg := fmt.Sprintf("%s/%s (LocksOnObject: %d, locksAcquiredOnObject: %d, totalBlockLocks:%d): ",
u.Bucket,
u.Object,
u.LocksOnObject,
u.LocksAcquiredOnObject,
u.TotalBlockedLocks)
for _, detail := range u.LockDetailsOnObject {
msg += fmt.Sprintf(" %+v", detail)
}
msg += "\n"
return msg
}
// JSON jsonified service status Message message.
func (u lockClearMessage) JSON() string {
u.Status = "success"
statusJSONBytes, e := json.Marshal(u)
fatalIf(probe.NewError(e), "Unable to marshal into JSON.")
return string(statusJSONBytes)
}
// checkAdminLockClearSyntax - validate all the passed arguments
func checkAdminLockClearSyntax(ctx *cli.Context) {
if len(ctx.Args()) == 0 || len(ctx.Args()) > 2 {
cli.ShowCommandHelpAndExit(ctx, "clear", 1)
}
// Check if a bucket is specified.
aliasedURL := filepath.ToSlash(ctx.Args().Get(0))
splits := splitStr(aliasedURL, "/", 3)
if splits[1] == "" {
fatalIf(errBucketNotSpecified().Trace(aliasedURL), "Cannot clear locks.")
}
if isForce := ctx.Bool("force"); isForce {
return
}
fatalIf(errDummy().Trace(),
"Clearing locks requires --force flag. This operation is "+
"*IRREVERSIBLE*. Please review carefully before"+
" performing this *DANGEROUS* operation.")
}
func mainAdminLockClear(ctx *cli.Context) error {
checkAdminLockClearSyntax(ctx)
// Get the alias parameter from cli
args := ctx.Args()
aliasedURL := args.Get(0)
// Parse duration flag
duration, e := time.ParseDuration(ctx.String("duration"))
fatalIf(probe.NewError(e), "Unable to parse the passed duration flag.")
// Create a new Minio Admin Client
client, err := newAdminClient(aliasedURL)
fatalIf(err, "Cannot get a configured admin connection.")
aliasedURL = filepath.ToSlash(aliasedURL)
splits := splitStr(aliasedURL, "/", 3)
// Clear locks related to a specified pair of bucket and prefix
locksInfo, e := client.ClearLocks(splits[1], splits[2], duration)
fatalIf(probe.NewError(e), "Cannot clear the specified locks.")
for _, l := range locksInfo {
printMsg(lockClearMessage{VolumeLockInfo: l})
}
return nil
}

View File

@ -1,140 +0,0 @@
/*
* Minio Client (C) 2016 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 (
"encoding/json"
"fmt"
"path/filepath"
"time"
"github.com/minio/cli"
"github.com/minio/mc/pkg/probe"
"github.com/minio/minio/pkg/madmin"
)
var (
adminLockListFlags = []cli.Flag{
cli.StringFlag{
Name: "duration, d",
Usage: "Only show locks that are held for longer than NN[h|m|s]",
Value: "24h",
},
}
)
var adminLockListCmd = cli.Command{
Name: "list",
Usage: "List locks held in a given Minio server",
Action: mainAdminLockList,
Before: setGlobalsFromContext,
Flags: append(adminLockListFlags, globalFlags...),
CustomHelpTemplate: `NAME:
{{.HelpName}} - {{.Usage}}
USAGE:
{{.HelpName}} [FLAGS] TARGET
FLAGS:
{{range .VisibleFlags}}{{.}}
{{end}}
EXAMPLES:
1. List locks held on 'testbucket' in a Minio server with alias 'play'.
$ {{.HelpName}} play/testbucket/
2. List locks held on 'testbucket' for more than 15 minutes.
$ {{.HelpName}} --duration 15m play/testbucket/
3. List locks held on all objects under prefix 'dir'.
$ {{.HelpName}} play/testbucket/dir/
`,
}
// lockListMessage container to hold locks information.
type lockListMessage struct {
Status string `json:"status"`
madmin.VolumeLockInfo
}
// String colorized service status message.
func (u lockListMessage) String() string {
msg := fmt.Sprintf("%s/%s (LocksOnObject: %d, locksAcquiredOnObject: %d, totalBlockLocks:%d): ",
u.Bucket,
u.Object,
u.LocksOnObject,
u.LocksAcquiredOnObject,
u.TotalBlockedLocks)
for _, detail := range u.LockDetailsOnObject {
msg += fmt.Sprintf(" %+v", detail)
}
msg += "\n"
return msg
}
// JSON jsonified service status Message message.
func (u lockListMessage) JSON() string {
u.Status = "success"
statusJSONBytes, e := json.Marshal(u)
fatalIf(probe.NewError(e), "Unable to marshal into JSON.")
return string(statusJSONBytes)
}
// checkAdminLockListSyntax - validate all the passed arguments
func checkAdminLockListSyntax(ctx *cli.Context) {
if len(ctx.Args()) == 0 || len(ctx.Args()) > 2 {
cli.ShowCommandHelpAndExit(ctx, "list", 1) // last argument is exit code
}
// Check if a bucket is specified.
aliasedURL := filepath.ToSlash(ctx.Args().Get(0))
splits := splitStr(aliasedURL, "/", 3)
if splits[1] == "" {
fatalIf(errBucketNotSpecified().Trace(aliasedURL), "Cannot list locks.")
}
}
func mainAdminLockList(ctx *cli.Context) error {
checkAdminLockListSyntax(ctx)
// Get the alias parameter from cli
args := ctx.Args()
aliasedURL := args.Get(0)
// Parse duration flag
duration, e := time.ParseDuration(ctx.String("duration"))
fatalIf(probe.NewError(e), "Unable to parse the passed duration flag.")
// Create a new Minio Admin Client
client, err := newAdminClient(aliasedURL)
fatalIf(err, "Cannot get a configured admin connection.")
aliasedURL = filepath.ToSlash(aliasedURL)
splits := splitStr(aliasedURL, "/", 3)
// Fetch the lock info related to a specified pair of bucket and prefix
locksInfo, e := client.ListLocks(splits[1], splits[2], duration)
fatalIf(probe.NewError(e), "Cannot get lock status.")
for _, l := range locksInfo {
printMsg(lockListMessage{VolumeLockInfo: l})
}
return nil
}

View File

@ -1,43 +0,0 @@
/*
* Minio Client (C) 2016 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 (
adminLockFlags = []cli.Flag{}
)
var adminLockCmd = cli.Command{
Name: "lock",
Usage: "Control locks in servers",
Action: mainAdminLock,
Before: setGlobalsFromContext,
Flags: append(adminLockFlags, globalFlags...),
Subcommands: []cli.Command{
adminLockListCmd,
adminLockClearCmd,
},
HideHelpCommand: true,
}
// mainAdminLock is the handle for "mc admin lock" command.
func mainAdminLock(ctx *cli.Context) error {
cli.ShowCommandHelp(ctx, ctx.Args().First())
return nil
// Sub-commands like "list", "unlock" have their own main.
}

View File

@ -34,7 +34,6 @@ var adminCmd = cli.Command{
adminInfoCmd,
adminCredsCmd,
adminConfigCmd,
adminLockCmd,
adminHealCmd,
},
}

View File

@ -116,10 +116,3 @@ var errSourceTargetSame = func(URL string) *probe.Error {
msg := "Source and target URL can not be same : " + URL
return probe.NewError(sourceTargetSameErr(errors.New(msg))).Untrace()
}
type bucketNotSpecifiedErr error
var errBucketNotSpecified = func() *probe.Error {
msg := "This operation requires a " + "bucket to be specified."
return probe.NewError(bucketNotSpecifiedErr(errors.New(msg))).Untrace()
}

View File

@ -36,10 +36,10 @@ func main() {
```
| Service operations | Info operations | LockInfo operations | Healing operations | Config operations | Misc |
| Service operations | Info operations | Healing operations | Config operations | Misc |
|:------------------------------------|:----------------------------|:----------------------------|:--------------------------------------|:--------------------------|:------------------------------------|
| [`ServiceStatus`](#ServiceStatus) | [`ServerInfo`](#ServerInfo) | [`ListLocks`](#ListLocks) | [`Heal`](#Heal) | [`GetConfig`](#GetConfig) | [`SetCredentials`](#SetCredentials) |
| [`ServiceSendAction`](#ServiceSendAction) | | [`ClearLocks`](#ClearLocks) | | [`SetConfig`](#SetConfig) | |
| [`ServiceStatus`](#ServiceStatus) | [`ServerInfo`](#ServerInfo) | [`Heal`](#Heal) | [`GetConfig`](#GetConfig) | [`SetCredentials`](#SetCredentials) |
| [`ServiceSendAction`](#ServiceSendAction) | | | [`SetConfig`](#SetConfig) | |
## 1. Constructor
@ -203,38 +203,6 @@ Fetches information for all cluster nodes, such as server properties, storage in
```
## 5. Lock operations
<a name="ListLocks"></a>
### ListLocks(bucket, prefix string, duration time.Duration) ([]VolumeLockInfo, error)
If successful returns information on the list of locks held on ``bucket`` matching ``prefix`` for longer than ``duration`` seconds.
__Example__
``` go
volLocks, err := madmClnt.ListLocks("mybucket", "myprefix", 30 * time.Second)
if err != nil {
log.Fatalln(err)
}
log.Println("List of locks: ", volLocks)
```
<a name="ClearLocks"></a>
### ClearLocks(bucket, prefix string, duration time.Duration) ([]VolumeLockInfo, error)
If successful returns information on the list of locks cleared on ``bucket`` matching ``prefix`` for longer than ``duration`` seconds.
__Example__
``` go
volLocks, err := madmClnt.ClearLocks("mybucket", "myprefix", 30 * time.Second)
if err != nil {
log.Fatalln(err)
}
log.Println("List of locks cleared: ", volLocks)
```
## 6. Heal operations
<a name="Heal"></a>
@ -243,25 +211,26 @@ __Example__
Start a heal sequence that scans data under given (possible empty)
`bucket` and `prefix`. The `recursive` bool turns on recursive
traversal under the given path. `dryRun` does not mutate on-disk data,
but performs data validation. `incomplete` enables healing of
multipart uploads that are in progress. `removeBadFiles` removes
unrecoverable files. `statisticsOnly` turns off detailed
heal-operations reporting in the status call.
but performs data validation.
Two heal sequences on overlapping paths may not be initiated.
The progress of a heal should be followed using the `HealStatus`
The progress of a heal should be followed using the same API `Heal`
by providing the `clientToken` previously obtained from a `Heal`
API. The server accumulates results of the heal traversal and waits
for the client to receive and acknowledge them using the status
API. When the statistics-only option is set, the server only maintains
aggregates statistics - in this case, no acknowledgement of results is
required.
request by providing `clientToken`.
__Example__
``` go
healPath, err := madmClnt.HealStart("", "", true, false, true, false, false)
opts := madmin.HealOpts{
Recursive: true,
DryRun: false,
}
forceStart := false
healPath, err := madmClnt.Heal("", "", opts, "", forceStart)
if err != nil {
log.Fatalln(err)
}
@ -269,6 +238,14 @@ __Example__
```
#### HealStartSuccess structure
| Param | Type | Description |
|----|--------|--------|
| s.ClientToken | _string_ | A unique token for a successfully started heal operation, this token is used to request realtime progress of the heal operation. |
| s.ClientAddress | _string_ | Address of the client which initiated the heal operation, the client address has the form "host:port".|
| s.StartTime | _time.Time_ | Time when heal was initially started.|
#### HealTaskStatus structure
| Param | Type | Description |
@ -277,7 +254,6 @@ __Example__
| s.FailureDetail | _string_ | Error message in case of heal sequence failure |
| s.HealSettings | _HealOpts_ | Contains the booleans set in the `HealStart` call |
| s.Items | _[]HealResultItem_ | Heal records for actions performed by server |
| s.Statistics | _HealStatistics_ | Aggregate of heal records from beginning |
#### HealResultItem structure
@ -291,38 +267,6 @@ __Example__
| DiskInfo.AvailableOn | _[]int_ | List of disks on which the healed entity is present and healthy |
| DiskInfo.HealedOn | _[]int_ | List of disks on which the healed entity was restored |
#### HealStatistics structure
Most parameters represent the aggregation of heal operations since the
start of the heal sequence.
| Param | Type | Description |
|-------|-----|----------|
| NumDisks | _int_ | Number of disks configured in the backend |
| NumBucketsScanned | _int64_ | Number of buckets scanned |
| BucketsMissingByDisk | _map[int]int64_ | Map of disk to number of buckets missing |
| BucketsAvailableByDisk | _map[int]int64_ | Map of disk to number of buckets available |
| BucketsHealedByDisk | _map[int]int64_ | Map of disk to number of buckets healed on |
| NumObjectsScanned | _int64_ | Number of objects scanned |
| NumUploadsScanned | _int64_ | Number of uploads scanned |
| ObjectsByAvailablePC | _map[int64]_ | Map of available part counts (after heal) to number of objects |
| ObjectsByHealedPC | _map[int64]_ | Map of healed part counts to number of objects |
| ObjectsMissingByDisk | _map[int64]_ | Map of disk number to number of objects with parts missing on that disk |
| ObjectsAvailableByDisk | _map[int64]_ | Map of disk number to number of objects available on that disk |
| ObjectsHealedByDisk | _map[int64]_ | Map of disk number to number of objects healed on that disk |
__Example__
``` go
res, err := madmClnt.HealStatus("", "")
if err != nil {
log.Fatalln(err)
}
log.Printf("Heal sequence status data %#v", res)
```
## 7. Config operations
<a name="GetConfig"></a>

View File

@ -62,7 +62,7 @@ func (adm *AdminClient) GetConfig() ([]byte, error) {
return nil, httpRespToErrorResponse(resp)
}
// Return the JSON marshalled bytes to user.
// Return the JSON marshaled bytes to user.
return ioutil.ReadAll(resp.Body)
}

View File

@ -1,22 +0,0 @@
/*
* Minio Cloud Storage, (C) 2016 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
const (
// Unsigned payload.
unsignedPayload = "UNSIGNED-PAYLOAD"
)

View File

@ -1,135 +0,0 @@
/*
* Minio Cloud Storage, (C) 2016 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 (
"encoding/json"
"io"
"io/ioutil"
"net/http"
"net/url"
"time"
)
type statusType string
type lockType string
// OpsLockState - represents lock specific details.
type OpsLockState struct {
OperationID string `json:"id"` // String containing operation ID.
LockSource string `json:"source"` // Operation type (GetObject, PutObject...)
LockType lockType `json:"type"` // Lock type (RLock, WLock)
Status statusType `json:"status"` // Status can be Running/Ready/Blocked.
Since time.Time `json:"since"` // Time when the lock was initially held.
}
// VolumeLockInfo - represents summary and individual lock details of all
// locks held on a given bucket, object.
type VolumeLockInfo struct {
Bucket string `json:"bucket"`
Object string `json:"object"`
// All locks blocked + running for given <volume,path> pair.
LocksOnObject int64 `json:"-"`
// Count of operations which has successfully acquired the lock
// but hasn't unlocked yet( operation in progress).
LocksAcquiredOnObject int64 `json:"-"`
// Count of operations which are blocked waiting for the lock
// to be released.
TotalBlockedLocks int64 `json:"-"`
// Count of all read locks
TotalReadLocks int64 `json:"readLocks"`
// Count of all write locks
TotalWriteLocks int64 `json:"writeLocks"`
// State information containing state of the locks for all operations
// on given <volume,path> pair.
LockDetailsOnObject []OpsLockState `json:"lockOwners"`
}
// getLockInfos - unmarshal []VolumeLockInfo from a reader.
func getLockInfos(body io.Reader) ([]VolumeLockInfo, error) {
respBytes, err := ioutil.ReadAll(body)
if err != nil {
return nil, err
}
var lockInfos []VolumeLockInfo
err = json.Unmarshal(respBytes, &lockInfos)
if err != nil {
return nil, err
}
return lockInfos, nil
}
// ListLocks - Calls List Locks Management API to fetch locks matching
// bucket, prefix and held before the duration supplied.
func (adm *AdminClient) ListLocks(bucket, prefix string,
duration time.Duration) ([]VolumeLockInfo, error) {
queryVal := make(url.Values)
queryVal.Set("bucket", bucket)
queryVal.Set("prefix", prefix)
queryVal.Set("older-than", duration.String())
// Execute GET on /minio/admin/v1/locks to list locks.
resp, err := adm.executeMethod("GET", requestData{
queryValues: queryVal,
relPath: "/v1/locks",
})
defer closeResponse(resp)
if err != nil {
return nil, err
}
if resp.StatusCode != http.StatusOK {
return nil, httpRespToErrorResponse(resp)
}
return getLockInfos(resp.Body)
}
// ClearLocks - Calls Clear Locks Management API to clear locks held
// on bucket, matching prefix older than duration supplied.
func (adm *AdminClient) ClearLocks(bucket, prefix string,
duration time.Duration) ([]VolumeLockInfo, error) {
queryVal := make(url.Values)
queryVal.Set("bucket", bucket)
queryVal.Set("prefix", prefix)
queryVal.Set("duration", duration.String())
// Execute POST on /?lock to clear locks.
resp, err := adm.executeMethod("DELETE", requestData{
queryValues: queryVal,
relPath: "/v1/locks",
})
defer closeResponse(resp)
if err != nil {
return nil, err
}
if resp.StatusCode != http.StatusOK {
return nil, httpRespToErrorResponse(resp)
}
return getLockInfos(resp.Body)
}

View File

@ -17,7 +17,6 @@
package madmin
import (
"crypto/md5"
"encoding/json"
"io"
"io/ioutil"
@ -38,13 +37,6 @@ func sum256(data []byte) []byte {
return hash.Sum(nil)
}
// sumMD5 calculate sumMD5 sum for an input byte array.
func sumMD5(data []byte) []byte {
hash := md5.New()
hash.Write(data)
return hash.Sum(nil)
}
// jsonDecoder decode json to go type.
func jsonDecoder(body io.Reader, v interface{}) error {
d := json.NewDecoder(body)

6
vendor/vendor.json vendored
View File

@ -134,10 +134,10 @@
"revisionTime": "2018-07-11T12:25:12Z"
},
{
"checksumSHA1": "MEC+K9aTG+8tfPjnJ4qj2Y+kc4s=",
"checksumSHA1": "FIs3tgGerLUN+S9IewYzFhJtQQY=",
"path": "github.com/minio/minio/pkg/madmin",
"revision": "3dc13323e51dc7038232f5f02f55b37b388c59c2",
"revisionTime": "2018-05-16T01:20:22Z"
"revision": "556a51120ce8a68c6745ab0b0e374390529479a8",
"revisionTime": "2018-08-02T17:39:42Z"
},
{
"checksumSHA1": "flg07CqTxM9togozKRQiJugao4s=",