Skip to content

Commit

Permalink
Add authentication to REST Calls for Migration. (#936)
Browse files Browse the repository at this point in the history
  • Loading branch information
Paul Theunis authored Mar 18, 2019
1 parent c0b02c8 commit a1f1699
Show file tree
Hide file tree
Showing 3 changed files with 164 additions and 91 deletions.
94 changes: 77 additions & 17 deletions api/server/migrate.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"net/http"

"github.com/libopenstorage/openstorage/api"
ost_errors "github.com/libopenstorage/openstorage/api/errors"
)

func (vd *volAPI) cloudMigrateStart(w http.ResponseWriter, r *http.Request) {
Expand All @@ -17,21 +16,52 @@ func (vd *volAPI) cloudMigrateStart(w http.ResponseWriter, r *http.Request) {
return
}

d, err := vd.getVolDriver(r)
// Get context with auth token
ctx, err := vd.annotateContext(r)
if err != nil {
notFound(w, r)
vd.sendError(vd.name, method, w, err.Error(), http.StatusBadRequest)
return
}

response, err := d.CloudMigrateStart(startReq)
// Get gRPC connection
conn, err := vd.getConn()
if err != nil {
if _, ok := err.(*ost_errors.ErrExists); ok {
w.WriteHeader(http.StatusConflict)
return
vd.sendError(vd.name, method, w, err.Error(), http.StatusInternalServerError)
return
}

migrations := api.NewOpenStorageMigrateClient(conn)
migrateRequest := &api.SdkCloudMigrateStartRequest{
ClusterId: startReq.ClusterId,
}

switch startReq.Operation {
case api.CloudMigrate_MigrateCluster:
migrateRequest.Opt = &api.SdkCloudMigrateStartRequest_AllVolumes{
AllVolumes: &api.SdkCloudMigrateStartRequest_MigrateAllVolumes{},
}
case api.CloudMigrate_MigrateVolume:
migrateRequest.Opt = &api.SdkCloudMigrateStartRequest_Volume{
Volume: &api.SdkCloudMigrateStartRequest_MigrateVolume{
VolumeId: startReq.TargetId,
},
}
case api.CloudMigrate_MigrateVolumeGroup:
migrateRequest.Opt = &api.SdkCloudMigrateStartRequest_VolumeGroup{
VolumeGroup: &api.SdkCloudMigrateStartRequest_MigrateVolumeGroup{
GroupId: startReq.TargetId,
},
}
}

resp, err := migrations.Start(ctx, migrateRequest)
if err != nil {
vd.sendError(method, startReq.TargetId, w, err.Error(), http.StatusInternalServerError)
return
}
response := &api.CloudMigrateStartResponse{
TaskId: resp.GetResult().GetTaskId(),
}
json.NewEncoder(w).Encode(response)
}

Expand All @@ -44,13 +74,26 @@ func (vd *volAPI) cloudMigrateCancel(w http.ResponseWriter, r *http.Request) {
return
}

d, err := vd.getVolDriver(r)
// Get context with auth token
ctx, err := vd.annotateContext(r)
if err != nil {
notFound(w, r)
vd.sendError(vd.name, method, w, err.Error(), http.StatusBadRequest)
return
}

err = d.CloudMigrateCancel(cancelReq)
// Get gRPC connection
conn, err := vd.getConn()
if err != nil {
vd.sendError(vd.name, method, w, err.Error(), http.StatusInternalServerError)
return
}

migrations := api.NewOpenStorageMigrateClient(conn)
migrateRequest := &api.SdkCloudMigrateCancelRequest{
Request: cancelReq,
}

_, err = migrations.Cancel(ctx, migrateRequest)
if err != nil {
vd.sendError(method, cancelReq.TaskId, w, err.Error(), http.StatusInternalServerError)
return
Expand All @@ -62,12 +105,6 @@ func (vd *volAPI) cloudMigrateStatus(w http.ResponseWriter, r *http.Request) {
statusReq := &api.CloudMigrateStatusRequest{}
method := "cloudMigrateState"

d, err := vd.getVolDriver(r)
if err != nil {
notFound(w, r)
return
}

// Use empty request if nothing was sent
if r.ContentLength != 0 {
if err := json.NewDecoder(r.Body).Decode(statusReq); err != nil {
Expand All @@ -76,11 +113,34 @@ func (vd *volAPI) cloudMigrateStatus(w http.ResponseWriter, r *http.Request) {
}
}

statusResp, err := d.CloudMigrateStatus(statusReq)
// Get context with auth token
ctx, err := vd.annotateContext(r)
if err != nil {
vd.sendError(vd.name, method, w, err.Error(), http.StatusBadRequest)
return
}

// Get gRPC connection
conn, err := vd.getConn()
if err != nil {
vd.sendError(vd.name, method, w, err.Error(), http.StatusInternalServerError)
return
}

migrations := api.NewOpenStorageMigrateClient(conn)
migrateRequest := &api.SdkCloudMigrateStatusRequest{
Request: statusReq,
}

resp, err := migrations.Status(ctx, migrateRequest)
if err != nil {
vd.sendError(method, "", w, err.Error(), http.StatusInternalServerError)
return
}

statusResp := &api.CloudMigrateStatusResponse{
Info: resp.GetResult().GetInfo(),
}

json.NewEncoder(w).Encode(statusResp)
}
145 changes: 71 additions & 74 deletions api/server/migrate_test.go
Original file line number Diff line number Diff line change
@@ -1,111 +1,108 @@
package server

/*
import (
"fmt"
"testing"
"context"
"github.com/libopenstorage/openstorage/api"
client "github.com/libopenstorage/openstorage/api/client/volume"
"github.com/stretchr/testify/require"
volumeclient "github.com/libopenstorage/openstorage/api/client/volume"
"github.com/stretchr/testify/assert"
"testing"
)

func TestMigrateStart(t *testing.T) {
ts, testVolDriver := testRestServer(t)
var err error
// Setup volume rest functions server
ts, testVolDriver := testRestServerSdk(t)
defer ts.Close()
defer testVolDriver.Stop()

cl, err := client.NewDriverClient(ts.URL, mockDriverName, "", mockDriverName)
require.NoError(t, err)
// get token
token, err := createToken("test", "system.admin", testSharedSecret)
assert.NoError(t, err)

cl, err := volumeclient.NewAuthDriverClient(ts.URL, "fake", version, token, "", "fake")
assert.NoError(t, err)

// Setup request
name := "myvol"
size := uint64(1234)
req := &api.VolumeCreateRequest{
Locator: &api.VolumeLocator{Name: name},
Source: &api.Source{},
Spec: &api.VolumeSpec{
HaLevel: 3,
Size: size,
Format: api.FSType_FS_TYPE_EXT4,
Shared: true,
},
}

// Create a volume client
driverclient := volumeclient.VolumeDriver(cl)
id, err := driverclient.Create(req.GetLocator(), req.GetSource(), req.GetSpec())
assert.Nil(t, err)
assert.NotEmpty(t, id)

goodRequest := &api.CloudMigrateStartRequest{
Operation: api.CloudMigrate_MigrateCluster,
Operation: api.CloudMigrate_MigrateVolume,
ClusterId: "clusterID",
TargetId: "goodVolumeID",
TargetId: id,
}
badRequest := &api.CloudMigrateStartRequest{
Operation: api.CloudMigrate_MigrateCluster,
ClusterId: "clusterID",
TargetId: "badVolumeID",
}
goodResponse := &api.CloudMigrateStartResponse{
TaskId: "random-id",
}
testVolDriver.MockDriver().EXPECT().CloudMigrateStart(badRequest).Return(nil, fmt.Errorf("Volume not found")).Times(1)
testVolDriver.MockDriver().EXPECT().CloudMigrateStart(goodRequest).Return(goodResponse, nil).Times(1)

// Start Migrate
resp, err := client.VolumeDriver(cl).CloudMigrateStart(badRequest)
require.Error(t, err)
require.Nil(t, resp)
require.Contains(t, err.Error(), "Volume not found")
resp, err = client.VolumeDriver(cl).CloudMigrateStart(goodRequest)
require.NoError(t, err)
require.Equal(t, goodResponse.TaskId, resp.TaskId, "Unexpected taskId in response")
resp, err := volumeclient.VolumeDriver(cl).CloudMigrateStart(goodRequest)
assert.Nil(t, err)
assert.NotNil(t, resp.TaskId)

// Assert volume information is correct
volumes := api.NewOpenStorageVolumeClient(testVolDriver.Conn())
ctx, err := contextWithToken(context.Background(), "test", "system.admin", testSharedSecret)
assert.NoError(t, err)

_, err = volumes.Delete(ctx, &api.SdkVolumeDeleteRequest{
VolumeId: id,
})
assert.NoError(t, err)
}

func TestMigrateCancel(t *testing.T) {
ts, testVolDriver := testRestServer(t)
var err error
// Setup volume rest functions server
ts, testVolDriver := testRestServerSdk(t)
defer ts.Close()
defer testVolDriver.Stop()

cl, err := client.NewDriverClient(ts.URL, mockDriverName, "", mockDriverName)
require.NoError(t, err)
// get token
token, err := createToken("test", "system.admin", testSharedSecret)
assert.NoError(t, err)

cl, err := volumeclient.NewAuthDriverClient(ts.URL, "fake", version, token, "", "fake")
assert.NoError(t, err)

goodRequest := &api.CloudMigrateCancelRequest{
TaskId: "goodTaskID",
}
badRequest := &api.CloudMigrateCancelRequest{
TaskId: "badTaskID",
}
testVolDriver.MockDriver().EXPECT().CloudMigrateCancel(badRequest).Return(fmt.Errorf("TaskId not found")).Times(1)
testVolDriver.MockDriver().EXPECT().CloudMigrateCancel(goodRequest).Return(nil).Times(1)

// Cancel Migrate
err = client.VolumeDriver(cl).CloudMigrateCancel(badRequest)
require.Error(t, err)
require.Contains(t, err.Error(), "TaskId not found")
err = client.VolumeDriver(cl).CloudMigrateCancel(goodRequest)
require.NoError(t, err)
err = volumeclient.VolumeDriver(cl).CloudMigrateCancel(goodRequest)
assert.Nil(t, err)
}

func TestMigrateiStatus(t *testing.T) {
ts, testVolDriver := testRestServer(t)
func TestMigrateStatus(t *testing.T) {
var err error
// Setup volume rest functions server
ts, testVolDriver := testRestServerSdk(t)
defer ts.Close()
defer testVolDriver.Stop()

cl, err := client.NewDriverClient(ts.URL, mockDriverName, "", mockDriverName)
require.NoError(t, err)
emptyStatus := &api.CloudMigrateStatusResponse{}
statusResponse := &api.CloudMigrateStatusResponse{
Info: map[string]*api.CloudMigrateInfoList{
"clusterId": &api.CloudMigrateInfoList{
List: []*api.CloudMigrateInfo{
&api.CloudMigrateInfo{
TaskId: "taskId",
ClusterId: "clusterId",
LocalVolumeId: "localVolumeId",
LocalVolumeName: "localVolumeName",
RemoteVolumeId: "remoteVolumeName",
CloudbackupId: "cloudbackupId",
CurrentStage: api.CloudMigrate_Done,
Status: api.CloudMigrate_Complete,
}}}},
}
// get token
token, err := createToken("test", "system.admin", testSharedSecret)
assert.NoError(t, err)

testVolDriver.MockDriver().EXPECT().CloudMigrateStatus(&api.CloudMigrateStatusRequest{}).Return(emptyStatus, nil).Times(1)
testVolDriver.MockDriver().EXPECT().CloudMigrateStatus(&api.CloudMigrateStatusRequest{}).Return(statusResponse, nil).Times(1)
cl, err := volumeclient.NewAuthDriverClient(ts.URL, "fake", version, token, "", "fake")
assert.NoError(t, err)

// Get Migrate status
status, err := client.VolumeDriver(cl).CloudMigrateStatus(&api.CloudMigrateStatusRequest{})
require.NoError(t, err)
require.Equal(t, 0, len(status.Info))
status, err = client.VolumeDriver(cl).CloudMigrateStatus(&api.CloudMigrateStatusRequest{})
require.NoError(t, err)
require.Equal(t, 1, len(status.Info))
require.Equal(t, statusResponse, status)
resp, err := volumeclient.VolumeDriver(cl).CloudMigrateStatus(&api.CloudMigrateStatusRequest{})
assert.Nil(t, err)
assert.Equal(t, 1, len(resp.Info))
}
*/
16 changes: 16 additions & 0 deletions volume/drivers/fake/fake.go
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,22 @@ func (d *driver) Detach(volumeID string, options map[string]string) error {
return nil
}

func (d *driver) CloudMigrateStart(request *api.CloudMigrateStartRequest) (*api.CloudMigrateStartResponse, error) {
return &api.CloudMigrateStartResponse{TaskId: request.TaskId}, nil
}

func (d *driver) CloudMigrateCancel(request *api.CloudMigrateCancelRequest) error {
return nil
}

func (d *driver) CloudMigrateStatus(request *api.CloudMigrateStatusRequest) (*api.CloudMigrateStatusResponse, error) {
cml := make(map[string]*api.CloudMigrateInfoList, 0)
cml["result"] = &api.CloudMigrateInfoList{}
return &api.CloudMigrateStatusResponse{
Info: cml,
}, nil
}

func (d *driver) Set(volumeID string, locator *api.VolumeLocator, spec *api.VolumeSpec) error {
v, err := d.GetVol(volumeID)
if err != nil {
Expand Down

0 comments on commit a1f1699

Please sign in to comment.