mirror of
https://github.com/pgsty/minio.git
synced 2026-07-20 12:40:24 +03:00
Implement list, clear locks REST API w/ pkg/madmin support (#3491)
* Filter lock info based on bucket, prefix and time since lock was held * Implement list and clear locks REST API * madmin: Add list and clear locks API * locks: Clear locks matching bucket, prefix, relTime. * Gather lock information across nodes for both list and clear locks admin REST API. * docs: Add lock API to management APIs
This commit is contained in:
committed by
Harshavardhana
parent
cae62ce543
commit
c8f57133a4
+136
-9
@@ -19,6 +19,8 @@ package cmd
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -28,9 +30,8 @@ const (
|
||||
// ServiceStatusHandler - GET /?service
|
||||
// HTTP header x-minio-operation: status
|
||||
// ----------
|
||||
// This implementation of the GET operation fetches server status information.
|
||||
// provides total disk space available to use, online disks, offline disks and
|
||||
// quorum threshold.
|
||||
// Fetches server status information like total disk space available
|
||||
// to use, online disks, offline disks and quorum threshold.
|
||||
func (adminAPI adminAPIHandlers) ServiceStatusHandler(w http.ResponseWriter, r *http.Request) {
|
||||
adminAPIErr := checkRequestAuthType(r, "", "", "")
|
||||
if adminAPIErr != ErrNone {
|
||||
@@ -44,15 +45,16 @@ func (adminAPI adminAPIHandlers) ServiceStatusHandler(w http.ResponseWriter, r *
|
||||
errorIf(err, "Failed to marshal storage info into json.")
|
||||
return
|
||||
}
|
||||
// Reply with storage information (across nodes in a
|
||||
// distributed setup) as json.
|
||||
writeSuccessResponse(w, jsonBytes)
|
||||
}
|
||||
|
||||
// ServiceStopHandler - POST /?service
|
||||
// HTTP header x-minio-operation: stop
|
||||
// ----------
|
||||
// This implementation of the POST operation stops minio server gracefully,
|
||||
// in a distributed setup stops all the servers in the cluster. Body sent
|
||||
// if any on client request is ignored.
|
||||
// Stops minio server gracefully. In a distributed setup, stops all the
|
||||
// servers in the cluster.
|
||||
func (adminAPI adminAPIHandlers) ServiceStopHandler(w http.ResponseWriter, r *http.Request) {
|
||||
adminAPIErr := checkRequestAuthType(r, "", "", "")
|
||||
if adminAPIErr != ErrNone {
|
||||
@@ -67,9 +69,8 @@ func (adminAPI adminAPIHandlers) ServiceStopHandler(w http.ResponseWriter, r *ht
|
||||
// ServiceRestartHandler - POST /?service
|
||||
// HTTP header x-minio-operation: restart
|
||||
// ----------
|
||||
// This implementation of the POST operation restarts minio server gracefully,
|
||||
// in a distributed setup restarts all the servers in the cluster. Body sent
|
||||
// if any on client request is ignored.
|
||||
// Restarts minio server gracefully. In a distributed setup, restarts
|
||||
// all the servers in the cluster.
|
||||
func (adminAPI adminAPIHandlers) ServiceRestartHandler(w http.ResponseWriter, r *http.Request) {
|
||||
adminAPIErr := checkRequestAuthType(r, "", "", "")
|
||||
if adminAPIErr != ErrNone {
|
||||
@@ -80,3 +81,129 @@ func (adminAPI adminAPIHandlers) ServiceRestartHandler(w http.ResponseWriter, r
|
||||
w.WriteHeader(http.StatusOK)
|
||||
sendServiceCmd(globalAdminPeers, serviceRestart)
|
||||
}
|
||||
|
||||
// Type-safe lock query params.
|
||||
type lockQueryKey string
|
||||
|
||||
// Only valid query params for list/clear locks management APIs.
|
||||
const (
|
||||
lockBucket lockQueryKey = "bucket"
|
||||
lockPrefix lockQueryKey = "prefix"
|
||||
lockOlderThan lockQueryKey = "older-than"
|
||||
)
|
||||
|
||||
// validateLockQueryParams - Validates query params for list/clear locks management APIs.
|
||||
func validateLockQueryParams(vars url.Values) (string, string, time.Duration, APIErrorCode) {
|
||||
bucket := vars.Get(string(lockBucket))
|
||||
prefix := vars.Get(string(lockPrefix))
|
||||
relTimeStr := vars.Get(string(lockOlderThan))
|
||||
|
||||
// N B empty bucket name is invalid
|
||||
if !IsValidBucketName(bucket) {
|
||||
return "", "", time.Duration(0), ErrInvalidBucketName
|
||||
}
|
||||
|
||||
// empty prefix is valid.
|
||||
if !IsValidObjectPrefix(prefix) {
|
||||
return "", "", time.Duration(0), ErrInvalidObjectName
|
||||
}
|
||||
|
||||
// If older-than parameter was empty then set it to 0s to list
|
||||
// all locks older than now.
|
||||
if relTimeStr == "" {
|
||||
relTimeStr = "0s"
|
||||
}
|
||||
relTime, err := time.ParseDuration(relTimeStr)
|
||||
if err != nil {
|
||||
errorIf(err, "Failed to parse duration passed as query value.")
|
||||
return "", "", time.Duration(0), ErrInvalidDuration
|
||||
}
|
||||
|
||||
return bucket, prefix, relTime, ErrNone
|
||||
}
|
||||
|
||||
// ListLocksHandler - GET /?lock&bucket=mybucket&prefix=myprefix&older-than=rel_time
|
||||
// - bucket is a mandatory query parameter
|
||||
// - prefix and older-than are optional query parameters
|
||||
// HTTP header x-minio-operation: list
|
||||
// ---------
|
||||
// Lists locks held on a given bucket, prefix and relative time.
|
||||
func (adminAPI adminAPIHandlers) ListLocksHandler(w http.ResponseWriter, r *http.Request) {
|
||||
adminAPIErr := checkRequestAuthType(r, "", "", "")
|
||||
if adminAPIErr != ErrNone {
|
||||
writeErrorResponse(w, r, adminAPIErr, r.URL.Path)
|
||||
return
|
||||
}
|
||||
|
||||
vars := r.URL.Query()
|
||||
bucket, prefix, relTime, adminAPIErr := validateLockQueryParams(vars)
|
||||
if adminAPIErr != ErrNone {
|
||||
writeErrorResponse(w, r, adminAPIErr, r.URL.Path)
|
||||
return
|
||||
}
|
||||
|
||||
// Fetch lock information of locks matching bucket/prefix that
|
||||
// are available since relTime.
|
||||
volLocks, err := listPeerLocksInfo(globalAdminPeers, bucket, prefix, relTime)
|
||||
if err != nil {
|
||||
writeErrorResponse(w, r, ErrInternalError, r.URL.Path)
|
||||
errorIf(err, "Failed to fetch lock information from remote nodes.")
|
||||
return
|
||||
}
|
||||
|
||||
// Marshal list of locks as json.
|
||||
jsonBytes, err := json.Marshal(volLocks)
|
||||
if err != nil {
|
||||
writeErrorResponseNoHeader(w, r, ErrInternalError, r.URL.Path)
|
||||
errorIf(err, "Failed to marshal lock information into json.")
|
||||
return
|
||||
}
|
||||
|
||||
// Reply with list of locks held on bucket, matching prefix
|
||||
// older than relTime supplied, as json.
|
||||
writeSuccessResponse(w, jsonBytes)
|
||||
}
|
||||
|
||||
// ClearLocksHandler - POST /?lock&bucket=mybucket&prefix=myprefix&older-than=relTime
|
||||
// - bucket is a mandatory query parameter
|
||||
// - prefix and older-than are optional query parameters
|
||||
// HTTP header x-minio-operation: clear
|
||||
// ---------
|
||||
// Clear locks held on a given bucket, prefix and relative time.
|
||||
func (adminAPI adminAPIHandlers) ClearLocksHandler(w http.ResponseWriter, r *http.Request) {
|
||||
adminAPIErr := checkRequestAuthType(r, "", "", "")
|
||||
if adminAPIErr != ErrNone {
|
||||
writeErrorResponse(w, r, adminAPIErr, r.URL.Path)
|
||||
return
|
||||
}
|
||||
|
||||
vars := r.URL.Query()
|
||||
bucket, prefix, relTime, adminAPIErr := validateLockQueryParams(vars)
|
||||
if adminAPIErr != ErrNone {
|
||||
writeErrorResponse(w, r, adminAPIErr, r.URL.Path)
|
||||
return
|
||||
}
|
||||
|
||||
// Fetch lock information of locks matching bucket/prefix that
|
||||
// are available since relTime.
|
||||
volLocks, err := listPeerLocksInfo(globalAdminPeers, bucket, prefix, relTime)
|
||||
if err != nil {
|
||||
writeErrorResponseNoHeader(w, r, ErrInternalError, r.URL.Path)
|
||||
errorIf(err, "Failed to fetch lock information from remote nodes.")
|
||||
return
|
||||
}
|
||||
|
||||
// Marshal list of locks as json.
|
||||
jsonBytes, err := json.Marshal(volLocks)
|
||||
if err != nil {
|
||||
writeErrorResponseNoHeader(w, r, ErrInternalError, r.URL.Path)
|
||||
errorIf(err, "Failed to marshal lock information into json.")
|
||||
return
|
||||
}
|
||||
// Remove lock matching bucket/prefix older than relTime.
|
||||
for _, volLock := range volLocks {
|
||||
globalNSMutex.ForceUnlock(volLock.Bucket, volLock.Object)
|
||||
}
|
||||
// Reply with list of locks cleared, as json.
|
||||
writeSuccessResponse(w, jsonBytes)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user