Skip to content
This repository has been archived by the owner on Mar 26, 2020. It is now read-only.

Commit

Permalink
Labels: Implement Labels
Browse files Browse the repository at this point in the history
Labels are used to tag different object, and perform
collective operation based on label configuration values

More information on #issue:1094

Signed-off-by: Mohammed Rafi KC <[email protected]>
  • Loading branch information
rafikc30 committed Sep 6, 2018
1 parent 37f8583 commit 40d3960
Show file tree
Hide file tree
Showing 16 changed files with 885 additions and 46 deletions.
98 changes: 52 additions & 46 deletions doc/endpoints.md

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions glusterd2/commands/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package commands

import (
"github.com/gluster/glusterd2/glusterd2/commands/global"
"github.com/gluster/glusterd2/glusterd2/commands/labels"
"github.com/gluster/glusterd2/glusterd2/commands/peers"
"github.com/gluster/glusterd2/glusterd2/commands/snapshot"
"github.com/gluster/glusterd2/glusterd2/commands/version"
Expand All @@ -25,4 +26,5 @@ var Commands = []Command{
&snapshotcommands.Command{},
&peercommands.Command{},
&globalcommands.Command{},
&labelcommands.Command{},
}
71 changes: 71 additions & 0 deletions glusterd2/commands/labels/commands.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package labelcommands

import (
"github.com/gluster/glusterd2/glusterd2/servers/rest/route"
"github.com/gluster/glusterd2/pkg/api"
"github.com/gluster/glusterd2/pkg/utils"
)

// Command is a structure which implements GlusterD Command interface
type Command struct {
}

// Routes returns list of REST API routes to register with Glusterd
func (c *Command) Routes() route.Routes {
return route.Routes{
route.Route{
Name: "LabelCreate",
Method: "POST",
Pattern: "/labels",
Version: 1,
RequestType: utils.GetTypeString((*api.LabelCreateReq)(nil)),
ResponseType: utils.GetTypeString((*api.LabelCreateResp)(nil)),
HandlerFunc: labelCreateHandler},
route.Route{
Name: "LabelInfo",
Method: "GET",
Pattern: "/labels/{labelname}",
Version: 1,
ResponseType: utils.GetTypeString((*api.LabelGetResp)(nil)),
HandlerFunc: labelInfoHandler},
route.Route{
Name: "LabelListAll",
Method: "GET",
Pattern: "/labels",
Version: 1,
ResponseType: utils.GetTypeString((*api.LabelListResp)(nil)),
HandlerFunc: labelListHandler},
route.Route{
Name: "LabelDelete",
Method: "DELETE",
Pattern: "/labels/{labelname}",
Version: 1,
HandlerFunc: labelDeleteHandler},
route.Route{
Name: "LabelConfigSet",
Method: "POST",
Pattern: "/labels/{labelname}/config",
Version: 1,
RequestType: utils.GetTypeString((*api.LabelSetReq)(nil)),
ResponseType: utils.GetTypeString((*api.LabelConfigResp)(nil)),
HandlerFunc: labelConfigSetHandler},
route.Route{
Name: "LabelConfigReset",
Method: "DELETE",
Pattern: "/labels/{labelname}/config",
Version: 1,
RequestType: utils.GetTypeString((*api.LabelResetReq)(nil)),
ResponseType: utils.GetTypeString((*api.LabelConfigResp)(nil)),
HandlerFunc: labelConfigResetHandler},
}
}

// RegisterStepFuncs registers transaction step functions with
// Glusterd Transaction framework
func (c *Command) RegisterStepFuncs() {
registerLabelCreateStepFuncs()
registerLabelDeleteStepFuncs()
registerLabelConfigSetStepFuncs()
registerLabelConfigResetStepFuncs()
return
}
131 changes: 131 additions & 0 deletions glusterd2/commands/labels/label-create.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
package labelcommands

import (
"errors"
"fmt"
"net/http"

"github.com/gluster/glusterd2/glusterd2/gdctx"
"github.com/gluster/glusterd2/glusterd2/label"
restutils "github.com/gluster/glusterd2/glusterd2/servers/rest/utils"
"github.com/gluster/glusterd2/glusterd2/transaction"
"github.com/gluster/glusterd2/pkg/api"
gderrors "github.com/gluster/glusterd2/pkg/errors"

"github.com/pborman/uuid"
)

const maxSnapCount = 256

func validateLabel(info *label.Info) error {

if info.SnapMaxHardLimit > maxSnapCount {
return fmt.Errorf("Snap-max-hard-limit count cannot exceed more than %d", maxSnapCount)
}
if info.SnapMaxSoftLimit > info.SnapMaxHardLimit {
return errors.New("snap-soft-limit cannot exceed more than snap-max-hard-limit")
}
return nil
}

func newLabelInfo(req *api.LabelCreateReq) *label.Info {
var labelInfo label.Info

labelInfo.Name = req.Name
labelInfo.SnapMaxHardLimit = req.SnapMaxHardLimit
labelInfo.SnapMaxSoftLimit = req.SnapMaxSoftLimit
labelInfo.ActivateOnCreate = req.ActivateOnCreate
labelInfo.AutoDelete = req.AutoDelete
labelInfo.Description = req.Description

return &labelInfo
}

func storeLabel(c transaction.TxnCtx) error {

var labelInfo label.Info

if err := c.Get("label", &labelInfo); err != nil {
return err
}
if err := label.AddOrUpdateLabelFunc(&labelInfo); err != nil {
c.Logger().WithError(err).WithField(
"label", labelInfo.Name).Debug("storeLabel: failed to store label info")
return err
}

return nil
}

func registerLabelCreateStepFuncs() {
transaction.RegisterStepFunc(storeLabel, "label-create.Store")
}

func labelCreateHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
logger := gdctx.GetReqLogger(ctx)
var req api.LabelCreateReq

if err := restutils.UnmarshalRequest(r, &req); err != nil {
restutils.SendHTTPError(ctx, w, http.StatusBadRequest, gderrors.ErrJSONParsingFailed)
return
}
if label.ExistsFunc(req.Name) {
restutils.SendHTTPError(ctx, w, http.StatusBadRequest, gderrors.ErrLabelExists)
return
}

/*
TODO : label name validation
*/

labelInfo := newLabelInfo(&req)
if err := validateLabel(labelInfo); err != nil {
restutils.SendHTTPError(ctx, w, http.StatusBadRequest, err)
return
}

txn, err := transaction.NewTxnWithLocks(ctx, req.Name)
if err != nil {
status, err := restutils.ErrToStatusCode(err)
restutils.SendHTTPError(ctx, w, status, err)
return
}
defer txn.Done()

txn.Steps = []*transaction.Step{
{
DoFunc: "label-create.Store",
Nodes: []uuid.UUID{gdctx.MyUUID},
},
}

if err = txn.Ctx.Set("label", &labelInfo); err != nil {
logger.WithError(err).Error("failed to set request in transaction context")
restutils.SendHTTPError(ctx, w, http.StatusInternalServerError, err)
return
}

if err = txn.Do(); err != nil {
logger.WithError(err).Error("label create transaction failed")
status, err := restutils.ErrToStatusCode(err)
restutils.SendHTTPError(ctx, w, status, err)
return
}

labelInfo, err = label.GetLabel(req.Name)
if err != nil {
restutils.SendHTTPError(ctx, w, http.StatusInternalServerError, err)
return
}

txn.Ctx.Logger().WithField("LabelName", req.Name).Info("new label created")

resp := createLabelCreateResp(labelInfo)
restutils.SetLocationHeader(r, w, labelInfo.Name)
restutils.SendHTTPResponse(ctx, w, http.StatusCreated, resp)
}

