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

Commit 98967b9

Browse files
committed
API to remove device
1 parent 755eff7 commit 98967b9

File tree

7 files changed

+215
-1
lines changed

7 files changed

+215
-1
lines changed

doc/endpoints.md

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

e2e/smartvol_ops_test.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,31 @@ func editDevice(t *testing.T) {
478478
r.Nil(client.VolumeDelete(smartvolname))
479479
}
480480

481+
func testDeviceDelete(t *testing.T) {
482+
r := require.New(t)
483+
peerList, err := client.Peers()
484+
r.Nil(err)
485+
486+
var deviceList []deviceapi.Info
487+
var peerID string
488+
for _, peer := range peerList {
489+
deviceList, err = client.DeviceList(peer.ID.String(), "")
490+
r.Nil(err)
491+
if len(deviceList) > 0 {
492+
peerID = peer.ID.String()
493+
break
494+
}
495+
}
496+
497+
err = client.DeviceDelete(peerID, deviceList[0].Device)
498+
r.Nil(err)
499+
500+
newDeviceList, err := client.DeviceList(peerID, "")
501+
r.Nil(err)
502+
503+
r.Equal(len(deviceList)-1, len(newDeviceList))
504+
}
505+
481506
// TestSmartVolume creates a volume and starts it, runs further tests on it and
482507
// finally deletes the volume
483508
func TestSmartVolume(t *testing.T) {
@@ -528,6 +553,7 @@ func TestSmartVolume(t *testing.T) {
528553
t.Run("Smartvol Distributed-Disperse Volume", testSmartVolumeDistributeDisperse)
529554
t.Run("Replace Brick", testReplaceBrick)
530555
t.Run("Edit device", editDevice)
556+
t.Run("Delete device", testDeviceDelete)
531557

532558
// // Device Cleanup
533559
r.Nil(loopDevicesCleanup(t))

pkg/restclient/device.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,10 @@ func (c *Client) DeviceEdit(peerid, device, state string) error {
4343
err := c.post(url, req, http.StatusOK, nil)
4444
return err
4545
}
46+
47+
// DeviceDelete removes devices
48+
func (c *Client) DeviceDelete(peerid, device string) error {
49+
device = strings.TrimLeft(device, "/")
50+
url := fmt.Sprintf("/v1/devices/%s/%s", peerid, device)
51+
return c.del(url, nil, http.StatusNoContent, nil)
52+
}

plugins/device/deviceutils/store-utils.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ package deviceutils
33
import (
44
"context"
55
"encoding/json"
6+
"errors"
67

78
"github.com/gluster/glusterd2/glusterd2/brick"
89
"github.com/gluster/glusterd2/glusterd2/gdctx"
10+
"github.com/gluster/glusterd2/glusterd2/peer"
911
"github.com/gluster/glusterd2/glusterd2/store"
1012
gderrors "github.com/gluster/glusterd2/pkg/errors"
1113
"github.com/gluster/glusterd2/pkg/lvmutils"
@@ -70,6 +72,44 @@ func GetDevice(peerID, deviceName string) (*deviceapi.Info, error) {
7072
return &device, nil
7173
}
7274

75+
func updateDevices(peerID string, devices []deviceapi.Info) error {
76+
peerInfo, err := peer.GetPeer(peerID)
77+
if err != nil {
78+
return err
79+
}
80+
deviceJSON, err := json.Marshal(devices)
81+
peerInfo.Metadata["_devices"] = string(deviceJSON)
82+
return peer.AddOrUpdatePeer(peerInfo)
83+
}
84+
85+
func deviceInList(reqDevice string, devices []deviceapi.Info) int {
86+
for index, key := range devices {
87+
if reqDevice == key.Device {
88+
return index
89+
}
90+
}
91+
return -1
92+
}
93+
94+
// DeleteDevice removes device from peer if device is not been used.
95+
func DeleteDevice(peerID, deviceName string) error {
96+
devices, err := GetDevices(peerID)
97+
if err != nil {
98+
return err
99+
}
100+
101+
index := deviceInList(deviceName, devices)
102+
if index < 0 {
103+
return errors.New("device does not exist in the given peer")
104+
}
105+
106+
// TODO: Check whether the device is being used or not before deleting.
107+
108+
// TODO: Not very efficient, can be improved
109+
devices = append(devices[:index], devices[index+1:]...)
110+
return updateDevices(peerID, devices)
111+
}
112+
73113
// SetDeviceState sets device state and updates device state in etcd
74114
func SetDeviceState(peerID, deviceName, deviceState string) error {
75115
dev, err := GetDevice(peerID, deviceName)

plugins/device/init.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,20 @@ func (p *Plugin) RestRoutes() route.Routes {
5454
Pattern: "/devices",
5555
Version: 1,
5656
ResponseType: utils.GetTypeString((*deviceapi.ListDeviceResp)(nil)),
57-
HandlerFunc: deviceListHandler},
57+
HandlerFunc: listAllDevicesHandler},
58+
route.Route{
59+
Name: "DeviceDelete",
60+
Method: "DELETE",
61+
Pattern: "/devices/{peerid}/{device:.*}",
62+
Version: 1,
63+
HandlerFunc: deviceDeleteHandler,
64+
},
5865
}
5966
}
6067

6168
// RegisterStepFuncs registers transaction step functions with
6269
// Glusterd Transaction framework
6370
func (p *Plugin) RegisterStepFuncs() {
6471
transaction.RegisterStepFunc(txnPrepareDevice, "prepare-device")
72+
transaction.RegisterStepFunc(txnDeleteDevice, "delete-device")
6573
}

plugins/device/rest.go

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,3 +194,82 @@ func deviceEditHandler(w http.ResponseWriter, r *http.Request) {
194194

195195
restutils.SendHTTPResponse(ctx, w, http.StatusOK, nil)
196196
}
197+
198+
func deviceDeleteHandler(w http.ResponseWriter, r *http.Request) {
199+
ctx := r.Context()
200+
logger := gdctx.GetReqLogger(ctx)
201+
peerID := mux.Vars(r)["peerid"]
202+
if uuid.Parse(peerID) == nil {
203+
restutils.SendHTTPError(ctx, w, http.StatusBadRequest, "invalid peer-id passed in url")
204+
return
205+
}
206+
deviceName := mux.Vars(r)["device"]
207+
if deviceName == "" {
208+
restutils.SendHTTPError(ctx, w, http.StatusBadRequest, "Device name not provided in URL")
209+
return
210+
}
211+
212+
// Adding prefix(/) to device name
213+
deviceName = "/" + deviceName
214+
215+
txn, err := transaction.NewTxnWithLocks(ctx, peerID+deviceName)
216+
if err != nil {
217+
status, err := restutils.ErrToStatusCode(err)
218+
restutils.SendHTTPError(ctx, w, status, err)
219+
return
220+
}
221+
defer txn.Done()
222+
223+
peerInfo, err := peer.GetPeer(peerID)
224+
if err != nil {
225+
logger.WithError(err).WithField("peerid", peerID).Error("Peer ID not found in store")
226+
if err == errors.ErrPeerNotFound {
227+
restutils.SendHTTPError(ctx, w, http.StatusNotFound, errors.ErrPeerNotFound)
228+
} else {
229+
restutils.SendHTTPError(ctx, w, http.StatusInternalServerError, "failed to get peer details from store")
230+
}
231+
return
232+
}
233+
234+
txn.Nodes = []uuid.UUID{peerInfo.ID}
235+
txn.Steps = []*transaction.Step{
236+
{
237+
DoFunc: "delete-device",
238+
Nodes: txn.Nodes,
239+
},
240+
}
241+
242+
err = txn.Ctx.Set("peerid", &peerID)
243+
if err != nil {
244+
restutils.SendHTTPError(ctx, w, http.StatusInternalServerError, err)
245+
return
246+
}
247+
248+
err = txn.Ctx.Set("device", &deviceName)
249+
if err != nil {
250+
restutils.SendHTTPError(ctx, w, http.StatusInternalServerError, err)
251+
return
252+
}
253+
254+
err = txn.Do()
255+
if err != nil {
256+
restutils.SendHTTPError(ctx, w, http.StatusInternalServerError, "transaction to prepare device failed")
257+
return
258+
}
259+
260+
restutils.SendHTTPResponse(ctx, w, http.StatusNoContent, nil)
261+
}
262+
263+
func listAllDevicesHandler(w http.ResponseWriter, r *http.Request) {
264+
265+
ctx := r.Context()
266+
logger := gdctx.GetReqLogger(ctx)
267+
devices, err := deviceutils.GetDevices()
268+
if err != nil {
269+
logger.WithError(err).Error(err)
270+
restutils.SendHTTPError(ctx, w, http.StatusInternalServerError, err)
271+
return
272+
}
273+
274+
restutils.SendHTTPResponse(ctx, w, http.StatusOK, devices)
275+
}

plugins/device/transaction.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package device
22

33
import (
4+
"errors"
5+
46
"github.com/gluster/glusterd2/glusterd2/transaction"
57
"github.com/gluster/glusterd2/pkg/lvmutils"
68
deviceapi "github.com/gluster/glusterd2/plugins/device/api"
@@ -59,3 +61,54 @@ func txnPrepareDevice(c transaction.TxnCtx) error {
5961
}
6062
return nil
6163
}
64+
65+
func txnDeleteDevice(c transaction.TxnCtx) error {
66+
var peerID string
67+
if err := c.Get("peerid", &peerID); err != nil {
68+
return err
69+
}
70+
71+
var deviceName string
72+
if err := c.Get("device", &deviceName); err != nil {
73+
return err
74+
}
75+
76+
devices, err := deviceutils.GetDevices(peerID)
77+
if err != nil {
78+
return err
79+
}
80+
81+
if len(devices) == 0 {
82+
return errors.New("No devices added in the given peer")
83+
}
84+
85+
vgName := ""
86+
for _, device := range devices {
87+
if device.Device == deviceName {
88+
vgName = device.VgName()
89+
}
90+
}
91+
92+
if vgName == "" {
93+
return errors.New("No device found with given device name")
94+
}
95+
96+
// Remove VG
97+
if err := lvmutils.RemoveVG(vgName); err != nil {
98+
c.Logger().WithError(err).WithField("device", deviceName).Error("Failed to remove volume group")
99+
return err
100+
}
101+
102+
//Remove PV
103+
if err := lvmutils.RemovePV(deviceName); err != nil {
104+
c.Logger().WithError(err).WithField("device", deviceName).Error("Failed to remove physical volume")
105+
return err
106+
}
107+
108+
err = deviceutils.DeleteDevice(peerID, deviceName)
109+
if err != nil {
110+
c.Logger().WithError(err).WithField("peerid", peerID).Error("Failed to remove device")
111+
return err
112+
}
113+
return nil
114+
}

0 commit comments

Comments
 (0)