Skip to content

Commit

Permalink
Added support for migrations field for Placement Groups (#617)
Browse files Browse the repository at this point in the history
* Added support for migrations field in PGs

* Added integration test
  • Loading branch information
ezilber-akamai authored Nov 18, 2024
1 parent 91c542c commit d7dbe30
Show file tree
Hide file tree
Showing 10 changed files with 1,586 additions and 7 deletions.
27 changes: 20 additions & 7 deletions placement_groups.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,26 @@ type PlacementGroupMember struct {

// PlacementGroup represents a Linode placement group.
type PlacementGroup struct {
ID int `json:"id"`
Label string `json:"label"`
Region string `json:"region"`
PlacementGroupType PlacementGroupType `json:"placement_group_type"`
PlacementGroupPolicy PlacementGroupPolicy `json:"placement_group_policy"`
IsCompliant bool `json:"is_compliant"`
Members []PlacementGroupMember `json:"members"`
ID int `json:"id"`
Label string `json:"label"`
Region string `json:"region"`
PlacementGroupType PlacementGroupType `json:"placement_group_type"`
PlacementGroupPolicy PlacementGroupPolicy `json:"placement_group_policy"`
IsCompliant bool `json:"is_compliant"`
Members []PlacementGroupMember `json:"members"`
Migrations PlacementGroupMigrations `json:"migrations"`
}

// PlacementGroupMigrations represent the instances that are being migrated to or from the placement group.
type PlacementGroupMigrations struct {
Inbound []struct {
// The unique identifier for a compute instance being migrated into the placement group.
LinodeID int `json:"linode_id"`
} `json:"inbound"`
Outbound []struct {
// The unique identifier for a compute instance being migrated out of the placement group.
LinodeID int `json:"linode_id"`
} `json:"outbound"`
}

// PlacementGroupCreateOptions represents the options to use
Expand Down
1,159 changes: 1,159 additions & 0 deletions test/integration/fixtures/TestInstance_MigrateToPG.yaml

Large diffs are not rendered by default.

103 changes: 103 additions & 0 deletions test/integration/instances_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,109 @@ func TestInstance_Migrate(t *testing.T) {
}
}

func TestInstance_MigrateToPG(t *testing.T) {
client, clientTeardown := createTestClient(t, "fixtures/TestInstance_MigrateToPG")

defer func() {
clientTeardown()
}()

regions := getRegionsWithCaps(t, client, []string{"Placement Group"})

pgOutboundCreateOpts := linodego.PlacementGroupCreateOptions{
Label: "linodego-test-" + getUniqueText(),
Region: regions[0],
PlacementGroupType: linodego.PlacementGroupTypeAntiAffinityLocal,
PlacementGroupPolicy: linodego.PlacementGroupPolicyFlexible,
}

pgOutbound, err := client.CreatePlacementGroup(context.Background(), pgOutboundCreateOpts)
if err != nil {
t.Fatalf("failed to create placement group: %s", err)
}

instanceCreateOpts := linodego.InstanceCreateOptions{
Label: "go-test-ins-" + randLabel(),
RootPass: randPassword(),
Region: regions[0],
Type: "g6-nanode-1",
Image: "linode/debian9",
Booted: linodego.Pointer(true),
PlacementGroup: &linodego.InstanceCreatePlacementGroupOptions{
ID: pgOutbound.ID,
},
}

instance, err := client.CreateInstance(context.Background(), instanceCreateOpts)
if err != nil {
t.Fatalf("failed to create instance: %s", err)
}

instance, err = client.WaitForInstanceStatus(
context.Background(),
instance.ID,
linodego.InstanceRunning,
180,
)
if err != nil {
t.Errorf("Error waiting for instance readiness for migration: %s", err.Error())
}

pgInboundCreateOpts := linodego.PlacementGroupCreateOptions{
Label: "linodego-test-" + getUniqueText(),
Region: regions[1],
PlacementGroupType: linodego.PlacementGroupTypeAntiAffinityLocal,
PlacementGroupPolicy: linodego.PlacementGroupPolicyFlexible,
}

pgInbound, err := client.CreatePlacementGroup(context.Background(), pgInboundCreateOpts)
if err != nil {
t.Fatalf("failed to create placement group: %s", err)
}

upgrade := false

err = client.MigrateInstance(
context.Background(),
instance.ID,
linodego.InstanceMigrateOptions{
Type: "cold",
Region: regions[1],
Upgrade: &upgrade,
PlacementGroup: &linodego.InstanceCreatePlacementGroupOptions{ID: pgInbound.ID},
},
)
if err != nil {
t.Errorf("failed to migrate instance %d: %v", instance.ID, err.Error())
}

pgInboundRefreshed, err := client.GetPlacementGroup(context.Background(), pgInbound.ID)
if err != nil {
t.Fatalf("failed to get placement group: %s", err)
}

pgOutboundRefreshed, err := client.GetPlacementGroup(context.Background(), pgOutbound.ID)
if err != nil {
t.Fatalf("failed to get placement group: %s", err)
}

require.Equal(t, pgInboundRefreshed.ID, pgInbound.ID)
require.Equal(t, pgInboundRefreshed.Migrations.Inbound[0].LinodeID, instance.ID)
require.Equal(t, pgOutboundRefreshed.Migrations.Outbound[0].LinodeID, instance.ID)

if err := client.DeleteInstance(context.Background(), instance.ID); err != nil {
t.Errorf("failed to delete instance: %s", err)
}

if err := client.DeletePlacementGroup(context.Background(), pgInboundRefreshed.ID); err != nil {
t.Errorf("failed to delete placement group: %s", err)
}

if err := client.DeletePlacementGroup(context.Background(), pgOutboundRefreshed.ID); err != nil {
t.Errorf("failed to delete placement group: %s", err)
}
}

func TestInstance_Disks_List(t *testing.T) {
client, instance, teardown, err := setupInstance(t, "fixtures/TestInstance_Disks_List", true)
defer teardown()
Expand Down
18 changes: 18 additions & 0 deletions test/unit/fixtures/placement_group_assign.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"id": 528,
"is_compliant": true,
"label": "PG_Miami_failover",
"members": [
{
"is_compliant": true,
"linode_id": 123
},
{
"is_compliant": true,
"linode_id": 456
}
],
"placement_group_policy": "strict",
"placement_group_type": "anti-affinity:local",
"region": "us-mia"
}
14 changes: 14 additions & 0 deletions test/unit/fixtures/placement_group_create.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"id": 528,
"is_compliant": true,
"label": "PG_Miami_failover",
"members": [
{
"is_compliant": true,
"linode_id": 123
}
],
"placement_group_policy": "strict",
"placement_group_type": "anti-affinity:local",
"region": "us-mia"
}
14 changes: 14 additions & 0 deletions test/unit/fixtures/placement_group_unassign.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"id": 528,
"is_compliant": true,
"label": "PG_Miami_failover",
"members": [
{
"is_compliant": true,
"linode_id": 123
}
],
"placement_group_policy": "strict",
"placement_group_type": "anti-affinity:local",
"region": "us-mia"
}
14 changes: 14 additions & 0 deletions test/unit/fixtures/placement_group_update.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"id": 528,
"is_compliant": true,
"label": "PG_Miami_failover_new",
"members": [
{
"is_compliant": true,
"linode_id": 123
}
],
"placement_group_policy": "strict",
"placement_group_type": "anti-affinity:local",
"region": "us-mia"
}
26 changes: 26 additions & 0 deletions test/unit/fixtures/placement_groups_get.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"id": 528,
"is_compliant": true,
"label": "PG_Miami_failover",
"members": [
{
"is_compliant": true,
"linode_id": 123
}
],
"migrations": {
"inbound": [
{
"linode_id": 123
}
],
"outbound": [
{
"linode_id": 456
}
]
},
"placement_group_policy": "strict",
"placement_group_type": "anti-affinity:local",
"region": "us-mia"
}
33 changes: 33 additions & 0 deletions test/unit/fixtures/placement_groups_list.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"data": [
{
"id": 528,
"is_compliant": true,
"label": "PG_Miami_failover",
"members": [
{
"is_compliant": true,
"linode_id": 123
}
],
"migrations": {
"inbound": [
{
"linode_id": 123
}
],
"outbound": [
{
"linode_id": 456
}
]
},
"placement_group_policy": "strict",
"placement_group_type": "anti-affinity:local",
"region": "us-mia"
}
],
"page": 1,
"pages": 1,
"results": 1
}
Loading

0 comments on commit d7dbe30

Please sign in to comment.