func createLabelCreateResp(info *label.Info) *api.LabelCreateResp {
return (*api.LabelCreateResp)(label.CreateLabelInfoResp(info))
}
83 changes: 83 additions & 0 deletions glusterd2/commands/labels/label-delete.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package labelcommands

import (
"fmt"
"net/http"

"github.com/gluster/glusterd2/glusterd2/gdctx"
"github.com/gluster/glusterd2/glusterd2/label"
restutils "github.com/gluster/glusterd2/glusterd2/servers/rest/utils"
"github.com/gluster/glusterd2/glusterd2/transaction"
"github.com/gorilla/mux"
"github.com/pborman/uuid"
)

func registerLabelDeleteStepFuncs() {
transaction.RegisterStepFunc(deleteLabel, "label-delete.Store")
}

func deleteLabel(c transaction.TxnCtx) error {

var labelInfo label.Info
if err := c.Get("labelinfo", &labelInfo); err != nil {
return err
}

err := label.DeleteLabel(&labelInfo)
return err
}

func labelDeleteHandler(w http.ResponseWriter, r *http.Request) {

ctx := r.Context()
logger := gdctx.GetReqLogger(ctx)

labelname := mux.Vars(r)["labelname"]
labelInfo, err := label.GetLabel(labelname)
if err != nil {
status, err := restutils.ErrToStatusCode(err)
restutils.SendHTTPError(ctx, w, status, err)
return
}

txn, err := transaction.NewTxnWithLocks(ctx, labelname)
if err != nil {
status, err := restutils.ErrToStatusCode(err)
restutils.SendHTTPError(ctx, w, status, err)
return
}
defer txn.Done()

if labelname == (label.DefaultLabel).Name {
errMsg := "Default label cannot be deleted."
restutils.SendHTTPError(ctx, w, http.StatusBadRequest, errMsg)
return
}

if len(labelInfo.SnapList) > 0 {
errMsg := fmt.Sprintf("Cannot delete Label %s ,as it has %d snapshots tagged.", labelname, len(labelInfo.SnapList))
restutils.SendHTTPError(ctx, w, http.StatusFailedDependency, errMsg)
return
}
txn.Steps = []*transaction.Step{
{
DoFunc: "label-delete.Store",
Nodes: []uuid.UUID{gdctx.MyUUID},
},
}

if err := txn.Ctx.Set("labelinfo", labelInfo); err != nil {
restutils.SendHTTPError(ctx, w, http.StatusInternalServerError, err)
return
}

if err := txn.Do(); err != nil {
logger.WithError(err).WithField(
"label", labelname).Error("transaction to delete label failed")
restutils.SendHTTPError(ctx, w, http.StatusInternalServerError, err)
return
}

logger.WithField("label-name", labelname).Info("label deleted")
restutils.SendHTTPResponse(ctx, w, http.StatusNoContent, nil)
}
30 changes: 30 additions & 0 deletions glusterd2/commands/labels/label-info.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package labelcommands

