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

Commit 40d3960

Browse files
committed
Labels: Implement Labels
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 <rkavunga@redhat.com>
1 parent 37f8583 commit 40d3960

File tree

16 files changed

+885
-46
lines changed

16 files changed

+885
-46
lines changed

doc/endpoints.md

Lines changed: 52 additions & 46 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

glusterd2/commands/command.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package commands
33

44
import (
55
"github.com/gluster/glusterd2/glusterd2/commands/global"
6+
"github.com/gluster/glusterd2/glusterd2/commands/labels"
67
"github.com/gluster/glusterd2/glusterd2/commands/peers"
78
"github.com/gluster/glusterd2/glusterd2/commands/snapshot"
89
"github.com/gluster/glusterd2/glusterd2/commands/version"
@@ -25,4 +26,5 @@ var Commands = []Command{
2526
&snapshotcommands.Command{},
2627
&peercommands.Command{},
2728
&globalcommands.Command{},
29+
&labelcommands.Command{},
2830
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package labelcommands
2+
3+
import (
4+
"github.com/gluster/glusterd2/glusterd2/servers/rest/route"
5+
"github.com/gluster/glusterd2/pkg/api"
6+
"github.com/gluster/glusterd2/pkg/utils"
7+
)
8+
9+
// Command is a structure which implements GlusterD Command interface
10+
type Command struct {
11+
}
12+
13+
// Routes returns list of REST API routes to register with Glusterd
14+
func (c *Command) Routes() route.Routes {
15+
return route.Routes{
16+
route.Route{
17+
Name: "LabelCreate",
18+
Method: "POST",
19+
Pattern: "/labels",
20+
Version: 1,
21+
RequestType: utils.GetTypeString((*api.LabelCreateReq)(nil)),
22+
ResponseType: utils.GetTypeString((*api.LabelCreateResp)(nil)),
23+
HandlerFunc: labelCreateHandler},
24+
route.Route{
25+
Name: "LabelInfo",
26+
Method: "GET",
27+
Pattern: "/labels/{labelname}",
28+
Version: 1,
29+
ResponseType: utils.GetTypeString((*api.LabelGetResp)(nil)),
30+
HandlerFunc: labelInfoHandler},
31+
route.Route{
32+
Name: "LabelListAll",
33+
Method: "GET",
34+
Pattern: "/labels",
35+
Version: 1,
36+
ResponseType: utils.GetTypeString((*api.LabelListResp)(nil)),
37+
HandlerFunc: labelListHandler},
38+
route.Route{
39+
Name: "LabelDelete",
40+
Method: "DELETE",
41+
Pattern: "/labels/{labelname}",
42+
Version: 1,
43+
HandlerFunc: labelDeleteHandler},
44+
route.Route{
45+
Name: "LabelConfigSet",
46+
Method: "POST",
47+
Pattern: "/labels/{labelname}/config",
48+
Version: 1,
49+
RequestType: utils.GetTypeString((*api.LabelSetReq)(nil)),
50+
ResponseType: utils.GetTypeString((*api.LabelConfigResp)(nil)),
51+
HandlerFunc: labelConfigSetHandler},
52+
route.Route{
53+
Name: "LabelConfigReset",
54+
Method: "DELETE",
55+
Pattern: "/labels/{labelname}/config",
56+
Version: 1,
57+
RequestType: utils.GetTypeString((*api.LabelResetReq)(nil)),
58+
ResponseType: utils.GetTypeString((*api.LabelConfigResp)(nil)),
59+
HandlerFunc: labelConfigResetHandler},
60+
}
61+
}
62+
63+
// RegisterStepFuncs registers transaction step functions with
64+
// Glusterd Transaction framework
65+
func (c *Command) RegisterStepFuncs() {
66+
registerLabelCreateStepFuncs()
67+
registerLabelDeleteStepFuncs()
68+
registerLabelConfigSetStepFuncs()
69+
registerLabelConfigResetStepFuncs()
70+
return
71+
}
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
package labelcommands
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"net/http"
7+
8+
"github.com/gluster/glusterd2/glusterd2/gdctx"
9+
"github.com/gluster/glusterd2/glusterd2/label"
10+
restutils "github.com/gluster/glusterd2/glusterd2/servers/rest/utils"
11+
"github.com/gluster/glusterd2/glusterd2/transaction"
12+
"github.com/gluster/glusterd2/pkg/api"
13+
gderrors "github.com/gluster/glusterd2/pkg/errors"
14+
15+
"github.com/pborman/uuid"
16+
)
17+
18+
const maxSnapCount = 256
19+
20+
func validateLabel(info *label.Info) error {
21+
22+
if info.SnapMaxHardLimit > maxSnapCount {
23+
return fmt.Errorf("Snap-max-hard-limit count cannot exceed more than %d", maxSnapCount)
24+
}
25+
if info.SnapMaxSoftLimit > info.SnapMaxHardLimit {
26+
return errors.New("snap-soft-limit cannot exceed more than snap-max-hard-limit")
27+
}
28+
return nil
29+
}
30+
31+
func newLabelInfo(req *api.LabelCreateReq) *label.Info {
32+
var labelInfo label.Info
33+
34+
labelInfo.Name = req.Name
35+
labelInfo.SnapMaxHardLimit = req.SnapMaxHardLimit
36+
labelInfo.SnapMaxSoftLimit = req.SnapMaxSoftLimit
37+
labelInfo.ActivateOnCreate = req.ActivateOnCreate
38+
labelInfo.AutoDelete = req.AutoDelete
39+
labelInfo.Description = req.Description
40+
41+
return &labelInfo
42+
}
43+
44+
func storeLabel(c transaction.TxnCtx) error {
45+
46+
var labelInfo label.Info
47+
48+
if err := c.Get("label", &labelInfo); err != nil {
49+
return err
50+
}
51+
if err := label.AddOrUpdateLabelFunc(&labelInfo); err != nil {
52+
c.Logger().WithError(err).WithField(
53+
"label", labelInfo.Name).Debug("storeLabel: failed to store label info")
54+
return err
55+
}
56+
57+
return nil
58+
}
59+
60+
func registerLabelCreateStepFuncs() {
61+
transaction.RegisterStepFunc(storeLabel, "label-create.Store")
62+
}
63+
64+
func labelCreateHandler(w http.ResponseWriter, r *http.Request) {
65+
ctx := r.Context()
66+
logger := gdctx.GetReqLogger(ctx)
67+
var req api.LabelCreateReq
68+
69+
if err := restutils.UnmarshalRequest(r, &req); err != nil {
70+
restutils.SendHTTPError(ctx, w, http.StatusBadRequest, gderrors.ErrJSONParsingFailed)
71+
return
72+
}
73+
if label.ExistsFunc(req.Name) {
74+
restutils.SendHTTPError(ctx, w, http.StatusBadRequest, gderrors.ErrLabelExists)
75+
return
76+
}
77+
78+
/*
79+
TODO : label name validation
80+
*/
81+
82+
labelInfo := newLabelInfo(&req)
83+
if err := validateLabel(labelInfo); err != nil {
84+
restutils.SendHTTPError(ctx, w, http.StatusBadRequest, err)
85+
return
86+
}
87+
88+
txn, err := transaction.NewTxnWithLocks(ctx, req.Name)
89+
if err != nil {
90+
status, err := restutils.ErrToStatusCode(err)
91+
restutils.SendHTTPError(ctx, w, status, err)
92+
return
93+
}
94+
defer txn.Done()
95+
96+
txn.Steps = []*transaction.Step{
97+
{
98+
DoFunc: "label-create.Store",
99+
Nodes: []uuid.UUID{gdctx.MyUUID},
100+
},
101+
}
102+
103+
if err = txn.Ctx.Set("label", &labelInfo); err != nil {
104+
logger.WithError(err).Error("failed to set request in transaction context")
105+
restutils.SendHTTPError(ctx, w, http.StatusInternalServerError, err)
106+
return
107+
}
108+
109+
if err = txn.Do(); err != nil {
110+
logger.WithError(err).Error("label create transaction failed")
111+
status, err := restutils.ErrToStatusCode(err)
112+
restutils.SendHTTPError(ctx, w, status, err)
113+
return
114+
}
115+
116+
labelInfo, err = label.GetLabel(req.Name)
117+
if err != nil {
118+
restutils.SendHTTPError(ctx, w, http.StatusInternalServerError, err)
119+
return
120+
}
121+
122+
txn.Ctx.Logger().WithField("LabelName", req.Name).Info("new label created")
123+
124+
resp := createLabelCreateResp(labelInfo)
125+
restutils.SetLocationHeader(r, w, labelInfo.Name)
126+
restutils.SendHTTPResponse(ctx, w, http.StatusCreated, resp)
127+
}
128+
129+
func createLabelCreateResp(info *label.Info) *api.LabelCreateResp {
130+
return (*api.LabelCreateResp)(label.CreateLabelInfoResp(info))
131+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package labelcommands
2+
3+
import (
4+
"fmt"
5+
"net/http"
6+
7+
"github.com/gluster/glusterd2/glusterd2/gdctx"
8+
"github.com/gluster/glusterd2/glusterd2/label"
9+
restutils "github.com/gluster/glusterd2/glusterd2/servers/rest/utils"
10+
"github.com/gluster/glusterd2/glusterd2/transaction"
11+
"github.com/gorilla/mux"
12+
"github.com/pborman/uuid"
13+
)
14+
15+
func registerLabelDeleteStepFuncs() {
16+
transaction.RegisterStepFunc(deleteLabel, "label-delete.Store")
17+
}
18+
19+
func deleteLabel(c transaction.TxnCtx) error {
20+
21+
var labelInfo label.Info
22+
if err := c.Get("labelinfo", &labelInfo); err != nil {
23+
return err
24+
}
25+
26+
err := label.DeleteLabel(&labelInfo)
27+
return err
28+
}
29+
30+
func labelDeleteHandler(w http.ResponseWriter, r *http.Request) {
31+
32+
ctx := r.Context()
33+
logger := gdctx.GetReqLogger(ctx)
34+
35+
labelname := mux.Vars(r)["labelname"]
36+
labelInfo, err := label.GetLabel(labelname)
37+
if err != nil {
38+
status, err := restutils.ErrToStatusCode(err)
39+
restutils.SendHTTPError(ctx, w, status, err)
40+
return
41+
}
42+
43+
txn, err := transaction.NewTxnWithLocks(ctx, labelname)
44+
if err != nil {
45+
status, err := restutils.ErrToStatusCode(err)
46+
restutils.SendHTTPError(ctx, w, status, err)
47+
return
48+
}
49+
defer txn.Done()
50+
51+
if labelname == (label.DefaultLabel).Name {
52+
errMsg := "Default label cannot be deleted."
53+
restutils.SendHTTPError(ctx, w, http.StatusBadRequest, errMsg)
54+
return
55+
}
56+
57+
if len(labelInfo.SnapList) > 0 {
58+
errMsg := fmt.Sprintf("Cannot delete Label %s ,as it has %d snapshots tagged.", labelname, len(labelInfo.SnapList))
59+
restutils.SendHTTPError(ctx, w, http.StatusFailedDependency, errMsg)
60+
return
61+
}
62+
txn.Steps = []*transaction.Step{
63+
{
64+
DoFunc: "label-delete.Store",
65+
Nodes: []uuid.UUID{gdctx.MyUUID},
66+
},
67+
}
68+
69+
if err := txn.Ctx.Set("labelinfo", labelInfo); err != nil {
70+
restutils.SendHTTPError(ctx, w, http.StatusInternalServerError, err)
71+
return
72+
}
73+
74+
if err := txn.Do(); err != nil {
75+
logger.WithError(err).WithField(
76+
"label", labelname).Error("transaction to delete label failed")
77+
restutils.SendHTTPError(ctx, w, http.StatusInternalServerError, err)
78+
return
79+
}
80+
81+
logger.WithField("label-name", labelname).Info("label deleted")
82+
restutils.SendHTTPResponse(ctx, w, http.StatusNoContent, nil)
83+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package labelcommands
2+
3+
import (
4+
"net/http"
5+
6+
"github.com/gluster/glusterd2/glusterd2/label"
7+
restutils "github.com/gluster/glusterd2/glusterd2/servers/rest/utils"
8+
"github.com/gluster/glusterd2/pkg/api"
9+
"github.com/gorilla/mux"
10+
)
11+
12+
func labelInfoHandler(w http.ResponseWriter, r *http.Request) {
13+
14+
ctx := r.Context()
15+
16+
labelname := mux.Vars(r)["labelname"]
17+
labelInfo, err := label.GetLabel(labelname)
18+
if err != nil {
19+
status, err := restutils.ErrToStatusCode(err)
20+
restutils.SendHTTPError(ctx, w, status, err)
21+
return
22+
}
23+
24+
resp := createLabelGetResp(labelInfo)
25+
restutils.SendHTTPResponse(ctx, w, http.StatusOK, resp)
26+
}
27+
28+
func createLabelGetResp(info *label.Info) *api.LabelGetResp {
29+
return (*api.LabelGetResp)(label.CreateLabelInfoResp(info))
30+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package labelcommands
2+
3+
import (
4+
"net/http"
5+
6+
"github.com/gluster/glusterd2/glusterd2/label"
7+
restutils "github.com/gluster/glusterd2/glusterd2/servers/rest/utils"
8+
"github.com/gluster/glusterd2/pkg/api"
9+
)
10+
11+
func labelListHandler(w http.ResponseWriter, r *http.Request) {
12+
13+
ctx := r.Context()
14+
15+
labelInfos, err := label.GetLabels()
16+
if err != nil {
17+
status, err := restutils.ErrToStatusCode(err)
18+
restutils.SendHTTPError(ctx, w, status, err)
19+
return
20+
}
21+
22+
resp := createLabelListResp(labelInfos)
23+
restutils.SendHTTPResponse(ctx, w, http.StatusOK, resp)
24+
}
25+
26+
func createLabelListResp(infos []*label.Info) *api.LabelListResp {
27+
var resp = make(api.LabelListResp, len(infos))
28+
29+
for index, v := range infos {
30+
resp[index] = *(createLabelGetResp(v))
31+
}
32+
33+
return &resp
34+
}

0 commit comments

Comments
 (0)