feat(mastercli): add API to add storageClass to volume's allowedStorageClass list

Signed-off-by: true1064 <tangjingyu@oppo.com>
This commit is contained in:
true1064 2023-12-26 15:34:16 +08:00 committed by AmazingChi
parent 5bcc78bb43
commit 9d2bf3b483
10 changed files with 193 additions and 24 deletions

View File

@ -16,6 +16,7 @@ package cmd
import (
"fmt"
"math"
"sort"
"strconv"
"strings"
@ -55,6 +56,7 @@ func newVolCmd(client *master.MasterClient) *cobra.Command {
newVolSetAuditLogCmd(client),
newVolSetTrashIntervalCmd(client),
newVolSetDpRepairBlockSize(client),
newVolAddAllowedStorageClassCmd(client),
)
return cmd
}
@ -1236,3 +1238,54 @@ func newVolSetTrashIntervalCmd(client *master.MasterClient) *cobra.Command {
}
return cmd
}
var (
cmdVolAddAllowedStorageClassUse = "addAllowedStorageClass [VOLUME] [STORAGE_CLASS_TO_ADD] [flags]"
cmdVolAddAllowedStorageClassShort = "add a storageClass to volume's allowedStorageClass list"
)
func newVolAddAllowedStorageClassCmd(client *master.MasterClient) *cobra.Command {
var clientIDKey string
var addAllowedStorageClass uint32
var ascUint64 uint64
cmd := &cobra.Command{
Use: cmdVolAddAllowedStorageClassUse,
Short: cmdVolAddAllowedStorageClassShort,
Args: cobra.MinimumNArgs(2),
Run: func(cmd *cobra.Command, args []string) {
volName := args[0]
addAllowedStorageClassStr := args[1]
var err error
defer func() {
errout(err)
}()
ascUint64, err = strconv.ParseUint(addAllowedStorageClassStr, 10, 32)
if err != nil || ascUint64 > math.MaxUint32 {
err = fmt.Errorf("parse param[addAllowedStorageClass] is not valid uint32[%d], err %v", ascUint64, err)
return
}
addAllowedStorageClass = uint32(ascUint64)
if !proto.IsValidStorageClass(addAllowedStorageClass) {
err = fmt.Errorf("param[addAllowedStorageClass] is not valid storageClass: %v", addAllowedStorageClass)
return
}
var vv *proto.SimpleVolView
if vv, err = client.AdminAPI().GetVolumeSimpleInfo(volName); err != nil {
return
}
if err = client.AdminAPI().VolAddAllowedStorageClass(volName, addAllowedStorageClass, util.CalcAuthKey(vv.Owner), clientIDKey); err != nil {
return
}
stdout("Volume add allowedStorageClass successfully\n")
},
}
cmd.Flags().StringVar(&clientIDKey, CliFlagClientIDKey, client.ClientIDKey(), CliUsageClientIDKey)
return cmd
}

View File