import (
"net/http"

"github.com/gluster/glusterd2/glusterd2/label"
restutils "github.com/gluster/glusterd2/glusterd2/servers/rest/utils"
"github.com/gluster/glusterd2/pkg/api"
"github.com/gorilla/mux"
)

func labelInfoHandler(w http.ResponseWriter, r *http.Request) {

ctx := r.Context()

labelname := mux.Vars(r)["labelname"]
labelInfo, err := label.GetLabel(labelname)
if err != nil {
status, err := restutils.ErrToStatusCode(err)
restutils.SendHTTPError(ctx, w, status, err)
return
}

resp := createLabelGetResp(labelInfo)
restutils.SendHTTPResponse(ctx, w, http.StatusOK, resp)
}

func createLabelGetResp(info *label.Info) *api.LabelGetResp {
return (*api.LabelGetResp)(label.CreateLabelInfoResp(info))
}
34 changes: 34 additions & 0 deletions glusterd2/commands/labels/label-list.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package labelcommands

import (
"net/http"

"github.com/gluster/glusterd2/glusterd2/label"
restutils "github.com/gluster/glusterd2/glusterd2/servers/rest/utils"
"github.com/gluster/glusterd2/pkg/api"
)

func labelListHandler(w http.ResponseWriter, r *http.Request) {

ctx := r.Context()

labelInfos, err := label.GetLabels()
if err != nil {
status, err := restutils.ErrToStatusCode(err)
restutils.SendHTTPError(ctx, w, status, err)
return
}

resp := createLabelListResp(labelInfos)
restutils.SendHTTPResponse(ctx, w, http.StatusOK, resp)
}

func createLabelListResp(infos []*label.Info) *api.LabelListResp {
var resp = make(api.LabelListResp, len(infos))

for index, v := range infos {
resp[index] = *(createLabelGetResp(v))
}

return &resp
}
Loading

0 comments on commit 40d3960

Please sign in to comment.