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

Commit

Permalink
API to remove device
Browse files Browse the repository at this point in the history
  • Loading branch information
rishubhjain committed Dec 11, 2018
1 parent 755eff7 commit 2d5a7e7
Show file tree
Hide file tree
Showing 7 changed files with 215 additions and 1 deletion.
1 change: 1 addition & 0 deletions doc/endpoints.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 26 additions & 0 deletions e2e/smartvol_ops_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,31 @@ func editDevice(t *testing.T) {
r.Nil(client.VolumeDelete(smartvolname))
}

func testDeviceDelete(t *testing.T) {
r := require.New(t)
peerList, err := client.Peers()
r.Nil(err)

var deviceList []deviceapi.Info
var peerID string
for _, peer := range peerList {
deviceList, err = client.DeviceList(peer.ID.String(), "")
r.Nil(err)
if len(deviceList) > 0 {
peerID = peer.ID.String()
break
}
}

err = client.DeviceDelete(peerID, deviceList[0].Device)
r.Nil(err)

newDeviceList, err := client.DeviceList(peerID, "")
r.Nil(err)

r.Equal(len(deviceList)-1, len(newDeviceList))
}

// TestSmartVolume creates a volume and starts it, runs further tests on it and
// finally deletes the volume
func TestSmartVolume(t *testing.T) {
Expand Down Expand Up @@ -526,6 +551,7 @@ func TestSmartVolume(t *testing.T) {
t.Run("Smartvol Disperse Volume", testSmartVolumeDisperse)
t.Run("Smartvol Distributed-Replicate Volume", testSmartVolumeDistributeReplicate)
t.Run("Smartvol Distributed-Disperse Volume", testSmartVolumeDistributeDisperse)
t.Run("Delete device", testDeviceDelete)
t.Run("Replace Brick", testReplaceBrick)
t.Run("Edit device", editDevice)

Expand Down
7 changes: 7 additions & 0 deletions pkg/restclient/device.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,10 @@ func (c *Client) DeviceEdit(peerid, device, state string) error {
err := c.post(url, req, http.StatusOK, nil)
return err
}

// DeviceDelete removes devices
func (c *Client) DeviceDelete(peerid, device string) error {
device = strings.TrimLeft(device, "/")
url := fmt.Sprintf("/v1/devices/%s/%s", peerid, device)
return c.del(url, nil, http.StatusNoContent, nil)
}
40 changes: 40 additions & 0 deletions plugins/device/deviceutils/store-utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ package deviceutils
import (
"context"
"encoding/json"
"errors"

"github.com/gluster/glusterd2/glusterd2/brick"
"github.com/gluster/glusterd2/glusterd2/gdctx"
"github.com/gluster/glusterd2/glusterd2/peer"
"github.com/gluster/glusterd2/glusterd2/store"
gderrors "github.com/gluster/glusterd2/pkg/errors"
"github.com/gluster/glusterd2/pkg/lvmutils"
Expand Down Expand Up @@ -70,6 +72,44 @@ func GetDevice(peerID, deviceName string) (*deviceapi.Info, error) {
return &device, nil
}

func updateDevices(peerID string, devices []deviceapi.Info) error {
peerInfo, err := peer.GetPeer(peerID)
if err != nil {
return err
}
deviceJSON, err := json.Marshal(devices)
peerInfo.Metadata["_devices"] = string(deviceJSON)
return peer.AddOrUpdatePeer(peerInfo)
}

func deviceInList(reqDevice string, devices []deviceapi.Info) int {
for index, key := range devices {
if reqDevice == key.Device {
return index
}
}
return -1
}

// DeleteDevice removes device from peer if device is not been used.
func DeleteDevice(peerID, deviceName string) error {
devices, err := GetDevices(peerID)
if err != nil {
return err
}

index := deviceInList(deviceName, devices)
if index < 0 {
return errors.New("device does not exist in the given peer")
}

// TODO: Check whether the device is being used or not before deleting.

// TODO: Not very efficient, can be improved
devices = append(devices[:index], devices[index+1:]...)
return updateDevices(peerID, devices)
}

// SetDeviceState sets device state and updates device state in etcd
func SetDeviceState(peerID, deviceName, deviceState string) error {
dev, err := GetDevice(peerID, deviceName)
Expand Down
10 changes: 9 additions & 1 deletion plugins/device/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,20 @@ func (p *Plugin) RestRoutes() route.Routes {
Pattern: "/devices",
Version: 1,
ResponseType: utils.GetTypeString((*deviceapi.ListDeviceResp)(nil)),
HandlerFunc: deviceListHandler},
HandlerFunc: listAllDevicesHandler},
route.Route{
Name: "DeviceDelete",
Method: "DELETE",
Pattern: "/devices/{peerid}/{device:.*}",
Version: 1,
HandlerFunc: deviceDeleteHandler,
},
}
}

// RegisterStepFuncs registers transaction step functions with
// Glusterd Transaction framework
func (p *Plugin) RegisterStepFuncs() {
transaction.RegisterStepFunc(txnPrepareDevice, "prepare-device")
transaction.RegisterStepFunc(txnDeleteDevice, "delete-device")
}
79 changes: 79 additions & 0 deletions plugins/device/rest.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,3 +194,82 @@ func deviceEditHandler(w http.ResponseWriter, r *http.Request) {

restutils.SendHTTPResponse(ctx, w, http.StatusOK, nil)
}

func deviceDeleteHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
logger := gdctx.GetReqLogger(ctx)
peerID := mux.Vars(r)["peerid"]
if uuid.Parse(peerID) == nil {
restutils.SendHTTPError(ctx, w, http.StatusBadRequest, "invalid peer-id passed in url")
return
}
deviceName := mux.Vars(r)["device"]
if deviceName == "" {
restutils.SendHTTPError(ctx, w, http.StatusBadRequest, "Device name not provided in URL")
return
}

// Adding prefix(/) to device name
deviceName = "/" + deviceName

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

peerInfo, err := peer.GetPeer(peerID)
if err != nil {
logger.WithError(err).WithField("peerid", peerID).Error("Peer ID not found in store")
if err == errors.ErrPeerNotFound {
restutils.SendHTTPError(ctx, w, http.StatusNotFound, errors.ErrPeerNotFound)
} else {
restutils.SendHTTPError(ctx, w, http.StatusInternalServerError, "failed to get peer details from store")
}
return
}

txn.Nodes = []uuid.UUID{peerInfo.ID}
txn.Steps = []*transaction.Step{
{
DoFunc: "delete-device",
Nodes: txn.Nodes,
},
}

err = txn.Ctx.Set("peerid", &peerID)
if err != nil {
restutils.SendHTTPError(ctx, w, http.StatusInternalServerError, err)
return
}

err = txn.Ctx.Set("device", &deviceName)
if err != nil {
restutils.SendHTTPError(ctx, w, http.StatusInternalServerError, err)
return
}

err = txn.Do()
if err != nil {
restutils.SendHTTPError(ctx, w, http.StatusInternalServerError, "transaction to prepare device failed")
return
}

restutils.SendHTTPResponse(ctx, w, http.StatusNoContent, nil)
}

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

