Skip to content

Commit 74602fc

Browse files
authored
feat(CLOUDDEV-2535): Add live migration (#96)
* feat(CLOUDDEV-2535): Add instance live migration support * test(CLOUDDEV-2535): Add unit tests for instance live migration
1 parent e123694 commit 74602fc

File tree

2 files changed

+80
-0
lines changed

2 files changed

+80
-0
lines changed

instances.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ const (
3838
instancesInterfaces = "interfaces"
3939
instancesPutIntoServerGroup = "put_into_servergroup"
4040
instancesRemoveFromServerGroup = "remove_from_servergroup"
41+
instancesLiveMigration = "migrate"
4142
)
4243

4344
// InstancesService is an interface for creating and managing Instances with the EdgecenterCloud API.
@@ -58,6 +59,7 @@ type InstancesService interface {
5859
InterfaceList(context.Context, string) ([]InstancePortInterface, *Response, error)
5960
PutIntoServerGroup(context.Context, string, *InstancePutIntoServerGroupRequest) (*TaskResponse, *Response, error)
6061
RemoveFromServerGroup(context.Context, string) (*TaskResponse, *Response, error)
62+
Migrate(context.Context, string, *InstanceMigrateRequest) (*TaskResponse, *Response, error)
6163

6264
InstanceAction
6365
InstanceFlavor
@@ -262,6 +264,11 @@ type InstanceCheckFlavorVolumeRequest struct {
262264
Volumes []InstanceVolumeCreate `json:"volumes" required:"true" validate:"required,dive"`
263265
}
264266

267+
// InstanceMigrateRequest represents a request to migrate an Instance to another availability zone.
268+
type InstanceMigrateRequest struct {
269+
AvailabilityZone string `json:"availability_zone" required:"true"`
270+
}
271+
265272
type InstanceAvailableNames struct {
266273
AllowedBMNameWinTemplates []string `json:"allowed_bm_name_win_templates"`
267274
NameTemplatesLimited bool `json:"name_templates_limited"`
@@ -471,6 +478,37 @@ func (s *InstancesServiceOp) Delete(ctx context.Context, instanceID string, opts
471478
return tasks, resp, err
472479
}
473480

481+
// Migrate the Instance to another availability zone.
482+
func (s *InstancesServiceOp) Migrate(ctx context.Context, instanceID string, reqBody *InstanceMigrateRequest) (*TaskResponse, *Response, error) {
483+
if resp, err := isValidUUID(instanceID, "instanceID"); err != nil {
484+
return nil, resp, err
485+
}
486+
487+
if resp, err := s.client.Validate(); err != nil {
488+
return nil, resp, err
489+
}
490+
491+
path := fmt.Sprintf(
492+
"%s/%s/%s",
493+
s.client.addProjectRegionPath(instancesBasePathV1),
494+
instanceID,
495+
instancesLiveMigration,
496+
)
497+
498+
req, err := s.client.NewRequest(ctx, http.MethodPost, path, reqBody)
499+
if err != nil {
500+
return nil, nil, err
501+
}
502+
503+
tasks := new(TaskResponse)
504+
resp, err := s.client.Do(ctx, req, tasks)
505+
if err != nil {
506+
return nil, resp, err
507+
}
508+
509+
return tasks, resp, err
510+
}
511+
474512
// MetadataGet instance detailed metadata (tags).
475513
func (s *InstancesServiceOp) MetadataGet(ctx context.Context, instanceID string) (*MetadataDetailed, *Response, error) {
476514
if resp, err := isValidUUID(instanceID, "instanceID"); err != nil {

instances_test.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1411,3 +1411,45 @@ func TestInstances_RemoveFromServerGroup_ResponseError(t *testing.T) {
14111411
assert.Error(t, err)
14121412
assert.Equal(t, resp.StatusCode, 400)
14131413
}
1414+
1415+
func TestInstances_Migrate(t *testing.T) {
1416+
setup()
1417+
defer teardown()
1418+
1419+
request := &InstanceMigrateRequest{AvailabilityZone: "ru-1"}
1420+
expectedResp := &TaskResponse{Tasks: []string{taskID}}
1421+
URL := path.Join(instancesBasePathV1, strconv.Itoa(projectID), strconv.Itoa(regionID), testResourceID, instancesLiveMigration)
1422+
1423+
mux.HandleFunc(URL, func(w http.ResponseWriter, r *http.Request) {
1424+
testMethod(t, r, http.MethodPost)
1425+
resp, err := json.Marshal(expectedResp)
1426+
if err != nil {
1427+
t.Errorf("failed to marshal response: %v", err)
1428+
}
1429+
_, _ = fmt.Fprint(w, string(resp))
1430+
})
1431+
1432+
respActual, resp, err := client.Instances.Migrate(ctx, testResourceID, request)
1433+
require.NoError(t, err)
1434+
require.Equal(t, resp.StatusCode, 200)
1435+
assert.Equal(t, expectedResp, respActual)
1436+
}
1437+
1438+
func TestInstances_Migrate_ResponseError(t *testing.T) {
1439+
setup()
1440+
defer teardown()
1441+
1442+
request := &InstanceMigrateRequest{AvailabilityZone: "ru-1"}
1443+
1444+
URL := path.Join(instancesBasePathV1, strconv.Itoa(projectID), strconv.Itoa(regionID), testResourceID, instancesLiveMigration)
1445+
mux.HandleFunc(URL, func(w http.ResponseWriter, r *http.Request) {
1446+
testMethod(t, r, http.MethodPost)
1447+
w.WriteHeader(http.StatusBadRequest)
1448+
_, _ = fmt.Fprint(w, "Bad request")
1449+
})
1450+
1451+
respActual, resp, err := client.Instances.Migrate(ctx, testResourceID, request)
1452+
assert.Nil(t, respActual)
1453+
assert.Error(t, err)
1454+
assert.Equal(t, resp.StatusCode, 400)
1455+
}

0 commit comments

Comments
 (0)