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 12, 2018
1 parent 755eff7 commit 17496a8
Show file tree
Hide file tree
Showing 8 changed files with 310 additions and 74 deletions.
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.

155 changes: 155 additions & 0 deletions e2e/device_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
package e2e

import (
"testing"

"github.com/gluster/glusterd2/pkg/api"
gutils "github.com/gluster/glusterd2/pkg/utils"
deviceapi "github.com/gluster/glusterd2/plugins/device/api"

"github.com/stretchr/testify/require"
)

func editDevice(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(), "")
if len(deviceList) > 0 {
peerID = peer.ID.String()
break
}
}

device := deviceList[0]
if device.State == "enabled" {
err = client.DeviceEdit(peerID, device.Device, "disabled")
r.Nil(err)
} else if device.State == "disabled" {
err = client.DeviceEdit(peerID, device.Device, "enabled")
r.Nil(err)
}
newDeviceList, err := client.DeviceList(peerID, "")
r.Nil(err)
for _, newDevice := range newDeviceList {
if newDevice.Device == device.Device {
r.NotEqual(newDevice.State, device.State)
}
}

for _, peer := range peerList {
deviceList, err := client.DeviceList(peer.ID.String(), "")
r.Nil(err)
for _, device := range deviceList {
if device.State == "enabled" {
err = client.DeviceEdit(peer.ID.String(), device.Device, "disabled")
r.Nil(err)
}
}
}
smartvolname := formatVolName(t.Name())

// create Distribute Replicate(2x3) Volume
createReq := api.VolCreateReq{
Name: smartvolname,
Size: 40 * gutils.MiB,
DistributeCount: 2,
ReplicaCount: 3,
SubvolZonesOverlap: true,
}
_, err = client.VolumeCreate(createReq)
r.NotNil(err)

for _, peer := range peerList {
deviceList, err := client.DeviceList(peer.ID.String(), "")
r.Nil(err)
for _, device := range deviceList {
if device.State == "disabled" {
err = client.DeviceEdit(peer.ID.String(), device.Device, "enabled")
r.Nil(err)
}
}
}

_, err = client.VolumeCreate(createReq)
r.Nil(err)

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))
}

// TestDevice creates devices in the test environment
// finally deletes the devices
func TestDevice(t *testing.T) {
var err error

r := require.New(t)

tc, err := setupCluster(t, "./config/1.toml", "./config/2.toml", "./config/3.toml")
r.Nil(err)
defer teardownCluster(tc)

client, err = initRestclient(tc.gds[0])
r.Nil(err)
r.NotNil(client)

devicesDir := testTempDir(t, "devices")

// Device Setup
// Around 150MB will be reserved during pv/vg creation, create device with more size
r.Nil(prepareLoopDevice(devicesDir+"/gluster_dev1.img", "1", "250M"))
r.Nil(prepareLoopDevice(devicesDir+"/gluster_dev2.img", "2", "250M"))
r.Nil(prepareLoopDevice(devicesDir+"/gluster_dev3.img", "3", "250M"))

_, err = client.DeviceAdd(tc.gds[0].PeerID(), "/dev/gluster_loop1")
r.Nil(err)
dev, err := client.DeviceList(tc.gds[0].PeerID(), "/dev/gluster_loop1")
r.Nil(err)
r.Equal(dev[0].Device, "/dev/gluster_loop1")

_, err = client.DeviceAdd(tc.gds[1].PeerID(), "/dev/gluster_loop2")
r.Nil(err)
dev, err = client.DeviceList(tc.gds[1].PeerID(), "/dev/gluster_loop2")
r.Nil(err)
r.Equal(dev[0].Device, "/dev/gluster_loop2")

_, err = client.DeviceAdd(tc.gds[2].PeerID(), "/dev/gluster_loop3")
r.Nil(err)
dev, err = client.DeviceList(tc.gds[2].PeerID(), "/dev/gluster_loop3")
r.Nil(err)
r.Equal(dev[0].Device, "/dev/gluster_loop3")

t.Run("Edit device", editDevice)
t.Run("Delete device", testDeviceDelete)

// // Device Cleanup
r.Nil(loopDevicesCleanup(t))
}
73 changes: 0 additions & 73 deletions e2e/smartvol_ops_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (

"github.com/gluster/glusterd2/pkg/api"
gutils "github.com/gluster/glusterd2/pkg/utils"
deviceapi "github.com/gluster/glusterd2/plugins/device/api"

"github.com/pborman/uuid"
"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -407,77 +406,6 @@ func testSmartVolumeDistributeDisperse(t *testing.T) {
checkZeroLvs(r)
}

func editDevice(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(), "")
if len(deviceList) > 0 {
peerID = peer.ID.String()
break
}
}

device := deviceList[0]
if device.State == "enabled" {
err = client.DeviceEdit(peerID, device.Device, "disabled")
r.Nil(err)
} else if device.State == "disabled" {
err = client.DeviceEdit(peerID, device.Device, "enabled")
r.Nil(err)
}
newDeviceList, err := client.DeviceList(peerID, "")
r.Nil(err)
for _, newDevice := range newDeviceList {
if newDevice.Device == device.Device {
r.NotEqual(newDevice.State, device.State)
}
}

for _, peer := range peerList {
deviceList, err := client.DeviceList(peer.ID.String(), "")
r.Nil(err)
for _, device := range deviceList {
if device.State == "enabled" {
err = client.DeviceEdit(peer.ID.String(), device.Device, "disabled")
r.Nil(err)
}
}
}
smartvolname := formatVolName(t.Name())

// create Distribute Replicate(2x3) Volume
createReq := api.VolCreateReq{
Name: smartvolname,
Size: 40 * gutils.MiB,
DistributeCount: 2,
ReplicaCount: 3,
SubvolZonesOverlap: true,
}
_, err = client.VolumeCreate(createReq)
r.NotNil(err)

for _, peer := range peerList {
deviceList, err := client.DeviceList(peer.ID.String(), "")
r.Nil(err)
for _, device := range deviceList {
if device.State == "disabled" {
err = client.DeviceEdit(peer.ID.String(), device.Device, "enabled")
r.Nil(err)
}
}
}

_, err = client.VolumeCreate(createReq)
r.Nil(err)

r.Nil(client.VolumeDelete(smartvolname))
}

// 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 @@ -527,7 +455,6 @@ func TestSmartVolume(t *testing.T) {
t.Run("Smartvol Distributed-Replicate Volume", testSmartVolumeDistributeReplicate)
t.Run("Smartvol Distributed-Disperse Volume", testSmartVolumeDistributeDisperse)
t.Run("Replace Brick", testReplaceBrick)
t.Run("Edit device", editDevice)

// // Device Cleanup
r.Nil(loopDevicesCleanup(t))
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)
}
6 changes: 6 additions & 0 deletions plugins/device/deviceutils/store-utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@ func GetDevice(peerID, deviceName string) (*deviceapi.Info, error) {
return &device, nil
}

// DeleteDevice removes device from peer if device is not been used.
func DeleteDevice(peerID, deviceName string) error {
_, e := store.Delete(context.TODO(), devicePrefix+peerID+"/"+deviceName)
return e
}

// 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)
}
Loading

0 comments on commit 17496a8

Please sign in to comment.