ctx := r.Context()
logger := gdctx.GetReqLogger(ctx)
devices, err := deviceutils.GetDevices()
if err != nil {
logger.WithError(err).Error(err)
restutils.SendHTTPError(ctx, w, http.StatusInternalServerError, err)
return
}

restutils.SendHTTPResponse(ctx, w, http.StatusOK, devices)
}
53 changes: 53 additions & 0 deletions plugins/device/transaction.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package device

import (
"errors"

"github.com/gluster/glusterd2/glusterd2/transaction"
"github.com/gluster/glusterd2/pkg/lvmutils"
deviceapi "github.com/gluster/glusterd2/plugins/device/api"
Expand Down Expand Up @@ -59,3 +61,54 @@ func txnPrepareDevice(c transaction.TxnCtx) error {
}
return nil
}

func txnDeleteDevice(c transaction.TxnCtx) error {
var peerID string
if err := c.Get("peerid", &peerID); err != nil {
return err
}

var deviceName string
if err := c.Get("device", &deviceName); err != nil {
return err
}

devices, err := deviceutils.GetDevices(peerID)
if err != nil {
return err
}

if len(devices) == 0 {
return errors.New("No devices added in the given peer")
}

vgName := ""
for _, device := range devices {
if device.Device == deviceName {
vgName = device.VgName()
}
}

if vgName == "" {
return errors.New("No device found with given device name")
}

// Remove VG
if err := lvmutils.RemoveVG(vgName); err != nil {
c.Logger().WithError(err).WithField("device", deviceName).Error("Failed to remove volume group")
return err
}

//Remove PV
if err := lvmutils.RemovePV(deviceName); err != nil {
c.Logger().WithError(err).WithField("device", deviceName).Error("Failed to remove physical volume")
return err
}

err = deviceutils.DeleteDevice(peerID, deviceName)
if err != nil {
c.Logger().WithError(err).WithField("peerid", peerID).Error("Failed to remove device")
return err
}
return nil
}

0 comments on commit 2d5a7e7

Please sign in to comment.