From 4707158acdcf177031f2fa7ee5ff37d1a7d11307 Mon Sep 17 00:00:00 2001 From: rishubhjain Date: Tue, 12 Jun 2018 04:35:10 -0400 Subject: [PATCH 1/2] Volume shrink api --- glusterd2/commands/volumes/commands.go | 9 + glusterd2/commands/volumes/volume-shrink.go | 288 ++++++++++++++++++++ pkg/api/volume_req.go | 5 + pkg/api/volume_resp.go | 3 + 4 files changed, 305 insertions(+) create mode 100644 glusterd2/commands/volumes/volume-shrink.go diff --git a/glusterd2/commands/volumes/commands.go b/glusterd2/commands/volumes/commands.go index dcafd986c..24637501f 100644 --- a/glusterd2/commands/volumes/commands.go +++ b/glusterd2/commands/volumes/commands.go @@ -30,6 +30,14 @@ func (c *Command) Routes() route.Routes { RequestType: utils.GetTypeString((*api.VolExpandReq)(nil)), ResponseType: utils.GetTypeString((*api.VolumeExpandResp)(nil)), HandlerFunc: volumeExpandHandler}, + route.Route{ + Name: "VolumeShrink", + Method: "POST", + Pattern: "/volumes/{volname}/shrink", + Version: 1, + RequestType: utils.GetTypeString((*api.VolShrinkReq)(nil)), + ResponseType: utils.GetTypeString((*api.VolumeShrinkResp)(nil)), + HandlerFunc: volumeShrinkHandler}, // TODO: Implmement volume reset as // DELETE /volumes/{volname}/options route.Route{ @@ -160,6 +168,7 @@ func (c *Command) RegisterStepFuncs() { registerVolStopStepFuncs() registerBricksStatusStepFuncs() registerVolExpandStepFuncs() + registerVolShrinkStepFuncs() registerVolOptionStepFuncs() registerVolStatedumpFuncs() } diff --git a/glusterd2/commands/volumes/volume-shrink.go b/glusterd2/commands/volumes/volume-shrink.go new file mode 100644 index 000000000..02fe0f993 --- /dev/null +++ b/glusterd2/commands/volumes/volume-shrink.go @@ -0,0 +1,288 @@ +package volumecommands + +import ( + "errors" + "net/http" + "path/filepath" + "strings" + + "github.com/gluster/glusterd2/glusterd2/daemon" + "github.com/gluster/glusterd2/glusterd2/gdctx" + restutils "github.com/gluster/glusterd2/glusterd2/servers/rest/utils" + "github.com/gluster/glusterd2/glusterd2/transaction" + "github.com/gluster/glusterd2/glusterd2/volume" + "github.com/gluster/glusterd2/pkg/api" + "github.com/gluster/glusterd2/plugins/rebalance" + rebalanceapi "github.com/gluster/glusterd2/plugins/rebalance/api" + + "github.com/gorilla/mux" + "github.com/pborman/uuid" +) + +func registerVolShrinkStepFuncs() { + transaction.RegisterStepFunc(storeVolume, "vol-shrink.UpdateVolinfo") + transaction.RegisterStepFunc(notifyVolfileChange, "vol-shrink.NotifyClients") + transaction.RegisterStepFunc(startRebalance, "vol-shrink.StartRebalance") +} + +func startRebalance(c transaction.TxnCtx) error { + var rinfo rebalanceapi.RebalanceInfo + err := c.Get("rinfo", &rinfo) + if err != nil { + return err + } + + rebalanceProcess, err := rebalance.NewRebalanceProcess(rinfo) + if err != nil { + return err + } + + err = daemon.Start(rebalanceProcess, true) + + return err +} + +func validateVolumeShrinkReq(req api.VolShrinkReq) error { + dupEntry := map[string]bool{} + + for _, brick := range req.Bricks { + if dupEntry[brick.PeerID+filepath.Clean(brick.Path)] == true { + return errors.ErrDuplicateBrickPath + } + dupEntry[brick.PeerID+filepath.Clean(brick.Path)] = true + + } + + return nil + +} + +func volumeShrinkHandler(w http.ResponseWriter, r *http.Request) { + + ctx := r.Context() + logger := gdctx.GetReqLogger(ctx) + + volname := mux.Vars(r)["volname"] + + var req api.VolShrinkReq + if err := restutils.UnmarshalRequest(r, &req); err != nil { + restutils.SendHTTPError(ctx, w, http.StatusUnprocessableEntity, err.Error(), api.ErrCodeDefault) + return + } + + if err := validateVolumeShrinkReq(req); err != nil { + restutils.SendHTTPError(ctx, w, http.StatusBadRequest, err) + return + } + + volinfo, err := volume.GetVolume(volname) + if err != nil { + restutils.SendHTTPError(ctx, w, http.StatusNotFound, err.Error(), api.ErrCodeDefault) + return + } + + for index := range req.Bricks { + for _, b := range req.Bricks { + isPresent = false + for _, brick := range volinfo.Subvols[index].Bricks { + if brick.PeerID.String() == b.PeerID && brick.Path == filepath.Clean(b.Path) { + flag = true + break + } + } + if !isPresent { + restutils.SendHTTPError(ctx, w, http.StatusBadRequest, "One or more brick is not part of given volume") + return + } + } + } + + switch volinfo.Type { + case volume.Distribute: + case volume.Replicate: + case volume.DistReplicate: + if len(req.Bricks)%volinfo.Subvols[0].ReplicaCount != 0 { + err := errors.New("wrong number of bricks to remove") + restutils.SendHTTPError(ctx, w, http.StatusInternalServerError, err.Error(), api.ErrCodeDefault) + return + } + default: + err := errors.New("not implemented: " + volinfo.Type.String()) + restutils.SendHTTPError(ctx, w, http.StatusInternalServerError, err.Error(), api.ErrCodeDefault) + return + + } + + nodes, err := req.Nodes() + if err != nil { + logger.WithError(err).Error("could not prepare node list") + restutils.SendHTTPError(ctx, w, http.StatusInternalServerError, err) + return + } + + txn := transaction.NewTxn(ctx) + defer txn.Cleanup() + + txn, err := transaction.NewTxnWithLocks(ctx, volname) + if err != nil { + status, err := restutils.ErrToStatusCode(err) + restutils.SendHTTPError(ctx, w, status, err) + return + } + defer txn.Done() + + volinfo, err := volume.GetVolume(volname) + if err != nil { + restutils.SendHTTPError(ctx, w, http.StatusNotFound, err.Error(), api.ErrCodeDefault) + return + } + + for index := range req.Bricks { + for _, b := range req.Bricks { + isPresent = false + for _, brick := range volinfo.Subvols[index].Bricks { + if brick.PeerID.String() == b.PeerID && brick.Path == filepath.Clean(b.Path) { + flag = true + break + } + } + if !isPresent { + restutils.SendHTTPError(ctx, w, http.StatusBadRequest, "One or more brick is not part of given volume") + return + } + } + } + + switch volinfo.Type { + case volume.Distribute: + case volume.Replicate: + case volume.DistReplicate: + if len(req.Bricks)%volinfo.Subvols[0].ReplicaCount != 0 { + err := errors.New("wrong number of bricks to remove") + restutils.SendHTTPError(ctx, w, http.StatusInternalServerError, err) + return + } + default: + err := errors.New("not implemented: " + volinfo.Type.String()) + restutils.SendHTTPError(ctx, w, http.StatusInternalServerError, err) + return + + } + + nodes, err := req.Nodes() + if err != nil { + logger.WithError(err).Error("could not prepare node list") + restutils.SendHTTPError(ctx, w, http.StatusInternalServerError, err) + return + } + + txn.Steps = []*transaction.Step{ + lock, + { + DoFunc: "vol-shrink.UpdateVolinfo", + Nodes: []uuid.UUID{gdctx.MyUUID}, + }, + { + DoFunc: "vol-shrink.NotifyClients", + Nodes: nodes, + }, + { + DoFunc: "vol-shrink.StartRebalance", + Nodes: nodes, + }, + + unlock, + } + + decommissionedSubvols, err := findDecommissioned(req.Bricks, volinfo) + if err != nil { + restutils.SendHTTPError(ctx, w, http.StatusInternalServerError, err) + return + + } + + // The following line is for testing purposes. + // It seems that there is no other way to include this information in the rebalance volfile right now. + volinfo.Options["distribute.decommissioned-bricks"] = strings.TrimSpace(decommissionedSubvols) + + var rinfo rebalanceapi.RebalanceInfo + var commit uint64 + rinfo.Volname = volname + rinfo.RebalanceID = uuid.NewRandom() + rinfo.Cmd = rebalanceapi.GfDefragCmdStartForce + rinfo.Status = rebalanceapi.GfDefragStatusNotStarted + rinfo.CommitHash = rebalance.SetCommitHash(commit) + if err := txn.Ctx.Set("rinfo", rinfo); err != nil { + restutils.SendHTTPError(ctx, w, http.StatusInternalServerError, err.Error(), api.ErrCodeDefault) + return + } + + if err := txn.Ctx.Set("volinfo", volinfo); err != nil { + restutils.SendHTTPError(ctx, w, http.StatusInternalServerError, err.Error(), api.ErrCodeDefault) + return + } + + if err = txn.Do(); err != nil { + logger.WithError(err).Error("remove bricks start transaction failed") + if err == transaction.ErrLockTimeout { + restutils.SendHTTPError(ctx, w, http.StatusConflict, err.Error(), api.ErrCodeDefault) + } else { + restutils.SendHTTPError(ctx, w, http.StatusInternalServerError, err.Error(), api.ErrCodeDefault) + } + return + } + + restutils.SendHTTPResponse(ctx, w, http.StatusOK, decommissionedSubvols) + +} + +func findDecommissioned(bricks []api.BrickReq, volinfo *volume.Volinfo) (string, error) { + brickSet := make(map[string]bool) + for _, brick := range bricks { + u := uuid.Parse(brick.NodeID) + if u == nil { + return "", errors.New("Invalid nodeid") + } + path, err := filepath.Abs(brick.Path) + if err != nil { + return "", err + } + brickSet[brick.NodeID+":"+path] = true + } + + var subvolMap = make(map[string]int) + for _, subvol := range volinfo.Subvols { + for _, b := range subvol.Bricks { + if brickSet[b.NodeID.String()+":"+b.Path] { + if count, ok := subvolMap[subvol.Name]; !ok { + subvolMap[subvol.Name] = 1 + } else { + subvolMap[subvol.Name] = count + 1 + } + } + + } + } + + var base int + switch volinfo.Type { + case volume.Distribute: + base = 1 + case volume.Replicate: + base = len(bricks) + case volume.DistReplicate: + base = volinfo.Subvols[0].ReplicaCount + default: + return "", errors.New("not implemented: " + volinfo.Type.String()) + } + + decommissioned := "" + for subvol, count := range subvolMap { + if count != base { + return "", errors.New("Wrong number of bricks in the subvolume") + } + decommissioned = decommissioned + subvol + " " + } + + return decommissioned, nil +} diff --git a/pkg/api/volume_req.go b/pkg/api/volume_req.go index 30a55d46e..ce9ee74a5 100644 --- a/pkg/api/volume_req.go +++ b/pkg/api/volume_req.go @@ -67,6 +67,11 @@ type VolExpandReq struct { Flags map[string]bool `json:"flags,omitempty"` } +// VolShrinkReq represents a request to remove bricks from a volume +type VolShrinkReq struct { + Bricks []BrickReq `json:"bricks"` +} + // VolumeOption represents an option that is part of a profile type VolumeOption struct { Name string `json:"name"` diff --git a/pkg/api/volume_resp.go b/pkg/api/volume_resp.go index a332163d3..1f0d5dedb 100644 --- a/pkg/api/volume_resp.go +++ b/pkg/api/volume_resp.go @@ -92,6 +92,9 @@ type VolumeGetResp VolumeInfo // VolumeExpandResp is the response sent for a volume expand request. type VolumeExpandResp VolumeInfo +// VolumeShrinkResp is the response sent for a volume expand request. +type VolumeShrinkResp VolumeInfo + // VolumeStartResp is the response sent for a volume start request. type VolumeStartResp VolumeInfo From ea748299719658c1e41bbc346104903061bf6517 Mon Sep 17 00:00:00 2001 From: rishubhjain Date: Mon, 18 Jun 2018 03:37:23 -0400 Subject: [PATCH 2/2] Updating the endpoints documentation --- doc/endpoints.md | 22 ++++++-- .../commands/volumes/volume-shrink-txn.go | 30 +++++++++++ glusterd2/commands/volumes/volume-shrink.go | 54 +++++++------------ glusterd2/volume/events.go | 2 + 4 files changed, 69 insertions(+), 39 deletions(-) create mode 100644 glusterd2/commands/volumes/volume-shrink-txn.go diff --git a/doc/endpoints.md b/doc/endpoints.md index bd5da58fe..b8b93ebc5 100644 --- a/doc/endpoints.md +++ b/doc/endpoints.md @@ -16,6 +16,7 @@ Name | Methods | Path | Request | Response GetVersion | GET | /version | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [VersionResp](https://godoc.org/github.com/gluster/glusterd2/pkg/api#VersionResp) VolumeCreate | POST | /volumes | [VolCreateReq](https://godoc.org/github.com/gluster/glusterd2/pkg/api#VolCreateReq) | [VolumeCreateResp](https://godoc.org/github.com/gluster/glusterd2/pkg/api#VolumeCreateResp) VolumeExpand | POST | /volumes/{volname}/expand | [VolExpandReq](https://godoc.org/github.com/gluster/glusterd2/pkg/api#VolExpandReq) | [VolumeExpandResp](https://godoc.org/github.com/gluster/glusterd2/pkg/api#VolumeExpandResp) +VolumeShrink | POST | /volumes/{volname}/shrink | [VolShrinkReq](https://godoc.org/github.com/gluster/glusterd2/pkg/api#VolShrinkReq) | [VolumeShrinkResp](https://godoc.org/github.com/gluster/glusterd2/pkg/api#VolumeShrinkResp) VolumeOptions | POST | /volumes/{volname}/options | [VolOptionReq](https://godoc.org/github.com/gluster/glusterd2/pkg/api#VolOptionReq) | [VolumeOptionResp](https://godoc.org/github.com/gluster/glusterd2/pkg/api#VolumeOptionResp) VolumeReset | DELETE | /volumes/{volname}/options | [VolOptionResetReq](https://godoc.org/github.com/gluster/glusterd2/pkg/api#VolOptionResetReq) | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) OptionGroupList | GET | /volumes/options-group | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [OptionGroupListResp](https://godoc.org/github.com/gluster/glusterd2/pkg/api#OptionGroupListResp) @@ -33,6 +34,17 @@ VolfilesGenerate | POST | /volfiles | [](https://godoc.org/github.com/gluster/gl VolfilesGet | GET | /volfiles | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) VolfilesGet | GET | /volfiles/{volfileid:.*} | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) EditVolume | POST | /volumes/{volname}/edit | [VolEditReq](https://godoc.org/github.com/gluster/glusterd2/pkg/api#VolEditReq) | [VolumeEditResp](https://godoc.org/github.com/gluster/glusterd2/pkg/api#VolumeEditResp) +SnapshotCreate | POST | /snapshot | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) +SnapshotActivate | POST | /snapshot/{snapname}/activate | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) +SnapshotDeactivate | POST | /snapshot/{snapname}/deactivate | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) +SnapshotClone | POST | /snapshot/{snapname}/clone | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) +SnapshotRestore | POST | /snapshot/{snapname}/restore | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) +SnapshotInfo | GET | /snapshot/{snapname} | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) +SnapshotListAll | GET | /snapshots | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) +SnapshotDelete | DELETE | /snapshot/{snapname} | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) +SnapshotConfigGet | GET | /snapshot/config | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) +SnapshotConfigSet | PUT | /snapshot/config | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) +SnapshotConfigReset | DELETE | /snapshot/config | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) GetPeer | GET | /peers/{peerid} | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [PeerGetResp](https://godoc.org/github.com/gluster/glusterd2/pkg/api#PeerGetResp) GetPeers | GET | /peers | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [PeerListResp](https://godoc.org/github.com/gluster/glusterd2/pkg/api#PeerListResp) DeletePeer | DELETE | /peers/{peerid} | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) @@ -67,11 +79,15 @@ WebhookAdd | POST | /events/webhook | [](https://godoc.org/github.com/gluster/gl WebhookDelete | DELETE | /events/webhook | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) WebhookList | GET | /events/webhook | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) EventsList | GET | /events | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) -GlustershEnable | POST | /volumes/{name}/heal/enable | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) -GlustershDisable | POST | /volumes/{name}/heal/disable | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) +SelfHealInfo | GET | /volumes/{name}/{opts}/heal-info | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [BrickHealInfo](https://godoc.org/github.com/gluster/glusterd2/pkg/api#BrickHealInfo) +SelfHealInfo2 | GET | /volumes/{name}/heal-info | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [BrickHealInfo](https://godoc.org/github.com/gluster/glusterd2/pkg/api#BrickHealInfo) DeviceAdd | POST | /devices/{peerid} | [AddDeviceReq](https://godoc.org/github.com/gluster/glusterd2/pkg/api#AddDeviceReq) | [AddDeviceResp](https://godoc.org/github.com/gluster/glusterd2/pkg/api#AddDeviceResp) DeviceList | GET | /devices/{peerid} | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [ListDeviceResp](https://godoc.org/github.com/gluster/glusterd2/pkg/api#ListDeviceResp) -DeviceEditState | POST | /devices/{peerid} | [EditDeviceStateReq](https://godoc.org/github.com/gluster/glusterd2/pkg/api#EditDeviceStateReq) | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) +ListAllDevices | GET | /devices | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [ListDeviceResp](https://godoc.org/github.com/gluster/glusterd2/pkg/api#ListDeviceResp) +RebalanceStart | POST | /volumes/{volname}/rebalance/start | [StartReq](https://godoc.org/github.com/gluster/glusterd2/pkg/api#StartReq) | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) +RebalanceStop | POST | /volumes/{volname}/rebalance/stop | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) +RebalanceStatus | GET | /volumes/{volname}/rebalance | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) +SmartVolumeCreate | POST | /smartvol | [VolCreateReq](https://godoc.org/github.com/gluster/glusterd2/pkg/api#VolCreateReq) | [VolumeCreateResp](https://godoc.org/github.com/gluster/glusterd2/pkg/api#VolumeCreateResp) Statedump | GET | /statedump | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) List Endpoints | GET | /endpoints | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [ListEndpointsResp](https://godoc.org/github.com/gluster/glusterd2/pkg/api#ListEndpointsResp) Glusterd2 service status | GET | /ping | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) diff --git a/glusterd2/commands/volumes/volume-shrink-txn.go b/glusterd2/commands/volumes/volume-shrink-txn.go new file mode 100644 index 000000000..5a7f86d5c --- /dev/null +++ b/glusterd2/commands/volumes/volume-shrink-txn.go @@ -0,0 +1,30 @@ +package volumecommands + +import ( + "github.com/gluster/glusterd2/glusterd2/daemon" + "github.com/gluster/glusterd2/glusterd2/transaction" + rebalance "github.com/gluster/glusterd2/plugins/rebalance" + rebalanceapi "github.com/gluster/glusterd2/plugins/rebalance/api" +) + +func startRebalance(c transaction.TxnCtx) error { + var rinfo rebalanceapi.RebalInfo + err := c.Get("rinfo", &rinfo) + if err != nil { + return err + } + + rebalanceProcess, err := rebalance.NewRebalanceProcess(rinfo) + if err != nil { + return err + } + + err = daemon.Start(rebalanceProcess, true, c.Logger()) + if err != nil { + c.Logger().WithError(err).WithField( + "volume", rinfo.Volname).Error("Starting rebalance process failed") + return err + } + + return err +} diff --git a/glusterd2/commands/volumes/volume-shrink.go b/glusterd2/commands/volumes/volume-shrink.go index 8dc66623b..93cbf2b98 100644 --- a/glusterd2/commands/volumes/volume-shrink.go +++ b/glusterd2/commands/volumes/volume-shrink.go @@ -6,7 +6,7 @@ import ( "path/filepath" "strings" - "github.com/gluster/glusterd2/glusterd2/daemon" + "github.com/gluster/glusterd2/glusterd2/events" "github.com/gluster/glusterd2/glusterd2/gdctx" restutils "github.com/gluster/glusterd2/glusterd2/servers/rest/utils" "github.com/gluster/glusterd2/glusterd2/transaction" @@ -26,23 +26,6 @@ func registerVolShrinkStepFuncs() { transaction.RegisterStepFunc(startRebalance, "vol-shrink.StartRebalance") } -func startRebalance(c transaction.TxnCtx) error { - var rinfo rebalanceapi.RebalInfo - err := c.Get("rinfo", &rinfo) - if err != nil { - return err - } - - rebalanceProcess, err := rebalance.NewRebalanceProcess(rinfo) - if err != nil { - return err - } - - err = daemon.Start(rebalanceProcess, true) - - return err -} - func validateVolumeShrinkReq(req api.VolShrinkReq) error { dupEntry := map[string]bool{} @@ -100,7 +83,7 @@ func volumeShrinkHandler(w http.ResponseWriter, r *http.Request) { } } if !isPresent { - restutils.SendHTTPError(ctx, w, http.StatusBadRequest, "One or more brick is not part of given volume") + restutils.SendHTTPError(ctx, w, http.StatusBadRequest, "One or more bricks is not part of given volume") return } } @@ -148,19 +131,20 @@ func volumeShrinkHandler(w http.ResponseWriter, r *http.Request) { if err != nil { restutils.SendHTTPError(ctx, w, http.StatusInternalServerError, err) return - } - // The following line is for testing purposes. - // It seems that there is no other way to include this information in the rebalance volfile right now. - volinfo.Options["distribute.decommissioned-bricks"] = strings.TrimSpace(decommissionedSubvols) + // TODO: Find a better way to store information in the rebalance volfile. + volinfo.Metadata["distribute.decommissioned-bricks"] = strings.TrimSpace(decommissionedSubvols) + + rinfo := rebalanceapi.RebalInfo{ + Volname: volname, + RebalanceID: uuid.NewRandom(), + Cmd: rebalanceapi.CmdStartForce, + State: rebalanceapi.NotStarted, + CommitHash: rebalance.SetCommitHash(), + RebalStats: []rebalanceapi.RebalNodeStatus{}, + } - var rinfo rebalanceapi.RebalInfo - rinfo.Volname = volname - rinfo.RebalanceID = uuid.NewRandom() - rinfo.Cmd = rebalanceapi.CmdStartForce - rinfo.State = rebalanceapi.NotStarted - rinfo.CommitHash = rebalance.SetCommitHash() if err := txn.Ctx.Set("rinfo", rinfo); err != nil { restutils.SendHTTPError(ctx, w, http.StatusInternalServerError, err) return @@ -173,19 +157,18 @@ func volumeShrinkHandler(w http.ResponseWriter, r *http.Request) { if err = txn.Do(); err != nil { logger.WithError(err).Error("remove bricks start transaction failed") - if err == transaction.ErrLockTimeout { - restutils.SendHTTPError(ctx, w, http.StatusConflict, err) - } else { - restutils.SendHTTPError(ctx, w, http.StatusInternalServerError, err) - } + status, err := restutils.ErrToStatusCode(err) + restutils.SendHTTPError(ctx, w, status, err) return } - + logger.WithField("volume-name", volinfo.Name).Info("volume shrink successful") + events.Broadcast(volume.NewEvent(volume.EventVolumeShrink, volinfo)) restutils.SendHTTPResponse(ctx, w, http.StatusOK, decommissionedSubvols) } func findDecommissioned(bricks []api.BrickReq, volinfo *volume.Volinfo) (string, error) { + brickSet := make(map[string]bool) for _, brick := range bricks { u := uuid.Parse(brick.PeerID) @@ -209,7 +192,6 @@ func findDecommissioned(bricks []api.BrickReq, volinfo *volume.Volinfo) (string, subvolMap[subvol.Name] = count + 1 } } - } } diff --git a/glusterd2/volume/events.go b/glusterd2/volume/events.go index b43ee2f6d..787a8d342 100644 --- a/glusterd2/volume/events.go +++ b/glusterd2/volume/events.go @@ -13,6 +13,8 @@ const ( EventVolumeCreated Event = "volume.created" // EventVolumeExpanded represents Volume Expand event EventVolumeExpanded = "volume.expanded" + // EventVolumeShrink represents Volume Shrink event + EventVolumeShrink = "volume.shrink" // EventVolumeStarted represents Volume Start event EventVolumeStarted = "volume.started" // EventVolumeStopped represents Volume Stop event