@ -338,8 +338,8 @@ func extractUint32WithDefault(r *http.Request, key string, def uint32) (val uint
}
var valUint64 uint64
if valUint64, err = strconv.ParseUint(str, 10, 32); err != nil || valUint64 < 0 || valUint64 > math.MaxUint32 {
return 0, fmt.Errorf("parse [%s] is not valid uint64 [%d], err %v", key, val, err)
if valUint64, err = strconv.ParseUint(str, 10, 32); err != nil || valUint64 > math.MaxUint32 {
return 0, fmt.Errorf("parse [%s] is not valid uint32 [%d], err %v", key, val, err)
}
val = uint32(valUint64)
@ -1755,12 +1755,13 @@ func extractUint32(r *http.Request, key string) (val uint32, err error) {
return 0, nil
}
var tmp uint64
if tmp, err = strconv.ParseUint(str, 10, 32); err != nil {
return 0, fmt.Errorf("args [%s] is not legal, val %s", key, str)
var valUint64 uint64
if valUint64, err = strconv.ParseUint(str, 10, 32); err != nil || valUint64 > math.MaxUint32 {
return 0, fmt.Errorf("parse [%s] is not valid uint32 [%d], err %v", key, val, err)
}
return uint32(tmp), nil
val = uint32(valUint64)
return val, nil
}
func extractPositiveUint64(r *http.Request, key string) (val uint64, err error) {

View File

@ -7692,3 +7692,82 @@ func (m *Server) resetDecommissionDataNodeStatus(w http.ResponseWriter, r *http.
msg := fmt.Sprintf("reset decommission status for datanode %v success", dn.Addr)
sendOkReply(w, r, newSuccessHTTPReply(msg))
}
func (m *Server) volAddAllowedStorageClass(w http.ResponseWriter, r *http.Request) {
var (
name string
authKey string
err error
msg string
addAllowedStorageClass uint32
vol *Vol
)
metric := exporter.NewTPCnt(apiToMetricsName(proto.AdminVolAddAllowedStorageClass))
defer func() {
doStatAndMetric(proto.AdminVolAddAllowedStorageClass, metric, err, map[string]string{exporter.Vol: name})
}()
if err = r.ParseForm(); err != nil {
sendErrReply(w, r, &proto.HTTPReply{Code: proto.ErrCodeParamError, Msg: err.Error()})
return
}
if name, err = extractName(r); err != nil {
sendErrReply(w, r, &proto.HTTPReply{Code: proto.ErrCodeParamError, Msg: err.Error()})
return
}
if authKey, err = extractAuthKey(r); err != nil {
sendErrReply(w, r, &proto.HTTPReply{Code: proto.ErrCodeParamError, Msg: err.Error()})
return
}
if addAllowedStorageClass, err = extractUint32(r, allowedStorageClassKey); err != nil {
sendErrReply(w, r, &proto.HTTPReply{Code: proto.ErrCodeParamError, Msg: err.Error()})
return
}
if !proto.IsValidStorageClass(addAllowedStorageClass) {
err = fmt.Errorf("invalid storageClass(%v)", addAllowedStorageClass)
sendErrReply(w, r, &proto.HTTPReply{Code: proto.ErrCodeParamError, Msg: err.Error()})
return
}
if vol, err = m.cluster.getVol(name); err != nil {
sendErrReply(w, r, &proto.HTTPReply{Code: proto.ErrCodeVolNotExists, Msg: err.Error()})
return
}
if in := vol.isStorageClassInAllowed(addAllowedStorageClass); in {
err = fmt.Errorf("storageClass(%v) already in vol allowedStorageClass(%v)",
addAllowedStorageClass, vol.allowedStorageClass)
sendErrReply(w, r, &proto.HTTPReply{Code: proto.ErrCodeParamError, Msg: err.Error()})
return
}
resourceChecker := NewStorageClassResourceChecker(m.cluster)
if !resourceChecker.HasResourceOfStorageClass(addAllowedStorageClass) {
err = fmt.Errorf("cluster has no resoure to support storageClass(%v)",
proto.StorageClassString(addAllowedStorageClass))
sendErrReply(w, r, &proto.HTTPReply{Code: proto.ErrCodeParamError, Msg: err.Error()})
return
}
newArgs := getVolVarargs(vol)
newArgs.allowedStorageClass = append(newArgs.allowedStorageClass, addAllowedStorageClass)
sort.Slice(newArgs.allowedStorageClass, func(i, j int) bool {
return newArgs.allowedStorageClass[i] < newArgs.allowedStorageClass[j]
})
log.LogInfof("to add vol(%v) allowedStorageClass, old(%v), add(%v)",
name, vol.allowedStorageClass, addAllowedStorageClass)
if err = m.cluster.updateVol(name, authKey, newArgs); err != nil {
sendErrReply(w, r, newErrHTTPReply(err))
return
}
msg = fmt.Sprintf("add vol(%v) allowedStorageClass successfully", name)
log.LogInfof("%v, added(%v), current(%v)", msg, addAllowedStorageClass, vol.allowedStorageClass)
}

View File

@ -1669,7 +1669,7 @@ func (c *Cluster) batchCreateDataPartition(vol *Vol, reqCount int, init bool, me
}
if _, err = c.createDataPartition(vol.Name, nil, mediaType); err != nil {
log.LogErrorf("action[batchCreateDataPartition] after create [%v] data partition,occurred error,err[%v]", i, err)
log.LogErrorf("action[batchCreateDataPartition] after create [%v] data partition, occurred error,err[%v]", i, err)
break
}
createdCnt++
@ -3707,7 +3707,6 @@ func (c *Cluster) createVol(req *createVolReq) (vol *Vol, err error) {
req.name, readWriteDataPartitions, proto.MediaTypeString(chosenMediaType))
}
vol.dataPartitions.updateResponseCache(true, 0, vol.VolType)
vol.updateViewCache(c)
// NOTE: update dp view cache
vol.dataPartitions.updateResponseCache(true, 0, vol)

View File

@ -58,7 +58,7 @@ const (
cfgHttpReversePoolSize = "httpReversePoolSize"
cfgDefaultDataMediaType = "defaultDataMediaType" //for hybrid cloud
cfgDefaultDataMediaType = "defaultDataMediaType" // for hybrid cloud
)
// default value

View File

@ -170,11 +170,12 @@ var AuthenticationUri2MsgTypeMap = map[string]proto.MsgType{
proto.AdminSetNodeRdOnly: proto.MsgMasterSetNodeRdOnlyReq,
// Master API volume management
proto.AdminCreateVol: proto.MsgMasterCreateVolReq,
proto.AdminDeleteVol: proto.MsgMasterDeleteVolReq,
proto.AdminUpdateVol: proto.MsgMasterUpdateVolReq,
proto.AdminVolShrink: proto.MsgMasterVolShrinkReq,
proto.AdminVolExpand: proto.MsgMasterVolExpandReq,
proto.AdminCreateVol: proto.MsgMasterCreateVolReq,
proto.AdminDeleteVol: proto.MsgMasterDeleteVolReq,
proto.AdminUpdateVol: proto.MsgMasterUpdateVolReq,
proto.AdminVolShrink: proto.MsgMasterVolShrinkReq,
proto.AdminVolExpand: proto.MsgMasterVolExpandReq,
proto.AdminVolAddAllowedStorageClass: proto.MsgMasterVolAddAllowedStorageClass,
// Master API meta partition management
proto.AdminLoadMetaPartition: proto.MsgMasterLoadMetaPartitionReq,
@ -430,6 +431,9 @@ func (m *Server) registerAPIRoutes(router *mux.Router) {
router.NewRoute().Methods(http.MethodGet, http.MethodPost).
Path(proto.AdminAbortDecommissionDisk).
HandlerFunc(m.abortDecommissionDisk)
router.NewRoute().Methods(http.MethodGet, http.MethodPost).
Path(proto.AdminVolAddAllowedStorageClass).
HandlerFunc(m.volAddAllowedStorageClass)
// multi version snapshot APIs
router.NewRoute().Methods(http.MethodGet).

View File

@ -58,6 +58,7 @@ type VolVarargs struct {
accessTimeValidInterval int64
enablePersistAccessTime bool
volStorageClass uint32
allowedStorageClass []uint32
}
type CacheSubItem struct {
@ -1701,6 +1702,7 @@ func setVolFromArgs(args *VolVarargs, vol *Vol) {
vol.EnableAutoMetaRepair.Store(args.enableAutoDpMetaRepair)
vol.EnablePersistAccessTime = args.enablePersistAccessTime
vol.volStorageClass = args.volStorageClass
vol.allowedStorageClass = append([]uint32{}, args.allowedStorageClass...)
}
func getVolVarargs(vol *Vol) *VolVarargs {
@ -1744,6 +1746,7 @@ func getVolVarargs(vol *Vol) *VolVarargs {
enablePersistAccessTime: vol.EnablePersistAccessTime,
enableAutoDpMetaRepair: vol.EnableAutoMetaRepair.Load(),
volStorageClass: vol.volStorageClass,
allowedStorageClass: append([]uint32{}, vol.allowedStorageClass...),
}
}
@ -1814,3 +1817,16 @@ func (vol *Vol) checkDataReplicaMeta(c *Cluster) (cnt int) {
}
return
}
func (vol *Vol) isStorageClassInAllowed(storageClass uint32) (in bool) {
vol.volLock.Lock()
defer vol.volLock.Unlock()
for _, asc := range vol.allowedStorageClass {
if asc == storageClass {
in = true
}
}
return in
}

View File

@ -265,6 +265,8 @@ const (
S3QoSGet = "/s3/qos/get"
S3QoSDelete = "/s3/qos/delete"
AdminEnablePersistAccessTime = "/vol/enablePersistAccessTime"
AdminVolAddAllowedStorageClass = "/vol/addAllowedStorageClass"
)
var GApiInfo map[string]string = map[string]string{
@ -284,6 +286,7 @@ var GApiInfo map[string]string = map[string]string{
"adminupdatevol": AdminUpdateVol,
"adminvolshrink": AdminVolShrink,
"adminvolexpand": AdminVolExpand,
"adminvoladdallowedstorageclass": AdminVolAddAllowedStorageClass,
"admincreatevol": AdminCreateVol,
"admingetvol": AdminGetVol,
"adminclusterfreeze": AdminClusterFreeze,

View File

@ -208,11 +208,12 @@ const (
MsgMasterAutoDecommissionReq MsgType = MsgMasterAPIAccessReq + 0x20600
// Master API volume management
MsgMasterCreateVolReq MsgType = MsgMasterAPIAccessReq + 0x30100
MsgMasterDeleteVolReq MsgType = MsgMasterAPIAccessReq + 0x30200
MsgMasterUpdateVolReq MsgType = MsgMasterAPIAccessReq + 0x30300
MsgMasterVolShrinkReq MsgType = MsgMasterAPIAccessReq + 0x30400
MsgMasterVolExpandReq MsgType = MsgMasterAPIAccessReq + 0x30500
MsgMasterCreateVolReq MsgType = MsgMasterAPIAccessReq + 0x30100
MsgMasterDeleteVolReq MsgType = MsgMasterAPIAccessReq + 0x30200
MsgMasterUpdateVolReq MsgType = MsgMasterAPIAccessReq + 0x30300
MsgMasterVolShrinkReq MsgType = MsgMasterAPIAccessReq + 0x30400
MsgMasterVolExpandReq MsgType = MsgMasterAPIAccessReq + 0x30500
MsgMasterVolAddAllowedStorageClass MsgType = MsgMasterAPIAccessReq + 0x30501
// Master API meta partition management
MsgMasterLoadMetaPartitionReq MsgType = MsgMasterAPIAccessReq + 0x40100
@ -296,11 +297,12 @@ var MsgType2ResourceMap = map[MsgType]string{
MsgMasterAutoDecommissionReq: "master:autodecommission",
// Master API volume management
MsgMasterCreateVolReq: "master:createvol",
MsgMasterDeleteVolReq: "master:deletevol",
MsgMasterUpdateVolReq: "master:updatevol",
MsgMasterVolShrinkReq: "master:volshrink",
MsgMasterVolExpandReq: "master:volexpand",
MsgMasterCreateVolReq: "master:createvol",
MsgMasterDeleteVolReq: "master:deletevol",
MsgMasterUpdateVolReq: "master:updatevol",
MsgMasterVolShrinkReq: "master:volshrink",
MsgMasterVolExpandReq: "master:volexpand",
MsgMasterVolAddAllowedStorageClass: "master:voladdallowedStorageClass",
// Master API meta partition management
MsgMasterLoadMetaPartitionReq: "master:loadmetapartition",

View File

@ -350,6 +350,18 @@ func (api *AdminAPI) VolExpand(volName string, capacity uint64, authKey, clientI
return
}
func (api *AdminAPI) VolAddAllowedStorageClass(volName string, addAllowedStorageClass uint32, authKey, clientIDKey string) (err error) {
request := newRequest(http.MethodGet, proto.AdminVolAddAllowedStorageClass)
request.addParam("name", volName).Header(api.h)
request.addParam("allowedStorageClass", strconv.FormatUint(uint64(addAllowedStorageClass), 10))
request.addParam("authKey", authKey)
request.addParam("clientIDKey", clientIDKey)
if _, err = api.mc.serveRequest(request); err != nil {
return
}
return
}
func (api *AdminAPI) CreateVolName(volName, owner string, capacity uint64, deleteLockTime int64, crossZone, normalZonesFirst bool,
business string, mpCount, dpCount, replicaNum, dpSize int, followerRead bool, zoneName, cacheRuleKey string, ebsBlkSize,
cacheCapacity, cacheAction, cacheThreshold, cacheTTL, cacheHighWater, cacheLowWater, cacheLRUInterval int,