From 7ebeb19af4ccc85db9bd66126f81dd4efda8904e Mon Sep 17 00:00:00 2001 From: Lena Garber <114949949+lgarber-akamai@users.noreply.github.com> Date: Tue, 16 Apr 2024 10:24:03 -0400 Subject: [PATCH 1/6] new: Add support for VM Placement (#490) * Add placement group object * Add placement group limits to region response * Implement instance changes * prefixture * Add pg basic test * finish assignment tests * Add regions test * oops * make tidy --- instances.go | 75 ++- placement_groups.go | 152 ++++++ regions.go | 23 +- test/go.mod | 2 + .../fixtures/TestInstance_withPG.yaml | 360 +++++++++++++ .../TestPlacementGroup_assignment.yaml | 489 ++++++++++++++++++ .../fixtures/TestPlacementGroup_basic.yaml | 419 +++++++++++++++ .../fixtures/TestRegions_pgLimits.yaml | 120 +++++ test/integration/instances_test.go | 30 ++ test/integration/placement_group_test.go | 145 ++++++ test/integration/regions_test.go | 24 + 11 files changed, 1805 insertions(+), 34 deletions(-) create mode 100644 placement_groups.go create mode 100644 test/integration/fixtures/TestInstance_withPG.yaml create mode 100644 test/integration/fixtures/TestPlacementGroup_assignment.yaml create mode 100644 test/integration/fixtures/TestPlacementGroup_basic.yaml create mode 100644 test/integration/fixtures/TestRegions_pgLimits.yaml create mode 100644 test/integration/placement_group_test.go diff --git a/instances.go b/instances.go index a56c3321b..9122478cd 100644 --- a/instances.go +++ b/instances.go @@ -43,25 +43,26 @@ const ( // Instance represents a linode object type Instance struct { - ID int `json:"id"` - Created *time.Time `json:"-"` - Updated *time.Time `json:"-"` - Region string `json:"region"` - Alerts *InstanceAlert `json:"alerts"` - Backups *InstanceBackup `json:"backups"` - Image string `json:"image"` - Group string `json:"group"` - IPv4 []*net.IP `json:"ipv4"` - IPv6 string `json:"ipv6"` - Label string `json:"label"` - Type string `json:"type"` - Status InstanceStatus `json:"status"` - HasUserData bool `json:"has_user_data"` - Hypervisor string `json:"hypervisor"` - HostUUID string `json:"host_uuid"` - Specs *InstanceSpec `json:"specs"` - WatchdogEnabled bool `json:"watchdog_enabled"` - Tags []string `json:"tags"` + ID int `json:"id"` + Created *time.Time `json:"-"` + Updated *time.Time `json:"-"` + Region string `json:"region"` + Alerts *InstanceAlert `json:"alerts"` + Backups *InstanceBackup `json:"backups"` + Image string `json:"image"` + Group string `json:"group"` + IPv4 []*net.IP `json:"ipv4"` + IPv6 string `json:"ipv6"` + Label string `json:"label"` + Type string `json:"type"` + Status InstanceStatus `json:"status"` + HasUserData bool `json:"has_user_data"` + Hypervisor string `json:"hypervisor"` + HostUUID string `json:"host_uuid"` + Specs *InstanceSpec `json:"specs"` + WatchdogEnabled bool `json:"watchdog_enabled"` + Tags []string `json:"tags"` + PlacementGroup *InstancePlacementGroup `json:"placement_group"` } // InstanceSpec represents a linode spec @@ -104,6 +105,15 @@ type InstanceTransfer struct { Quota int `json:"quota"` } +// InstancePlacementGroup represents information about the placement group +// this Linode is a part of. +type InstancePlacementGroup struct { + ID int `json:"id"` + Label string `json:"label"` + AffinityType PlacementGroupAffinityType `json:"affinity_type"` + IsStrict bool `json:"is_strict"` +} + // InstanceMetadataOptions specifies various Instance creation fields // that relate to the Linode Metadata service. type InstanceMetadataOptions struct { @@ -129,6 +139,7 @@ type InstanceCreateOptions struct { Tags []string `json:"tags,omitempty"` Metadata *InstanceMetadataOptions `json:"metadata,omitempty"` FirewallID int `json:"firewall_id,omitempty"` + PlacementGroup *InstanceCreatePlacementGroupOptions `json:"placement_group,omitempty"` // Creation fields that need to be set explicitly false, "", or 0 use pointers SwapSize *int `json:"swap_size,omitempty"` @@ -138,6 +149,13 @@ type InstanceCreateOptions struct { Group string `json:"group,omitempty"` } +// InstanceCreatePlacementGroupOptions represents the placement group +// to create this Linode under. +type InstanceCreatePlacementGroupOptions struct { + ID int `json:"id"` + CompliantOnly *bool `json:"compliant_only,omitempty"` +} + // InstanceUpdateOptions is an options struct used when Updating an Instance type InstanceUpdateOptions struct { Label string `json:"label,omitempty"` @@ -190,13 +208,14 @@ type InstanceCloneOptions struct { Type string `json:"type,omitempty"` // LinodeID is an optional existing instance to use as the target of the clone - LinodeID int `json:"linode_id,omitempty"` - Label string `json:"label,omitempty"` - BackupsEnabled bool `json:"backups_enabled"` - Disks []int `json:"disks,omitempty"` - Configs []int `json:"configs,omitempty"` - PrivateIP bool `json:"private_ip,omitempty"` - Metadata *InstanceMetadataOptions `json:"metadata,omitempty"` + LinodeID int `json:"linode_id,omitempty"` + Label string `json:"label,omitempty"` + BackupsEnabled bool `json:"backups_enabled"` + Disks []int `json:"disks,omitempty"` + Configs []int `json:"configs,omitempty"` + PrivateIP bool `json:"private_ip,omitempty"` + Metadata *InstanceMetadataOptions `json:"metadata,omitempty"` + PlacementGroup *InstanceCreatePlacementGroupOptions `json:"placement_group,omitempty"` // Deprecated: group is a deprecated property denoting a group label for the Linode. Group string `json:"group,omitempty"` @@ -211,10 +230,12 @@ type InstanceResizeOptions struct { AllowAutoDiskResize *bool `json:"allow_auto_disk_resize,omitempty"` } -// InstanceResizeOptions is an options struct used when resizing an instance +// InstanceMigrateOptions is an options struct used when migrating an instance type InstanceMigrateOptions struct { Type InstanceMigrationType `json:"type,omitempty"` Region string `json:"region,omitempty"` + + PlacementGroup *InstanceCreatePlacementGroupOptions `json:"placement_group,omitempty"` } // InstancesPagedResponse represents a linode API response for listing diff --git a/placement_groups.go b/placement_groups.go new file mode 100644 index 000000000..08286bbb0 --- /dev/null +++ b/placement_groups.go @@ -0,0 +1,152 @@ +package linodego + +import "context" + +// PlacementGroupAffinityType is an enum that determines the affinity policy +// for Linodes in a placement group. +type PlacementGroupAffinityType string + +const ( + AffinityTypeAntiAffinityLocal PlacementGroupAffinityType = "anti_affinity:local" +) + +// PlacementGroupMember represents a single Linode assigned to a +// placement group. +type PlacementGroupMember struct { + LinodeID int `json:"linode_id"` + IsCompliant bool `json:"is_compliant"` +} + +// PlacementGroup represents a Linode placement group. +type PlacementGroup struct { + ID int `json:"id"` + Label string `json:"label"` + Region string `json:"region"` + AffinityType PlacementGroupAffinityType `json:"affinity_type"` + IsCompliant bool `json:"is_compliant"` + IsStrict bool `json:"is_strict"` + Members []PlacementGroupMember `json:"members"` +} + +// PlacementGroupCreateOptions represents the options to use +// when creating a placement group. +type PlacementGroupCreateOptions struct { + Label string `json:"label"` + Region string `json:"region"` + AffinityType PlacementGroupAffinityType `json:"affinity_type"` + IsStrict bool `json:"is_strict"` +} + +// PlacementGroupUpdateOptions represents the options to use +// when updating a placement group. +type PlacementGroupUpdateOptions struct { + Label string `json:"label,omitempty"` +} + +// PlacementGroupAssignOptions represents options used when +// assigning Linodes to a placement group. +type PlacementGroupAssignOptions struct { + Linodes []int `json:"linodes"` + CompliantOnly *bool `json:"compliant_only,omitempty"` +} + +// PlacementGroupUnAssignOptions represents options used when +// unassigning Linodes from a placement group. +type PlacementGroupUnAssignOptions struct { + Linodes []int `json:"linodes"` +} + +// ListPlacementGroups lists placement groups under the current account +// matching the given list options. +func (c *Client) ListPlacementGroups( + ctx context.Context, + options *ListOptions, +) ([]PlacementGroup, error) { + return getPaginatedResults[PlacementGroup]( + ctx, + c, + "placement/groups", + options, + ) +} + +// GetPlacementGroup gets a placement group with the specified ID. +func (c *Client) GetPlacementGroup( + ctx context.Context, + id int, +) (*PlacementGroup, error) { + return doGETRequest[PlacementGroup]( + ctx, + c, + formatAPIPath("placement/groups/%d", id), + ) +} + +// CreatePlacementGroup creates a placement group with the specified options. +func (c *Client) CreatePlacementGroup( + ctx context.Context, + options PlacementGroupCreateOptions, +) (*PlacementGroup, error) { + return doPOSTRequest[PlacementGroup]( + ctx, + c, + "placement/groups", + options, + ) +} + +// UpdatePlacementGroup updates a placement group with the specified ID using the provided options. +func (c *Client) UpdatePlacementGroup( + ctx context.Context, + id int, + options PlacementGroupUpdateOptions, +) (*PlacementGroup, error) { + return doPUTRequest[PlacementGroup]( + ctx, + c, + formatAPIPath("placement/groups/%d", id), + options, + ) +} + +// AssignPlacementGroupLinodes assigns the specified Linodes to the given +// placement group. +func (c *Client) AssignPlacementGroupLinodes( + ctx context.Context, + id int, + options PlacementGroupAssignOptions, +) (*PlacementGroup, error) { + return doPOSTRequest[PlacementGroup]( + ctx, + c, + formatAPIPath("placement/groups/%d/assign", id), + options, + ) +} + +// UnAssignPlacementGroupLinodes un-assigns the specified Linodes from the given +// placement group. +func (c *Client) UnAssignPlacementGroupLinodes( + ctx context.Context, + id int, + options PlacementGroupUnAssignOptions, +) (*PlacementGroup, error) { + return doPOSTRequest[PlacementGroup]( + ctx, + c, + formatAPIPath("placement/groups/%d/unassign", id), + options, + ) +} + +// DeletePlacementGroup deletes a placement group with the specified ID. +func (c *Client) DeletePlacementGroup( + ctx context.Context, + id int, +) error { + return doDELETERequest( + ctx, + c, + formatAPIPath("placement/groups/%d", id), + ) +} diff --git a/regions.go b/regions.go index 3b0caf8a5..1564669f4 100644 --- a/regions.go +++ b/regions.go @@ -15,13 +15,15 @@ var cacheExpiryTime = time.Minute // Region represents a linode region object type Region struct { - ID string `json:"id"` - Country string `json:"country"` - Capabilities []string `json:"capabilities"` - Status string `json:"status"` - Resolvers RegionResolvers `json:"resolvers"` - Label string `json:"label"` - SiteType string `json:"site_type"` + ID string `json:"id"` + Country string `json:"country"` + Capabilities []string `json:"capabilities"` + Status string `json:"status"` + Label string `json:"label"` + SiteType string `json:"site_type"` + + Resolvers RegionResolvers `json:"resolvers"` + PlacementGroupLimits *RegionPlacementGroupLimits `json:"placement_group_limits"` } // RegionResolvers contains the DNS resolvers of a region @@ -30,6 +32,13 @@ type RegionResolvers struct { IPv6 string `json:"ipv6"` } +// RegionPlacementGroupLimits contains information about the +// placement group limits for the current user in the current region. +type RegionPlacementGroupLimits struct { + MaximumPGsPerCustomer int `json:"maximum_pgs_per_customer"` + MaximumLinodesPerPG int `json:"maximum_linodes_per_pg"` +} + // RegionsPagedResponse represents a linode API response for listing type RegionsPagedResponse struct { *PageOptions diff --git a/test/go.mod b/test/go.mod index 14ee41906..be2c84654 100644 --- a/test/go.mod +++ b/test/go.mod @@ -6,6 +6,7 @@ require ( github.com/jarcoal/httpmock v1.3.1 github.com/linode/linodego v1.30.0 github.com/linode/linodego/k8s v0.0.0-00010101000000-000000000000 + github.com/stretchr/testify v1.9.0 golang.org/x/net v0.24.0 golang.org/x/oauth2 v0.19.0 k8s.io/client-go v0.28.8 @@ -31,6 +32,7 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect github.com/spf13/pflag v1.0.5 // indirect golang.org/x/sys v0.19.0 // indirect golang.org/x/term v0.19.0 // indirect diff --git a/test/integration/fixtures/TestInstance_withPG.yaml b/test/integration/fixtures/TestInstance_withPG.yaml new file mode 100644 index 000000000..455bf7d85 --- /dev/null +++ b/test/integration/fixtures/TestInstance_withPG.yaml @@ -0,0 +1,360 @@ +--- +version: 1 +interactions: +- request: + body: "" + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - linodego/dev https://github.com/linode/linodego + url: https://api.linode.com/v4beta/regions + method: GET + response: + body: '{"data": [{"id": "ap-west", "label": "Mumbai, India", "country": "in", + "capabilities": ["Linodes", "Backups", "NodeBalancers", "Vlans", "VPCs", "Managed + Databases"], "status": "ok", "resolvers": {"ipv4": "172.105.34.5,172.105.35.5,172.105.36.5,172.105.37.5,172.105.38.5,172.105.39.5,172.105.40.5,172.105.41.5,172.105.42.5,172.105.43.5", + "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, + "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "ca-central", "label": "Toronto, Ontario, CAN", + "country": "ca", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Vlans", + "VPCs", "Managed Databases"], "status": "ok", "resolvers": {"ipv4": "172.105.0.5,172.105.3.5,172.105.4.5,172.105.5.5,172.105.6.5,172.105.7.5,172.105.8.5,172.105.9.5,172.105.10.5,172.105.11.5", + "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, + "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "ap-southeast", "label": "Sydney, NSW, Australia", + "country": "au", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Vlans", + "VPCs", "Managed Databases"], "status": "ok", "resolvers": {"ipv4": "172.105.166.5,172.105.169.5,172.105.168.5,172.105.172.5,172.105.162.5,172.105.170.5,172.105.167.5,172.105.171.5,172.105.181.5,172.105.161.5", + "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, + "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "us-central", "label": "Dallas, TX, USA", "country": + "us", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Kubernetes", + "Managed Databases"], "status": "ok", "resolvers": {"ipv4": "72.14.179.5,72.14.188.5,173.255.199.5,66.228.53.5,96.126.122.5,96.126.124.5,96.126.127.5,198.58.107.5,198.58.111.5,23.239.24.5", + "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, + "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "us-west", "label": "Fremont, CA, USA", "country": + "us", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Managed Databases"], + "status": "ok", "resolvers": {"ipv4": "173.230.145.5,173.230.147.5,173.230.155.5,173.255.212.5,173.255.219.5,173.255.241.5,173.255.243.5,173.255.244.5,74.207.241.5,74.207.242.5", + "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, + "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "us-southeast", "label": "Atlanta, GA, USA", + "country": "us", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Managed + Databases"], "status": "ok", "resolvers": {"ipv4": "74.207.231.5,173.230.128.5,173.230.129.5,173.230.136.5,173.230.140.5,66.228.59.5,66.228.62.5,50.116.35.5,50.116.41.5,23.239.18.5", + "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, + "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "us-east", "label": "Newark, NJ, USA", "country": + "us", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Block Storage", + "Object Storage", "GPU Linodes", "Kubernetes", "Cloud Firewall", "Bare Metal", + "Vlans", "VPCs", "Block Storage Migrations", "Managed Databases", "Metadata"], + "status": "ok", "resolvers": {"ipv4": "66.228.42.5,96.126.106.5,50.116.53.5,50.116.58.5,50.116.61.5,50.116.62.5,66.175.211.5,97.107.133.4,207.192.69.4,207.192.69.5", + "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, + "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "eu-west", "label": "London, England, UK", + "country": "uk", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Cloud + Firewall", "Vlans", "VPCs", "Managed Databases", "Metadata", "Placement Group"], + "status": "ok", "resolvers": {"ipv4": "178.79.182.5,176.58.107.5,176.58.116.5,176.58.121.5,151.236.220.5,212.71.252.5,212.71.253.5,109.74.192.20,109.74.193.20,109.74.194.20", + "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, + "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "ap-south", "label": "Singapore, SG", "country": + "sg", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Object Storage", + "Managed Databases"], "status": "ok", "resolvers": {"ipv4": "139.162.11.5,139.162.13.5,139.162.14.5,139.162.15.5,139.162.16.5,139.162.21.5,139.162.27.5,103.3.60.18,103.3.60.19,103.3.60.20", + "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, + "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "eu-central", "label": "Frankfurt, DE", "country": + "de", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Object Storage", + "Managed Databases"], "status": "ok", "resolvers": {"ipv4": "139.162.130.5,139.162.131.5,139.162.132.5,139.162.133.5,139.162.134.5,139.162.135.5,139.162.136.5,139.162.137.5,139.162.138.5,139.162.139.5", + "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, + "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "ap-northeast", "label": "Tokyo 2, JP", "country": + "jp", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Managed Databases"], + "status": "ok", "resolvers": {"ipv4": "139.162.66.5,139.162.67.5,139.162.68.5,139.162.69.5,139.162.70.5,139.162.71.5,139.162.72.5,139.162.73.5,139.162.74.5,139.162.75.5", + "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, + "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + 5}, "site_type": "core"}], "page": 1, "pages": 1, "results": 11}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=900 + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "7144" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - '*' + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: '{"label":"linodego-test-1712862693761548000","region":"eu-west","affinity_type":"anti_affinity:local","is_strict":false}' + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - linodego/dev https://github.com/linode/linodego + url: https://api.linode.com/v4beta/placement/groups + method: POST + response: + body: '{"id": 356, "label": "linodego-test-1712862693761548000", "region": "eu-west", + "affinity_type": "anti_affinity:local", "is_strict": false, "is_compliant": + true, "members": []}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "175" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: '{"region":"eu-west","type":"g6-nanode-1","label":"go-test-ins-g14gx0ib8h49","root_pass":"h4#|k51Ic\u003cdoX\u00262W59A!fF8N.|}n:5}Yt=s\u003e0yJ\\D/6M8gc/~6PHGYG09nEd4kh5","image":"linode/debian9","placement_group":{"id":356},"booted":false}' + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - linodego/dev https://github.com/linode/linodego + url: https://api.linode.com/v4beta/linode/instances + method: POST + response: + body: '{"id": 25124077, "label": "go-test-ins-g14gx0ib8h49", "group": "", "status": + "provisioning", "created": "2018-01-02T03:04:05", "updated": "2018-01-02T03:04:05", + "type": "g6-nanode-1", "ipv4": ["139.144.245.159"], "ipv6": "1234::5678/128", + "image": "linode/debian9", "region": "eu-west", "specs": {"disk": 25600, "memory": + 1024, "vcpus": 1, "gpus": 0, "transfer": 1000}, "alerts": {"cpu": 90, "network_in": + 10, "network_out": 10, "transfer_quota": 80, "io": 10000}, "backups": {"enabled": + false, "available": false, "schedule": {"day": null, "window": null}, "last_successful": + null}, "hypervisor": "kvm", "watchdog_enabled": true, "tags": [], "host_uuid": + "e7dea8a2851fa88da8866ef434a553491200ea8c", "has_user_data": false, "placement_group": + {"id": 356, "label": "linodego-test-1712862693761548000", "affinity_type": "anti_affinity:local", + "is_strict": false}}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "881" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "10" + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - linodego/dev https://github.com/linode/linodego + url: https://api.linode.com/v4beta/linode/instances/25124077 + method: DELETE + response: + body: '{}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "2" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - linodego/dev https://github.com/linode/linodego + url: https://api.linode.com/v4beta/placement/groups/356 + method: DELETE + response: + body: '{}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "2" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" diff --git a/test/integration/fixtures/TestPlacementGroup_assignment.yaml b/test/integration/fixtures/TestPlacementGroup_assignment.yaml new file mode 100644 index 000000000..74449d2c2 --- /dev/null +++ b/test/integration/fixtures/TestPlacementGroup_assignment.yaml @@ -0,0 +1,489 @@ +--- +version: 1 +interactions: +- request: + body: "" + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - linodego/dev https://github.com/linode/linodego + url: https://api.linode.com/v4beta/regions + method: GET + response: + body: '{"data": [{"id": "ap-west", "label": "Mumbai, India", "country": "in", + "capabilities": ["Linodes", "Backups", "NodeBalancers", "Vlans", "VPCs", "Managed + Databases"], "status": "ok", "resolvers": {"ipv4": "172.105.34.5,172.105.35.5,172.105.36.5,172.105.37.5,172.105.38.5,172.105.39.5,172.105.40.5,172.105.41.5,172.105.42.5,172.105.43.5", + "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, + "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "ca-central", "label": "Toronto, Ontario, CAN", + "country": "ca", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Vlans", + "VPCs", "Managed Databases"], "status": "ok", "resolvers": {"ipv4": "172.105.0.5,172.105.3.5,172.105.4.5,172.105.5.5,172.105.6.5,172.105.7.5,172.105.8.5,172.105.9.5,172.105.10.5,172.105.11.5", + "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, + "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "ap-southeast", "label": "Sydney, NSW, Australia", + "country": "au", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Vlans", + "VPCs", "Managed Databases"], "status": "ok", "resolvers": {"ipv4": "172.105.166.5,172.105.169.5,172.105.168.5,172.105.172.5,172.105.162.5,172.105.170.5,172.105.167.5,172.105.171.5,172.105.181.5,172.105.161.5", + "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, + "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "us-central", "label": "Dallas, TX, USA", "country": + "us", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Kubernetes", + "Managed Databases"], "status": "ok", "resolvers": {"ipv4": "72.14.179.5,72.14.188.5,173.255.199.5,66.228.53.5,96.126.122.5,96.126.124.5,96.126.127.5,198.58.107.5,198.58.111.5,23.239.24.5", + "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, + "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "us-west", "label": "Fremont, CA, USA", "country": + "us", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Managed Databases"], + "status": "ok", "resolvers": {"ipv4": "173.230.145.5,173.230.147.5,173.230.155.5,173.255.212.5,173.255.219.5,173.255.241.5,173.255.243.5,173.255.244.5,74.207.241.5,74.207.242.5", + "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, + "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "us-southeast", "label": "Atlanta, GA, USA", + "country": "us", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Managed + Databases"], "status": "ok", "resolvers": {"ipv4": "74.207.231.5,173.230.128.5,173.230.129.5,173.230.136.5,173.230.140.5,66.228.59.5,66.228.62.5,50.116.35.5,50.116.41.5,23.239.18.5", + "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, + "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "us-east", "label": "Newark, NJ, USA", "country": + "us", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Block Storage", + "Object Storage", "GPU Linodes", "Kubernetes", "Cloud Firewall", "Bare Metal", + "Vlans", "VPCs", "Block Storage Migrations", "Managed Databases", "Metadata"], + "status": "ok", "resolvers": {"ipv4": "66.228.42.5,96.126.106.5,50.116.53.5,50.116.58.5,50.116.61.5,50.116.62.5,66.175.211.5,97.107.133.4,207.192.69.4,207.192.69.5", + "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, + "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "eu-west", "label": "London, England, UK", + "country": "uk", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Cloud + Firewall", "Vlans", "VPCs", "Managed Databases", "Metadata", "Placement Group"], + "status": "ok", "resolvers": {"ipv4": "178.79.182.5,176.58.107.5,176.58.116.5,176.58.121.5,151.236.220.5,212.71.252.5,212.71.253.5,109.74.192.20,109.74.193.20,109.74.194.20", + "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, + "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "ap-south", "label": "Singapore, SG", "country": + "sg", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Object Storage", + "Managed Databases"], "status": "ok", "resolvers": {"ipv4": "139.162.11.5,139.162.13.5,139.162.14.5,139.162.15.5,139.162.16.5,139.162.21.5,139.162.27.5,103.3.60.18,103.3.60.19,103.3.60.20", + "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, + "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "eu-central", "label": "Frankfurt, DE", "country": + "de", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Object Storage", + "Managed Databases"], "status": "ok", "resolvers": {"ipv4": "139.162.130.5,139.162.131.5,139.162.132.5,139.162.133.5,139.162.134.5,139.162.135.5,139.162.136.5,139.162.137.5,139.162.138.5,139.162.139.5", + "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, + "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "ap-northeast", "label": "Tokyo 2, JP", "country": + "jp", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Managed Databases"], + "status": "ok", "resolvers": {"ipv4": "139.162.66.5,139.162.67.5,139.162.68.5,139.162.69.5,139.162.70.5,139.162.71.5,139.162.72.5,139.162.73.5,139.162.74.5,139.162.75.5", + "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, + "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + 5}, "site_type": "core"}], "page": 1, "pages": 1, "results": 11}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=900 + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "7144" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - '*' + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: '{"label":"linodego-test-1712862497480882000","region":"eu-west","affinity_type":"anti_affinity:local","is_strict":false}' + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - linodego/dev https://github.com/linode/linodego + url: https://api.linode.com/v4beta/placement/groups + method: POST + response: + body: '{"id": 355, "label": "linodego-test-1712862497480882000", "region": "eu-west", + "affinity_type": "anti_affinity:local", "is_strict": false, "is_compliant": + true, "members": []}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "175" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: '{"region":"eu-west","type":"g6-nanode-1","label":"go-test-ins-z63p4b2z8w8t","root_pass":"$j?W`mM=o6$2026T7;\u003e`Dr*X+XR81FCwIX8crCl7nma]7i=@\u0026riC4FN8146\u003eQv\u003ey","image":"linode/debian9","booted":false}' + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - linodego/dev https://github.com/linode/linodego + url: https://api.linode.com/v4beta/linode/instances + method: POST + response: + body: '{"id": 25124076, "label": "go-test-ins-z63p4b2z8w8t", "group": "", "status": + "provisioning", "created": "2018-01-02T03:04:05", "updated": "2018-01-02T03:04:05", + "type": "g6-nanode-1", "ipv4": ["139.144.245.158"], "ipv6": "1234::5678/128", + "image": "linode/debian9", "region": "eu-west", "specs": {"disk": 25600, "memory": + 1024, "vcpus": 1, "gpus": 0, "transfer": 1000}, "alerts": {"cpu": 90, "network_in": + 10, "network_out": 10, "transfer_quota": 80, "io": 10000}, "backups": {"enabled": + false, "available": false, "schedule": {"day": null, "window": null}, "last_successful": + null}, "hypervisor": "kvm", "watchdog_enabled": true, "tags": [], "host_uuid": + "e7dea8a2851fa88da8866ef434a553491200ea8c", "has_user_data": false, "placement_group": + null}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "768" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "10" + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: '{"linodes":[25124076]}' + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - linodego/dev https://github.com/linode/linodego + url: https://api.linode.com/v4beta/placement/groups/355/assign + method: POST + response: + body: '{"id": 355, "label": "linodego-test-1712862497480882000", "region": "eu-west", + "affinity_type": "anti_affinity:local", "is_strict": false, "is_compliant": + true, "members": [{"linode_id": 25124076, "is_compliant": true}]}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "220" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - linodego/dev https://github.com/linode/linodego + url: https://api.linode.com/v4beta/linode/instances/25124076 + method: GET + response: + body: '{"id": 25124076, "label": "go-test-ins-z63p4b2z8w8t", "group": "", "status": + "provisioning", "created": "2018-01-02T03:04:05", "updated": "2018-01-02T03:04:05", + "type": "g6-nanode-1", "ipv4": ["139.144.245.158"], "ipv6": "1234::5678/128", + "image": "linode/debian9", "region": "eu-west", "specs": {"disk": 25600, "memory": + 1024, "vcpus": 1, "gpus": 0, "transfer": 1000}, "alerts": {"cpu": 90, "network_in": + 10, "network_out": 10, "transfer_quota": 80, "io": 10000}, "backups": {"enabled": + false, "available": false, "schedule": {"day": null, "window": null}, "last_successful": + null}, "hypervisor": "kvm", "watchdog_enabled": true, "tags": [], "host_uuid": + "e7dea8a2851fa88da8866ef434a553491200ea8c", "has_user_data": false, "placement_group": + {"id": 355, "label": "linodego-test-1712862497480882000", "affinity_type": "anti_affinity:local", + "is_strict": false}}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=0, s-maxage=0, no-cache, no-store + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "881" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - linodes:read_only + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: '{"linodes":[25124076]}' + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - linodego/dev https://github.com/linode/linodego + url: https://api.linode.com/v4beta/placement/groups/355/unassign + method: POST + response: + body: '{"id": 355, "label": "linodego-test-1712862497480882000", "region": "eu-west", + "affinity_type": "anti_affinity:local", "is_strict": false, "is_compliant": + true, "members": []}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "175" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - linodego/dev https://github.com/linode/linodego + url: https://api.linode.com/v4beta/placement/groups/355 + method: DELETE + response: + body: '{}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "2" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" diff --git a/test/integration/fixtures/TestPlacementGroup_basic.yaml b/test/integration/fixtures/TestPlacementGroup_basic.yaml new file mode 100644 index 000000000..28a50ca90 --- /dev/null +++ b/test/integration/fixtures/TestPlacementGroup_basic.yaml @@ -0,0 +1,419 @@ +--- +version: 1 +interactions: +- request: + body: "" + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - linodego/dev https://github.com/linode/linodego + url: https://api.linode.com/v4beta/regions + method: GET + response: + body: '{"data": [{"id": "ap-west", "label": "Mumbai, India", "country": "in", + "capabilities": ["Linodes", "Backups", "NodeBalancers", "Vlans", "VPCs", "Managed + Databases"], "status": "ok", "resolvers": {"ipv4": "172.105.34.5,172.105.35.5,172.105.36.5,172.105.37.5,172.105.38.5,172.105.39.5,172.105.40.5,172.105.41.5,172.105.42.5,172.105.43.5", + "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, + "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "ca-central", "label": "Toronto, Ontario, CAN", + "country": "ca", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Vlans", + "VPCs", "Managed Databases"], "status": "ok", "resolvers": {"ipv4": "172.105.0.5,172.105.3.5,172.105.4.5,172.105.5.5,172.105.6.5,172.105.7.5,172.105.8.5,172.105.9.5,172.105.10.5,172.105.11.5", + "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, + "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "ap-southeast", "label": "Sydney, NSW, Australia", + "country": "au", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Vlans", + "VPCs", "Managed Databases"], "status": "ok", "resolvers": {"ipv4": "172.105.166.5,172.105.169.5,172.105.168.5,172.105.172.5,172.105.162.5,172.105.170.5,172.105.167.5,172.105.171.5,172.105.181.5,172.105.161.5", + "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, + "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "us-central", "label": "Dallas, TX, USA", "country": + "us", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Kubernetes", + "Managed Databases"], "status": "ok", "resolvers": {"ipv4": "72.14.179.5,72.14.188.5,173.255.199.5,66.228.53.5,96.126.122.5,96.126.124.5,96.126.127.5,198.58.107.5,198.58.111.5,23.239.24.5", + "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, + "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "us-west", "label": "Fremont, CA, USA", "country": + "us", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Managed Databases"], + "status": "ok", "resolvers": {"ipv4": "173.230.145.5,173.230.147.5,173.230.155.5,173.255.212.5,173.255.219.5,173.255.241.5,173.255.243.5,173.255.244.5,74.207.241.5,74.207.242.5", + "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, + "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "us-southeast", "label": "Atlanta, GA, USA", + "country": "us", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Managed + Databases"], "status": "ok", "resolvers": {"ipv4": "74.207.231.5,173.230.128.5,173.230.129.5,173.230.136.5,173.230.140.5,66.228.59.5,66.228.62.5,50.116.35.5,50.116.41.5,23.239.18.5", + "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, + "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "us-east", "label": "Newark, NJ, USA", "country": + "us", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Block Storage", + "Object Storage", "GPU Linodes", "Kubernetes", "Cloud Firewall", "Bare Metal", + "Vlans", "VPCs", "Block Storage Migrations", "Managed Databases", "Metadata"], + "status": "ok", "resolvers": {"ipv4": "66.228.42.5,96.126.106.5,50.116.53.5,50.116.58.5,50.116.61.5,50.116.62.5,66.175.211.5,97.107.133.4,207.192.69.4,207.192.69.5", + "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, + "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "eu-west", "label": "London, England, UK", + "country": "uk", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Cloud + Firewall", "Vlans", "VPCs", "Managed Databases", "Metadata", "Placement Group"], + "status": "ok", "resolvers": {"ipv4": "178.79.182.5,176.58.107.5,176.58.116.5,176.58.121.5,151.236.220.5,212.71.252.5,212.71.253.5,109.74.192.20,109.74.193.20,109.74.194.20", + "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, + "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "ap-south", "label": "Singapore, SG", "country": + "sg", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Object Storage", + "Managed Databases"], "status": "ok", "resolvers": {"ipv4": "139.162.11.5,139.162.13.5,139.162.14.5,139.162.15.5,139.162.16.5,139.162.21.5,139.162.27.5,103.3.60.18,103.3.60.19,103.3.60.20", + "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, + "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "eu-central", "label": "Frankfurt, DE", "country": + "de", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Object Storage", + "Managed Databases"], "status": "ok", "resolvers": {"ipv4": "139.162.130.5,139.162.131.5,139.162.132.5,139.162.133.5,139.162.134.5,139.162.135.5,139.162.136.5,139.162.137.5,139.162.138.5,139.162.139.5", + "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, + "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "ap-northeast", "label": "Tokyo 2, JP", "country": + "jp", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Managed Databases"], + "status": "ok", "resolvers": {"ipv4": "139.162.66.5,139.162.67.5,139.162.68.5,139.162.69.5,139.162.70.5,139.162.71.5,139.162.72.5,139.162.73.5,139.162.74.5,139.162.75.5", + "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, + "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + 5}, "site_type": "core"}], "page": 1, "pages": 1, "results": 11}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=900 + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "7144" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - '*' + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: '{"label":"linodego-test-1712862362503240000","region":"eu-west","affinity_type":"anti_affinity:local","is_strict":false}' + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - linodego/dev https://github.com/linode/linodego + url: https://api.linode.com/v4beta/placement/groups + method: POST + response: + body: '{"id": 351, "label": "linodego-test-1712862362503240000", "region": "eu-west", + "affinity_type": "anti_affinity:local", "is_strict": false, "is_compliant": + true, "members": []}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "175" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: '{"label":"linodego-test-1712862362503240000-updated"}' + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - linodego/dev https://github.com/linode/linodego + url: https://api.linode.com/v4beta/placement/groups/351 + method: PUT + response: + body: '{"id": 351, "label": "linodego-test-1712862362503240000-updated", "region": + "eu-west", "affinity_type": "anti_affinity:local", "is_strict": false, "is_compliant": + true, "members": []}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "183" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - linodego/dev https://github.com/linode/linodego + url: https://api.linode.com/v4beta/placement/groups/351 + method: GET + response: + body: '{"id": 351, "label": "linodego-test-1712862362503240000-updated", "region": + "eu-west", "affinity_type": "anti_affinity:local", "is_strict": false, "is_compliant": + true, "members": []}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=0, s-maxage=0, no-cache, no-store + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "183" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - linodes:read_only + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - linodego/dev https://github.com/linode/linodego + X-Filter: + - '{"id": 351}' + url: https://api.linode.com/v4beta/placement/groups?page=1 + method: GET + response: + body: '{"data": [{"id": 351, "label": "linodego-test-1712862362503240000-updated", + "region": "eu-west", "affinity_type": "anti_affinity:local", "is_strict": false, + "is_compliant": true, "members": []}], "page": 1, "pages": 1, "results": 1}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=0, s-maxage=0, no-cache, no-store + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "232" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - linodes:read_only + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - linodego/dev https://github.com/linode/linodego + url: https://api.linode.com/v4beta/placement/groups/351 + method: DELETE + response: + body: '{}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "2" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" diff --git a/test/integration/fixtures/TestRegions_pgLimits.yaml b/test/integration/fixtures/TestRegions_pgLimits.yaml new file mode 100644 index 000000000..d238f4085 --- /dev/null +++ b/test/integration/fixtures/TestRegions_pgLimits.yaml @@ -0,0 +1,120 @@ +--- +version: 1 +interactions: +- request: + body: "" + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - linodego/dev https://github.com/linode/linodego + url: https://api.linode.com/v4beta/regions + method: GET + response: + body: '{"data": [{"id": "ap-west", "label": "Mumbai, India", "country": "in", + "capabilities": ["Linodes", "Backups", "NodeBalancers", "Vlans", "VPCs", "Managed + Databases"], "status": "ok", "resolvers": {"ipv4": "172.105.34.5,172.105.35.5,172.105.36.5,172.105.37.5,172.105.38.5,172.105.39.5,172.105.40.5,172.105.41.5,172.105.42.5,172.105.43.5", + "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, + "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "ca-central", "label": "Toronto, Ontario, CAN", + "country": "ca", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Vlans", + "VPCs", "Managed Databases"], "status": "ok", "resolvers": {"ipv4": "172.105.0.5,172.105.3.5,172.105.4.5,172.105.5.5,172.105.6.5,172.105.7.5,172.105.8.5,172.105.9.5,172.105.10.5,172.105.11.5", + "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, + "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "ap-southeast", "label": "Sydney, NSW, Australia", + "country": "au", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Vlans", + "VPCs", "Managed Databases"], "status": "ok", "resolvers": {"ipv4": "172.105.166.5,172.105.169.5,172.105.168.5,172.105.172.5,172.105.162.5,172.105.170.5,172.105.167.5,172.105.171.5,172.105.181.5,172.105.161.5", + "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, + "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "us-central", "label": "Dallas, TX, USA", "country": + "us", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Kubernetes", + "Managed Databases"], "status": "ok", "resolvers": {"ipv4": "72.14.179.5,72.14.188.5,173.255.199.5,66.228.53.5,96.126.122.5,96.126.124.5,96.126.127.5,198.58.107.5,198.58.111.5,23.239.24.5", + "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, + "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "us-west", "label": "Fremont, CA, USA", "country": + "us", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Managed Databases"], + "status": "ok", "resolvers": {"ipv4": "173.230.145.5,173.230.147.5,173.230.155.5,173.255.212.5,173.255.219.5,173.255.241.5,173.255.243.5,173.255.244.5,74.207.241.5,74.207.242.5", + "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, + "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "us-southeast", "label": "Atlanta, GA, USA", + "country": "us", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Managed + Databases"], "status": "ok", "resolvers": {"ipv4": "74.207.231.5,173.230.128.5,173.230.129.5,173.230.136.5,173.230.140.5,66.228.59.5,66.228.62.5,50.116.35.5,50.116.41.5,23.239.18.5", + "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, + "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "us-east", "label": "Newark, NJ, USA", "country": + "us", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Block Storage", + "Object Storage", "GPU Linodes", "Kubernetes", "Cloud Firewall", "Bare Metal", + "Vlans", "VPCs", "Block Storage Migrations", "Managed Databases", "Metadata"], + "status": "ok", "resolvers": {"ipv4": "66.228.42.5,96.126.106.5,50.116.53.5,50.116.58.5,50.116.61.5,50.116.62.5,66.175.211.5,97.107.133.4,207.192.69.4,207.192.69.5", + "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, + "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "eu-west", "label": "London, England, UK", + "country": "uk", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Cloud + Firewall", "Vlans", "VPCs", "Managed Databases", "Metadata", "Placement Group"], + "status": "ok", "resolvers": {"ipv4": "178.79.182.5,176.58.107.5,176.58.116.5,176.58.121.5,151.236.220.5,212.71.252.5,212.71.253.5,109.74.192.20,109.74.193.20,109.74.194.20", + "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, + "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "ap-south", "label": "Singapore, SG", "country": + "sg", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Object Storage", + "Managed Databases"], "status": "ok", "resolvers": {"ipv4": "139.162.11.5,139.162.13.5,139.162.14.5,139.162.15.5,139.162.16.5,139.162.21.5,139.162.27.5,103.3.60.18,103.3.60.19,103.3.60.20", + "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, + "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "eu-central", "label": "Frankfurt, DE", "country": + "de", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Object Storage", + "Managed Databases"], "status": "ok", "resolvers": {"ipv4": "139.162.130.5,139.162.131.5,139.162.132.5,139.162.133.5,139.162.134.5,139.162.135.5,139.162.136.5,139.162.137.5,139.162.138.5,139.162.139.5", + "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, + "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "ap-northeast", "label": "Tokyo 2, JP", "country": + "jp", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Managed Databases"], + "status": "ok", "resolvers": {"ipv4": "139.162.66.5,139.162.67.5,139.162.68.5,139.162.69.5,139.162.70.5,139.162.71.5,139.162.72.5,139.162.73.5,139.162.74.5,139.162.75.5", + "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, + "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + 5}, "site_type": "core"}], "page": 1, "pages": 1, "results": 11}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=900 + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "7144" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - '*' + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" diff --git a/test/integration/instances_test.go b/test/integration/instances_test.go index 352521e3c..478f1afcf 100644 --- a/test/integration/instances_test.go +++ b/test/integration/instances_test.go @@ -6,6 +6,8 @@ import ( "strconv" "testing" + "github.com/stretchr/testify/require" + "github.com/linode/linodego" ) @@ -475,6 +477,34 @@ func TestInstance_withMetadata(t *testing.T) { } } +func TestInstance_withPG(t *testing.T) { + client, clientTeardown := createTestClient(t, "fixtures/TestInstance_withPG") + + pg, pgTeardown, err := createPlacementGroup(t, client) + require.NoError(t, err) + + // Create an instance to assign to the PG + inst, err := createInstance(t, client, func(client *linodego.Client, options *linodego.InstanceCreateOptions) { + options.Region = pg.Region + options.PlacementGroup = &linodego.InstanceCreatePlacementGroupOptions{ + ID: pg.ID, + } + }) + require.NoError(t, err) + + defer func() { + client.DeleteInstance(context.Background(), inst.ID) + pgTeardown() + clientTeardown() + }() + + require.NotNil(t, inst.PlacementGroup) + require.Equal(t, inst.PlacementGroup.ID, pg.ID) + require.Equal(t, inst.PlacementGroup.Label, pg.Label) + require.Equal(t, inst.PlacementGroup.AffinityType, pg.AffinityType) + require.Equal(t, inst.PlacementGroup.IsStrict, pg.IsStrict) +} + func createInstance(t *testing.T, client *linodego.Client, modifiers ...instanceModifier) (*linodego.Instance, error) { if t != nil { t.Helper() diff --git a/test/integration/placement_group_test.go b/test/integration/placement_group_test.go new file mode 100644 index 000000000..f25cce77d --- /dev/null +++ b/test/integration/placement_group_test.go @@ -0,0 +1,145 @@ +package integration + +import ( + "context" + "fmt" + "reflect" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/linode/linodego" +) + +type placementGroupModifier func(*linodego.Client, *linodego.PlacementGroupCreateOptions) + +func TestPlacementGroup_basic(t *testing.T) { + client, clientTeardown := createTestClient(t, "fixtures/TestPlacementGroup_basic") + + // Create a PG + pg, pgTeardown, err := createPlacementGroup(t, client) + require.NoError(t, err) + + defer func() { + pgTeardown() + clientTeardown() + }() + + require.NotEqual(t, pg.ID, 0) + require.Contains(t, pg.Label, "linodego-test-") + require.NotEmpty(t, pg.Label) + require.Equal(t, pg.AffinityType, linodego.AffinityTypeAntiAffinityLocal) + require.Equal(t, pg.IsStrict, false) + require.Len(t, pg.Members, 0) + + updatedLabel := pg.Label + "-updated" + + // Test that the PG can be updated + pg, err = client.UpdatePlacementGroup( + context.Background(), + pg.ID, + linodego.PlacementGroupUpdateOptions{ + Label: updatedLabel, + }, + ) + require.NoError(t, err) + require.Equal(t, pg.Label, updatedLabel) + + // Test that the PG can be retrieved from the get endpoint + refreshedPG, err := client.GetPlacementGroup(context.Background(), pg.ID) + require.NoError(t, err) + require.True(t, reflect.DeepEqual(refreshedPG, pg)) + + // Test that the PG can be retrieved from the list endpoint + listedPGs, err := client.ListPlacementGroups(context.Background(), &linodego.ListOptions{ + Filter: fmt.Sprintf("{\"id\": %d}", pg.ID), + }) + require.NoError(t, err) + require.NotEmpty(t, listedPGs) + require.True(t, reflect.DeepEqual(listedPGs[0], *pg)) +} + +func TestPlacementGroup_assignment(t *testing.T) { + client, clientTeardown := createTestClient(t, "fixtures/TestPlacementGroup_assignment") + + pg, pgTeardown, err := createPlacementGroup(t, client) + require.NoError(t, err) + + // Create an instance to assign to the PG + inst, err := createInstance(t, client, func(client *linodego.Client, options *linodego.InstanceCreateOptions) { + options.Region = pg.Region + }) + require.NoError(t, err) + + defer func() { + // client.DeleteInstance(context.Background(), inst.ID) + pgTeardown() + clientTeardown() + }() + + // Ensure assignment works as expected + pg, err = client.AssignPlacementGroupLinodes( + context.Background(), + pg.ID, + linodego.PlacementGroupAssignOptions{ + Linodes: []int{ + inst.ID, + }, + }, + ) + require.NoError(t, err) + require.Len(t, pg.Members, 1) + require.Equal(t, pg.Members[0].LinodeID, inst.ID) + + // Refresh the instance to ensure the assignment has completed + inst, err = client.GetInstance(context.Background(), inst.ID) + require.NoError(t, err) + require.NotNil(t, inst.PlacementGroup) + require.Equal(t, inst.PlacementGroup.ID, pg.ID) + require.Equal(t, inst.PlacementGroup.Label, pg.Label) + require.Equal(t, inst.PlacementGroup.IsStrict, pg.IsStrict) + require.Equal(t, inst.PlacementGroup.AffinityType, pg.AffinityType) + + // Ensure unassignment works as expected + pg, err = client.UnAssignPlacementGroupLinodes( + context.Background(), + pg.ID, + linodego.PlacementGroupUnAssignOptions{ + Linodes: []int{ + inst.ID, + }, + }, + ) + require.NoError(t, err) + require.Len(t, pg.Members, 0) +} + +func createPlacementGroup( + t *testing.T, + client *linodego.Client, + pgModifier ...placementGroupModifier, +) (*linodego.PlacementGroup, func(), error) { + t.Helper() + createOpts := linodego.PlacementGroupCreateOptions{ + Label: "linodego-test-" + getUniqueText(), + Region: getRegionsWithCaps(t, client, []string{"Placement Group"})[0], + AffinityType: linodego.AffinityTypeAntiAffinityLocal, + IsStrict: false, + } + + for _, mod := range pgModifier { + mod(client, &createOpts) + } + + pg, err := client.CreatePlacementGroup(context.Background(), createOpts) + if err != nil { + t.Fatalf("failed to create placement group: %s", err) + } + + teardown := func() { + if err := client.DeletePlacementGroup(context.Background(), pg.ID); err != nil { + t.Errorf("failed to delete placement group: %s", err) + } + } + return pg, teardown, err +} diff --git a/test/integration/regions_test.go b/test/integration/regions_test.go index 2ace12e1c..b4de36985 100644 --- a/test/integration/regions_test.go +++ b/test/integration/regions_test.go @@ -2,7 +2,11 @@ package integration import ( "context" + "slices" "testing" + + "github.com/linode/linodego" + "github.com/stretchr/testify/require" ) func TestRegions_List(t *testing.T) { @@ -21,3 +25,23 @@ func TestRegions_List(t *testing.T) { retryStatement(t, 3, testFunc) } + +func TestRegions_pgLimits(t *testing.T) { + client, teardown := createTestClient(t, "fixtures/TestRegions_pgLimits") + defer teardown() + + regions, err := client.ListRegions(context.Background(), nil) + require.NoError(t, err) + + // Filtering is not currently supported on capabilities + regionIdx := slices.IndexFunc(regions, func(region linodego.Region) bool { + return slices.Contains(region.Capabilities, "Placement Group") + }) + require.NotZero(t, regionIdx) + + region := regions[regionIdx] + + require.NotNil(t, region.PlacementGroupLimits) + require.NotZero(t, region.PlacementGroupLimits.MaximumLinodesPerPG) + require.NotZero(t, region.PlacementGroupLimits.MaximumPGsPerCustomer) +} From 1e536d2603ec609efc22adbd2cb74db84b33b53a Mon Sep 17 00:00:00 2001 From: Lena Garber <114949949+lgarber-akamai@users.noreply.github.com> Date: Tue, 23 Apr 2024 13:07:38 -0400 Subject: [PATCH 2/6] Add event actions and entities for PGs (#492) --- account_events.go | 8 ++++++++ go.work.sum | 5 +++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/account_events.go b/account_events.go index 0f8565d18..453ae337a 100644 --- a/account_events.go +++ b/account_events.go @@ -155,6 +155,13 @@ const ( ActionPaymentMethodAdd EventAction = "payment_method_add" ActionPaymentSubmitted EventAction = "payment_submitted" ActionPasswordReset EventAction = "password_reset" + ActionPlacementGroupCreate EventAction = "placement_group_create" + ActionPlacementGroupUpdate EventAction = "placement_group_update" + ActionPlacementGroupDelete EventAction = "placement_group_delete" + ActionPlacementGroupAssign EventAction = "placement_group_assign" + ActionPlacementGroupUnassign EventAction = "placement_group_unassign" + ActionPlacementGroupBecameNonCompliant EventAction = "placement_group_became_non_compliant" + ActionPlacementGroupBecameCompliant EventAction = "placement_group_became_compliant" ActionProfileUpdate EventAction = "profile_update" ActionStackScriptCreate EventAction = "stackscript_create" ActionStackScriptDelete EventAction = "stackscript_delete" @@ -222,6 +229,7 @@ const ( EntityManagedService EntityType = "managed_service" EntityNodebalancer EntityType = "nodebalancer" EntityOAuthClient EntityType = "oauth_client" + EntityPlacementGroup EntityType = "placement_group" EntityProfile EntityType = "profile" EntityStackscript EntityType = "stackscript" EntityTag EntityType = "tag" diff --git a/go.work.sum b/go.work.sum index 677934393..d9c424d35 100644 --- a/go.work.sum +++ b/go.work.sum @@ -183,6 +183,7 @@ golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72 golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= +golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6 h1:QE6XYQK6naiK1EPAe1g/ILLxN5RBoH5xkJk3CqlMI/Y= golang.org/x/image v0.0.0-20190802002840-cff245a6509b h1:+qEpEAPhDZ1o0x3tHzZTQDArnOixOzGD9HUJfcg0mb4= @@ -206,13 +207,13 @@ golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= google.golang.org/api v0.126.0 h1:q4GJq+cAdMAC7XP7njvQ4tvohGLiSlytuL4BQxbIZ+o= google.golang.org/api v0.126.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvyo4Aw= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc h1:8DyZCyvI8mE1IdLy/60bS+52xfymkE72wv1asokgtao= google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64= google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc h1:kVKPf/IiYSBWEWtkIn6wZXwWGCnLKcC8oWfZvXjsGnM= From c7466a87fda550019296b923000ebf33b60303e5 Mon Sep 17 00:00:00 2001 From: Lena Garber <114949949+lgarber-akamai@users.noreply.github.com> Date: Wed, 1 May 2024 12:45:29 -0400 Subject: [PATCH 3/6] Correct case for UnassignPlacementGroupLinodes (#496) --- placement_groups.go | 4 ++-- test/integration/placement_group_test.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/placement_groups.go b/placement_groups.go index 08286bbb0..eaa5e4b22 100644 --- a/placement_groups.go +++ b/placement_groups.go @@ -124,9 +124,9 @@ func (c *Client) AssignPlacementGroupLinodes( ) } -// UnAssignPlacementGroupLinodes un-assigns the specified Linodes from the given +// UnassignPlacementGroupLinodes un-assigns the specified Linodes from the given // placement group. -func (c *Client) UnAssignPlacementGroupLinodes( +func (c *Client) UnassignPlacementGroupLinodes( ctx context.Context, id int, options PlacementGroupUnAssignOptions, diff --git a/test/integration/placement_group_test.go b/test/integration/placement_group_test.go index f25cce77d..01f2e1411 100644 --- a/test/integration/placement_group_test.go +++ b/test/integration/placement_group_test.go @@ -101,7 +101,7 @@ func TestPlacementGroup_assignment(t *testing.T) { require.Equal(t, inst.PlacementGroup.AffinityType, pg.AffinityType) // Ensure unassignment works as expected - pg, err = client.UnAssignPlacementGroupLinodes( + pg, err = client.UnassignPlacementGroupLinodes( context.Background(), pg.ID, linodego.PlacementGroupUnAssignOptions{ From e55147ab243dfefd1f3b078282f79af5d5221ad8 Mon Sep 17 00:00:00 2001 From: Lena Garber Date: Tue, 18 Jun 2024 11:05:51 -0400 Subject: [PATCH 4/6] Re-run fixtures --- .../fixtures/TestInstance_withPG.yaml | 89 ++++++------- .../TestPlacementGroup_assignment.yaml | 124 ++++++++---------- test/integration/placement_group_test.go | 2 +- 3 files changed, 102 insertions(+), 113 deletions(-) diff --git a/test/integration/fixtures/TestInstance_withPG.yaml b/test/integration/fixtures/TestInstance_withPG.yaml index 455bf7d85..bc7f63acc 100644 --- a/test/integration/fixtures/TestInstance_withPG.yaml +++ b/test/integration/fixtures/TestInstance_withPG.yaml @@ -18,61 +18,69 @@ interactions: "capabilities": ["Linodes", "Backups", "NodeBalancers", "Vlans", "VPCs", "Managed Databases"], "status": "ok", "resolvers": {"ipv4": "172.105.34.5,172.105.35.5,172.105.36.5,172.105.37.5,172.105.38.5,172.105.39.5,172.105.40.5,172.105.41.5,172.105.42.5,172.105.43.5", "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, - "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + "placement_group_limits": {"maximum_pgs_per_customer": 100, "maximum_linodes_per_pg": 5}, "site_type": "core"}, {"id": "ca-central", "label": "Toronto, Ontario, CAN", "country": "ca", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Vlans", "VPCs", "Managed Databases"], "status": "ok", "resolvers": {"ipv4": "172.105.0.5,172.105.3.5,172.105.4.5,172.105.5.5,172.105.6.5,172.105.7.5,172.105.8.5,172.105.9.5,172.105.10.5,172.105.11.5", "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, - "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + "placement_group_limits": {"maximum_pgs_per_customer": 100, "maximum_linodes_per_pg": 5}, "site_type": "core"}, {"id": "ap-southeast", "label": "Sydney, NSW, Australia", "country": "au", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Vlans", "VPCs", "Managed Databases"], "status": "ok", "resolvers": {"ipv4": "172.105.166.5,172.105.169.5,172.105.168.5,172.105.172.5,172.105.162.5,172.105.170.5,172.105.167.5,172.105.171.5,172.105.181.5,172.105.161.5", "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, - "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + "placement_group_limits": {"maximum_pgs_per_customer": 100, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "fake-cph-4", "label": "Fake CPH 4, DK", "country": + "dk", "capabilities": ["Linodes", "Metadata"], "status": "ok", "resolvers": + {"ipv4": "8.8.8.8,1.1.1.1,1.0.0.1,8.8.4.4", "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678"}, + "placement_group_limits": {"maximum_pgs_per_customer": 100, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "fake-cph-5", "label": "Fake CPH 5, DK", "country": + "dk", "capabilities": ["Linodes", "Metadata"], "status": "ok", "resolvers": + {"ipv4": "8.8.8.8,1.1.1.1,1.0.0.1,8.8.4.4", "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678"}, + "placement_group_limits": {"maximum_pgs_per_customer": 100, "maximum_linodes_per_pg": 5}, "site_type": "core"}, {"id": "us-central", "label": "Dallas, TX, USA", "country": "us", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Kubernetes", "Managed Databases"], "status": "ok", "resolvers": {"ipv4": "72.14.179.5,72.14.188.5,173.255.199.5,66.228.53.5,96.126.122.5,96.126.124.5,96.126.127.5,198.58.107.5,198.58.111.5,23.239.24.5", "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, - "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + "placement_group_limits": {"maximum_pgs_per_customer": 100, "maximum_linodes_per_pg": 5}, "site_type": "core"}, {"id": "us-west", "label": "Fremont, CA, USA", "country": "us", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Managed Databases"], "status": "ok", "resolvers": {"ipv4": "173.230.145.5,173.230.147.5,173.230.155.5,173.255.212.5,173.255.219.5,173.255.241.5,173.255.243.5,173.255.244.5,74.207.241.5,74.207.242.5", "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, - "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + "placement_group_limits": {"maximum_pgs_per_customer": 100, "maximum_linodes_per_pg": 5}, "site_type": "core"}, {"id": "us-southeast", "label": "Atlanta, GA, USA", "country": "us", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Managed Databases"], "status": "ok", "resolvers": {"ipv4": "74.207.231.5,173.230.128.5,173.230.129.5,173.230.136.5,173.230.140.5,66.228.59.5,66.228.62.5,50.116.35.5,50.116.41.5,23.239.18.5", "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, - "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + "placement_group_limits": {"maximum_pgs_per_customer": 100, "maximum_linodes_per_pg": 5}, "site_type": "core"}, {"id": "us-east", "label": "Newark, NJ, USA", "country": - "us", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Block Storage", - "Object Storage", "GPU Linodes", "Kubernetes", "Cloud Firewall", "Bare Metal", - "Vlans", "VPCs", "Block Storage Migrations", "Managed Databases", "Metadata"], - "status": "ok", "resolvers": {"ipv4": "66.228.42.5,96.126.106.5,50.116.53.5,50.116.58.5,50.116.61.5,50.116.62.5,66.175.211.5,97.107.133.4,207.192.69.4,207.192.69.5", + "us", "capabilities": ["Linodes", "Disk Encryption", "Backups", "NodeBalancers", + "Block Storage", "Object Storage", "GPU Linodes", "Kubernetes", "Cloud Firewall", + "Bare Metal", "Vlans", "VPCs", "Block Storage Migrations", "Managed Databases", + "Placement Group"], "status": "ok", "resolvers": {"ipv4": "66.228.42.5,96.126.106.5,50.116.53.5,50.116.58.5,50.116.61.5,50.116.62.5,66.175.211.5,97.107.133.4,207.192.69.4,207.192.69.5", "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, - "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + "placement_group_limits": {"maximum_pgs_per_customer": 100, "maximum_linodes_per_pg": 5}, "site_type": "core"}, {"id": "eu-west", "label": "London, England, UK", "country": "uk", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Cloud Firewall", "Vlans", "VPCs", "Managed Databases", "Metadata", "Placement Group"], "status": "ok", "resolvers": {"ipv4": "178.79.182.5,176.58.107.5,176.58.116.5,176.58.121.5,151.236.220.5,212.71.252.5,212.71.253.5,109.74.192.20,109.74.193.20,109.74.194.20", "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, - "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + "placement_group_limits": {"maximum_pgs_per_customer": 100, "maximum_linodes_per_pg": 5}, "site_type": "core"}, {"id": "ap-south", "label": "Singapore, SG", "country": - "sg", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Object Storage", - "Managed Databases"], "status": "ok", "resolvers": {"ipv4": "139.162.11.5,139.162.13.5,139.162.14.5,139.162.15.5,139.162.16.5,139.162.21.5,139.162.27.5,103.3.60.18,103.3.60.19,103.3.60.20", + "sg", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Managed Databases"], + "status": "ok", "resolvers": {"ipv4": "139.162.11.5,139.162.13.5,139.162.14.5,139.162.15.5,139.162.16.5,139.162.21.5,139.162.27.5,103.3.60.18,103.3.60.19,103.3.60.20", "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, - "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + "placement_group_limits": {"maximum_pgs_per_customer": 100, "maximum_linodes_per_pg": 5}, "site_type": "core"}, {"id": "eu-central", "label": "Frankfurt, DE", "country": - "de", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Object Storage", - "Managed Databases"], "status": "ok", "resolvers": {"ipv4": "139.162.130.5,139.162.131.5,139.162.132.5,139.162.133.5,139.162.134.5,139.162.135.5,139.162.136.5,139.162.137.5,139.162.138.5,139.162.139.5", + "de", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Managed Databases"], + "status": "ok", "resolvers": {"ipv4": "139.162.130.5,139.162.131.5,139.162.132.5,139.162.133.5,139.162.134.5,139.162.135.5,139.162.136.5,139.162.137.5,139.162.138.5,139.162.139.5", "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, - "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + "placement_group_limits": {"maximum_pgs_per_customer": 100, "maximum_linodes_per_pg": 5}, "site_type": "core"}, {"id": "ap-northeast", "label": "Tokyo 2, JP", "country": "jp", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Managed Databases"], "status": "ok", "resolvers": {"ipv4": "139.162.66.5,139.162.67.5,139.162.68.5,139.162.69.5,139.162.70.5,139.162.71.5,139.162.72.5,139.162.73.5,139.162.74.5,139.162.75.5", "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, - "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": - 5}, "site_type": "core"}], "page": 1, "pages": 1, "results": 11}' + "placement_group_limits": {"maximum_pgs_per_customer": 100, "maximum_linodes_per_pg": + 5}, "site_type": "core"}], "page": 1, "pages": 1, "results": 13}' headers: Access-Control-Allow-Credentials: - "true" @@ -87,10 +95,6 @@ interactions: Cache-Control: - private, max-age=900 - private, max-age=60, s-maxage=60 - Connection: - - keep-alive - Content-Length: - - "7144" Content-Security-Policy: - default-src 'none' Content-Type: @@ -100,6 +104,7 @@ interactions: Strict-Transport-Security: - max-age=31536000 Vary: + - Accept-Encoding - Authorization, X-Filter - Authorization, X-Filter X-Accepted-Oauth-Scopes: @@ -119,7 +124,7 @@ interactions: code: 200 duration: "" - request: - body: '{"label":"linodego-test-1712862693761548000","region":"eu-west","affinity_type":"anti_affinity:local","is_strict":false}' + body: '{"label":"linodego-test-1718723007764225000","region":"us-east","affinity_type":"anti_affinity:local","is_strict":false}' form: {} headers: Accept: @@ -131,7 +136,7 @@ interactions: url: https://api.linode.com/v4beta/placement/groups method: POST response: - body: '{"id": 356, "label": "linodego-test-1712862693761548000", "region": "eu-west", + body: '{"id": 4021, "label": "linodego-test-1718723007764225000", "region": "us-east", "affinity_type": "anti_affinity:local", "is_strict": false, "is_compliant": true, "members": []}' headers: @@ -147,10 +152,8 @@ interactions: - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status Cache-Control: - private, max-age=60, s-maxage=60 - Connection: - - keep-alive Content-Length: - - "175" + - "176" Content-Security-Policy: - default-src 'none' Content-Type: @@ -178,7 +181,7 @@ interactions: code: 200 duration: "" - request: - body: '{"region":"eu-west","type":"g6-nanode-1","label":"go-test-ins-g14gx0ib8h49","root_pass":"h4#|k51Ic\u003cdoX\u00262W59A!fF8N.|}n:5}Yt=s\u003e0yJ\\D/6M8gc/~6PHGYG09nEd4kh5","image":"linode/debian9","placement_group":{"id":356},"booted":false}' + body: '{"region":"us-east","type":"g6-nanode-1","label":"go-test-ins-5skg99rf1a38","root_pass":"Jb\u00262S#q7072\u003cXj;imqjH7zr5n96A)OVLK8j\\Z31@{+Ei0R72jG]\u003cEGbr.5F/=-\u0026l","image":"linode/debian9","firewall_id":34216,"placement_group":{"id":4021},"booted":false}' form: {} headers: Accept: @@ -190,17 +193,18 @@ interactions: url: https://api.linode.com/v4beta/linode/instances method: POST response: - body: '{"id": 25124077, "label": "go-test-ins-g14gx0ib8h49", "group": "", "status": + body: '{"id": 25195351, "label": "go-test-ins-5skg99rf1a38", "group": "", "status": "provisioning", "created": "2018-01-02T03:04:05", "updated": "2018-01-02T03:04:05", - "type": "g6-nanode-1", "ipv4": ["139.144.245.159"], "ipv6": "1234::5678/128", - "image": "linode/debian9", "region": "eu-west", "specs": {"disk": 25600, "memory": + "type": "g6-nanode-1", "ipv4": ["143.42.181.72"], "ipv6": "1234::5678/128", + "image": "linode/debian9", "region": "us-east", "specs": {"disk": 25600, "memory": 1024, "vcpus": 1, "gpus": 0, "transfer": 1000}, "alerts": {"cpu": 90, "network_in": 10, "network_out": 10, "transfer_quota": 80, "io": 10000}, "backups": {"enabled": false, "available": false, "schedule": {"day": null, "window": null}, "last_successful": null}, "hypervisor": "kvm", "watchdog_enabled": true, "tags": [], "host_uuid": - "e7dea8a2851fa88da8866ef434a553491200ea8c", "has_user_data": false, "placement_group": - {"id": 356, "label": "linodego-test-1712862693761548000", "affinity_type": "anti_affinity:local", - "is_strict": false}}' + "2e8c6f5e2c38ef3261c570ae22ac2b65435af20b", "has_user_data": false, "placement_group": + {"id": 4021, "label": "linodego-test-1718723007764225000", "affinity_type": + "anti_affinity:local", "is_strict": false}, "disk_encryption": "enabled", "lke_cluster_id": + null}' headers: Access-Control-Allow-Credentials: - "true" @@ -214,10 +218,6 @@ interactions: - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status Cache-Control: - private, max-age=60, s-maxage=60 - Connection: - - keep-alive - Content-Length: - - "881" Content-Security-Policy: - default-src 'none' Content-Type: @@ -227,6 +227,7 @@ interactions: Strict-Transport-Security: - max-age=31536000 Vary: + - Accept-Encoding - Authorization, X-Filter X-Accepted-Oauth-Scopes: - linodes:read_write @@ -254,7 +255,7 @@ interactions: - application/json User-Agent: - linodego/dev https://github.com/linode/linodego - url: https://api.linode.com/v4beta/linode/instances/25124077 + url: https://api.linode.com/v4beta/linode/instances/25195351 method: DELETE response: body: '{}' @@ -271,8 +272,6 @@ interactions: - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status Cache-Control: - private, max-age=60, s-maxage=60 - Connection: - - keep-alive Content-Length: - "2" Content-Security-Policy: @@ -311,7 +310,7 @@ interactions: - application/json User-Agent: - linodego/dev https://github.com/linode/linodego - url: https://api.linode.com/v4beta/placement/groups/356 + url: https://api.linode.com/v4beta/placement/groups/4021 method: DELETE response: body: '{}' @@ -328,8 +327,6 @@ interactions: - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status Cache-Control: - private, max-age=60, s-maxage=60 - Connection: - - keep-alive Content-Length: - "2" Content-Security-Policy: diff --git a/test/integration/fixtures/TestPlacementGroup_assignment.yaml b/test/integration/fixtures/TestPlacementGroup_assignment.yaml index 74449d2c2..449cbc77a 100644 --- a/test/integration/fixtures/TestPlacementGroup_assignment.yaml +++ b/test/integration/fixtures/TestPlacementGroup_assignment.yaml @@ -18,61 +18,69 @@ interactions: "capabilities": ["Linodes", "Backups", "NodeBalancers", "Vlans", "VPCs", "Managed Databases"], "status": "ok", "resolvers": {"ipv4": "172.105.34.5,172.105.35.5,172.105.36.5,172.105.37.5,172.105.38.5,172.105.39.5,172.105.40.5,172.105.41.5,172.105.42.5,172.105.43.5", "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, - "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + "placement_group_limits": {"maximum_pgs_per_customer": 100, "maximum_linodes_per_pg": 5}, "site_type": "core"}, {"id": "ca-central", "label": "Toronto, Ontario, CAN", "country": "ca", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Vlans", "VPCs", "Managed Databases"], "status": "ok", "resolvers": {"ipv4": "172.105.0.5,172.105.3.5,172.105.4.5,172.105.5.5,172.105.6.5,172.105.7.5,172.105.8.5,172.105.9.5,172.105.10.5,172.105.11.5", "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, - "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + "placement_group_limits": {"maximum_pgs_per_customer": 100, "maximum_linodes_per_pg": 5}, "site_type": "core"}, {"id": "ap-southeast", "label": "Sydney, NSW, Australia", "country": "au", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Vlans", "VPCs", "Managed Databases"], "status": "ok", "resolvers": {"ipv4": "172.105.166.5,172.105.169.5,172.105.168.5,172.105.172.5,172.105.162.5,172.105.170.5,172.105.167.5,172.105.171.5,172.105.181.5,172.105.161.5", "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, - "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + "placement_group_limits": {"maximum_pgs_per_customer": 100, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "fake-cph-4", "label": "Fake CPH 4, DK", "country": + "dk", "capabilities": ["Linodes", "Metadata"], "status": "ok", "resolvers": + {"ipv4": "8.8.8.8,1.1.1.1,1.0.0.1,8.8.4.4", "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678"}, + "placement_group_limits": {"maximum_pgs_per_customer": 100, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "fake-cph-5", "label": "Fake CPH 5, DK", "country": + "dk", "capabilities": ["Linodes", "Metadata"], "status": "ok", "resolvers": + {"ipv4": "8.8.8.8,1.1.1.1,1.0.0.1,8.8.4.4", "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678"}, + "placement_group_limits": {"maximum_pgs_per_customer": 100, "maximum_linodes_per_pg": 5}, "site_type": "core"}, {"id": "us-central", "label": "Dallas, TX, USA", "country": "us", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Kubernetes", "Managed Databases"], "status": "ok", "resolvers": {"ipv4": "72.14.179.5,72.14.188.5,173.255.199.5,66.228.53.5,96.126.122.5,96.126.124.5,96.126.127.5,198.58.107.5,198.58.111.5,23.239.24.5", "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, - "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + "placement_group_limits": {"maximum_pgs_per_customer": 100, "maximum_linodes_per_pg": 5}, "site_type": "core"}, {"id": "us-west", "label": "Fremont, CA, USA", "country": "us", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Managed Databases"], "status": "ok", "resolvers": {"ipv4": "173.230.145.5,173.230.147.5,173.230.155.5,173.255.212.5,173.255.219.5,173.255.241.5,173.255.243.5,173.255.244.5,74.207.241.5,74.207.242.5", "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, - "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + "placement_group_limits": {"maximum_pgs_per_customer": 100, "maximum_linodes_per_pg": 5}, "site_type": "core"}, {"id": "us-southeast", "label": "Atlanta, GA, USA", "country": "us", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Managed Databases"], "status": "ok", "resolvers": {"ipv4": "74.207.231.5,173.230.128.5,173.230.129.5,173.230.136.5,173.230.140.5,66.228.59.5,66.228.62.5,50.116.35.5,50.116.41.5,23.239.18.5", "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, - "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + "placement_group_limits": {"maximum_pgs_per_customer": 100, "maximum_linodes_per_pg": 5}, "site_type": "core"}, {"id": "us-east", "label": "Newark, NJ, USA", "country": - "us", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Block Storage", - "Object Storage", "GPU Linodes", "Kubernetes", "Cloud Firewall", "Bare Metal", - "Vlans", "VPCs", "Block Storage Migrations", "Managed Databases", "Metadata"], - "status": "ok", "resolvers": {"ipv4": "66.228.42.5,96.126.106.5,50.116.53.5,50.116.58.5,50.116.61.5,50.116.62.5,66.175.211.5,97.107.133.4,207.192.69.4,207.192.69.5", + "us", "capabilities": ["Linodes", "Disk Encryption", "Backups", "NodeBalancers", + "Block Storage", "Object Storage", "GPU Linodes", "Kubernetes", "Cloud Firewall", + "Bare Metal", "Vlans", "VPCs", "Block Storage Migrations", "Managed Databases", + "Placement Group"], "status": "ok", "resolvers": {"ipv4": "66.228.42.5,96.126.106.5,50.116.53.5,50.116.58.5,50.116.61.5,50.116.62.5,66.175.211.5,97.107.133.4,207.192.69.4,207.192.69.5", "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, - "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + "placement_group_limits": {"maximum_pgs_per_customer": 100, "maximum_linodes_per_pg": 5}, "site_type": "core"}, {"id": "eu-west", "label": "London, England, UK", "country": "uk", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Cloud Firewall", "Vlans", "VPCs", "Managed Databases", "Metadata", "Placement Group"], "status": "ok", "resolvers": {"ipv4": "178.79.182.5,176.58.107.5,176.58.116.5,176.58.121.5,151.236.220.5,212.71.252.5,212.71.253.5,109.74.192.20,109.74.193.20,109.74.194.20", "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, - "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + "placement_group_limits": {"maximum_pgs_per_customer": 100, "maximum_linodes_per_pg": 5}, "site_type": "core"}, {"id": "ap-south", "label": "Singapore, SG", "country": - "sg", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Object Storage", - "Managed Databases"], "status": "ok", "resolvers": {"ipv4": "139.162.11.5,139.162.13.5,139.162.14.5,139.162.15.5,139.162.16.5,139.162.21.5,139.162.27.5,103.3.60.18,103.3.60.19,103.3.60.20", + "sg", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Managed Databases"], + "status": "ok", "resolvers": {"ipv4": "139.162.11.5,139.162.13.5,139.162.14.5,139.162.15.5,139.162.16.5,139.162.21.5,139.162.27.5,103.3.60.18,103.3.60.19,103.3.60.20", "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, - "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + "placement_group_limits": {"maximum_pgs_per_customer": 100, "maximum_linodes_per_pg": 5}, "site_type": "core"}, {"id": "eu-central", "label": "Frankfurt, DE", "country": - "de", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Object Storage", - "Managed Databases"], "status": "ok", "resolvers": {"ipv4": "139.162.130.5,139.162.131.5,139.162.132.5,139.162.133.5,139.162.134.5,139.162.135.5,139.162.136.5,139.162.137.5,139.162.138.5,139.162.139.5", + "de", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Managed Databases"], + "status": "ok", "resolvers": {"ipv4": "139.162.130.5,139.162.131.5,139.162.132.5,139.162.133.5,139.162.134.5,139.162.135.5,139.162.136.5,139.162.137.5,139.162.138.5,139.162.139.5", "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, - "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": + "placement_group_limits": {"maximum_pgs_per_customer": 100, "maximum_linodes_per_pg": 5}, "site_type": "core"}, {"id": "ap-northeast", "label": "Tokyo 2, JP", "country": "jp", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Managed Databases"], "status": "ok", "resolvers": {"ipv4": "139.162.66.5,139.162.67.5,139.162.68.5,139.162.69.5,139.162.70.5,139.162.71.5,139.162.72.5,139.162.73.5,139.162.74.5,139.162.75.5", "ipv6": "1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678,1234::5678"}, - "placement_group_limits": {"maximum_pgs_per_customer": 5, "maximum_linodes_per_pg": - 5}, "site_type": "core"}], "page": 1, "pages": 1, "results": 11}' + "placement_group_limits": {"maximum_pgs_per_customer": 100, "maximum_linodes_per_pg": + 5}, "site_type": "core"}], "page": 1, "pages": 1, "results": 13}' headers: Access-Control-Allow-Credentials: - "true" @@ -87,10 +95,6 @@ interactions: Cache-Control: - private, max-age=900 - private, max-age=60, s-maxage=60 - Connection: - - keep-alive - Content-Length: - - "7144" Content-Security-Policy: - default-src 'none' Content-Type: @@ -100,6 +104,7 @@ interactions: Strict-Transport-Security: - max-age=31536000 Vary: + - Accept-Encoding - Authorization, X-Filter - Authorization, X-Filter X-Accepted-Oauth-Scopes: @@ -119,7 +124,7 @@ interactions: code: 200 duration: "" - request: - body: '{"label":"linodego-test-1712862497480882000","region":"eu-west","affinity_type":"anti_affinity:local","is_strict":false}' + body: '{"label":"linodego-test-1718722972576732000","region":"us-east","affinity_type":"anti_affinity:local","is_strict":false}' form: {} headers: Accept: @@ -131,7 +136,7 @@ interactions: url: https://api.linode.com/v4beta/placement/groups method: POST response: - body: '{"id": 355, "label": "linodego-test-1712862497480882000", "region": "eu-west", + body: '{"id": 4020, "label": "linodego-test-1718722972576732000", "region": "us-east", "affinity_type": "anti_affinity:local", "is_strict": false, "is_compliant": true, "members": []}' headers: @@ -147,10 +152,8 @@ interactions: - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status Cache-Control: - private, max-age=60, s-maxage=60 - Connection: - - keep-alive Content-Length: - - "175" + - "176" Content-Security-Policy: - default-src 'none' Content-Type: @@ -178,7 +181,7 @@ interactions: code: 200 duration: "" - request: - body: '{"region":"eu-west","type":"g6-nanode-1","label":"go-test-ins-z63p4b2z8w8t","root_pass":"$j?W`mM=o6$2026T7;\u003e`Dr*X+XR81FCwIX8crCl7nma]7i=@\u0026riC4FN8146\u003eQv\u003ey","image":"linode/debian9","booted":false}' + body: '{"region":"us-east","type":"g6-nanode-1","label":"go-test-ins-t02660a1ehag","root_pass":"1@L\u003e)0sb6qd`]5\u0026OW~K\\Q6F~5l4Tys\\3Gh9RI93}2Wrs6u;Pu?5c;~)ERj8Jm9Xo","image":"linode/debian9","firewall_id":34215,"booted":false}' form: {} headers: Accept: @@ -190,16 +193,16 @@ interactions: url: https://api.linode.com/v4beta/linode/instances method: POST response: - body: '{"id": 25124076, "label": "go-test-ins-z63p4b2z8w8t", "group": "", "status": + body: '{"id": 25195349, "label": "go-test-ins-t02660a1ehag", "group": "", "status": "provisioning", "created": "2018-01-02T03:04:05", "updated": "2018-01-02T03:04:05", - "type": "g6-nanode-1", "ipv4": ["139.144.245.158"], "ipv6": "1234::5678/128", - "image": "linode/debian9", "region": "eu-west", "specs": {"disk": 25600, "memory": + "type": "g6-nanode-1", "ipv4": ["143.42.181.254"], "ipv6": "1234::5678/128", + "image": "linode/debian9", "region": "us-east", "specs": {"disk": 25600, "memory": 1024, "vcpus": 1, "gpus": 0, "transfer": 1000}, "alerts": {"cpu": 90, "network_in": 10, "network_out": 10, "transfer_quota": 80, "io": 10000}, "backups": {"enabled": false, "available": false, "schedule": {"day": null, "window": null}, "last_successful": null}, "hypervisor": "kvm", "watchdog_enabled": true, "tags": [], "host_uuid": - "e7dea8a2851fa88da8866ef434a553491200ea8c", "has_user_data": false, "placement_group": - null}' + "53257e56e7692e143036a5fbf7daaf92b5350bf3", "has_user_data": false, "placement_group": + null, "disk_encryption": "enabled", "lke_cluster_id": null}' headers: Access-Control-Allow-Credentials: - "true" @@ -213,10 +216,6 @@ interactions: - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status Cache-Control: - private, max-age=60, s-maxage=60 - Connection: - - keep-alive - Content-Length: - - "768" Content-Security-Policy: - default-src 'none' Content-Type: @@ -226,6 +225,7 @@ interactions: Strict-Transport-Security: - max-age=31536000 Vary: + - Accept-Encoding - Authorization, X-Filter X-Accepted-Oauth-Scopes: - linodes:read_write @@ -244,7 +244,7 @@ interactions: code: 200 duration: "" - request: - body: '{"linodes":[25124076]}' + body: '{"linodes":[25195349]}' form: {} headers: Accept: @@ -253,12 +253,12 @@ interactions: - application/json User-Agent: - linodego/dev https://github.com/linode/linodego - url: https://api.linode.com/v4beta/placement/groups/355/assign + url: https://api.linode.com/v4beta/placement/groups/4020/assign method: POST response: - body: '{"id": 355, "label": "linodego-test-1712862497480882000", "region": "eu-west", + body: '{"id": 4020, "label": "linodego-test-1718722972576732000", "region": "us-east", "affinity_type": "anti_affinity:local", "is_strict": false, "is_compliant": - true, "members": [{"linode_id": 25124076, "is_compliant": true}]}' + true, "members": [{"linode_id": 25195349, "is_compliant": true}]}' headers: Access-Control-Allow-Credentials: - "true" @@ -272,10 +272,8 @@ interactions: - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status Cache-Control: - private, max-age=60, s-maxage=60 - Connection: - - keep-alive Content-Length: - - "220" + - "221" Content-Security-Policy: - default-src 'none' Content-Type: @@ -312,20 +310,21 @@ interactions: - application/json User-Agent: - linodego/dev https://github.com/linode/linodego - url: https://api.linode.com/v4beta/linode/instances/25124076 + url: https://api.linode.com/v4beta/linode/instances/25195349 method: GET response: - body: '{"id": 25124076, "label": "go-test-ins-z63p4b2z8w8t", "group": "", "status": + body: '{"id": 25195349, "label": "go-test-ins-t02660a1ehag", "group": "", "status": "provisioning", "created": "2018-01-02T03:04:05", "updated": "2018-01-02T03:04:05", - "type": "g6-nanode-1", "ipv4": ["139.144.245.158"], "ipv6": "1234::5678/128", - "image": "linode/debian9", "region": "eu-west", "specs": {"disk": 25600, "memory": + "type": "g6-nanode-1", "ipv4": ["143.42.181.254"], "ipv6": "1234::5678/128", + "image": "linode/debian9", "region": "us-east", "specs": {"disk": 25600, "memory": 1024, "vcpus": 1, "gpus": 0, "transfer": 1000}, "alerts": {"cpu": 90, "network_in": 10, "network_out": 10, "transfer_quota": 80, "io": 10000}, "backups": {"enabled": false, "available": false, "schedule": {"day": null, "window": null}, "last_successful": null}, "hypervisor": "kvm", "watchdog_enabled": true, "tags": [], "host_uuid": - "e7dea8a2851fa88da8866ef434a553491200ea8c", "has_user_data": false, "placement_group": - {"id": 355, "label": "linodego-test-1712862497480882000", "affinity_type": "anti_affinity:local", - "is_strict": false}}' + "53257e56e7692e143036a5fbf7daaf92b5350bf3", "has_user_data": false, "placement_group": + {"id": 4020, "label": "linodego-test-1718722972576732000", "affinity_type": + "anti_affinity:local", "is_strict": false}, "disk_encryption": "enabled", "lke_cluster_id": + null}' headers: Access-Control-Allow-Credentials: - "true" @@ -340,10 +339,6 @@ interactions: Cache-Control: - private, max-age=0, s-maxage=0, no-cache, no-store - private, max-age=60, s-maxage=60 - Connection: - - keep-alive - Content-Length: - - "881" Content-Security-Policy: - default-src 'none' Content-Type: @@ -353,6 +348,7 @@ interactions: Strict-Transport-Security: - max-age=31536000 Vary: + - Accept-Encoding - Authorization, X-Filter - Authorization, X-Filter X-Accepted-Oauth-Scopes: @@ -372,7 +368,7 @@ interactions: code: 200 duration: "" - request: - body: '{"linodes":[25124076]}' + body: '{"linodes":[25195349]}' form: {} headers: Accept: @@ -381,10 +377,10 @@ interactions: - application/json User-Agent: - linodego/dev https://github.com/linode/linodego - url: https://api.linode.com/v4beta/placement/groups/355/unassign + url: https://api.linode.com/v4beta/placement/groups/4020/unassign method: POST response: - body: '{"id": 355, "label": "linodego-test-1712862497480882000", "region": "eu-west", + body: '{"id": 4020, "label": "linodego-test-1718722972576732000", "region": "us-east", "affinity_type": "anti_affinity:local", "is_strict": false, "is_compliant": true, "members": []}' headers: @@ -400,10 +396,8 @@ interactions: - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status Cache-Control: - private, max-age=60, s-maxage=60 - Connection: - - keep-alive Content-Length: - - "175" + - "176" Content-Security-Policy: - default-src 'none' Content-Type: @@ -440,7 +434,7 @@ interactions: - application/json User-Agent: - linodego/dev https://github.com/linode/linodego - url: https://api.linode.com/v4beta/placement/groups/355 + url: https://api.linode.com/v4beta/placement/groups/4020 method: DELETE response: body: '{}' @@ -457,8 +451,6 @@ interactions: - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status Cache-Control: - private, max-age=60, s-maxage=60 - Connection: - - keep-alive Content-Length: - "2" Content-Security-Policy: diff --git a/test/integration/placement_group_test.go b/test/integration/placement_group_test.go index 01f2e1411..7507f77ff 100644 --- a/test/integration/placement_group_test.go +++ b/test/integration/placement_group_test.go @@ -66,7 +66,7 @@ func TestPlacementGroup_assignment(t *testing.T) { require.NoError(t, err) // Create an instance to assign to the PG - inst, err := createInstance(t, client, func(client *linodego.Client, options *linodego.InstanceCreateOptions) { + inst, err := createInstance(t, client, true, func(client *linodego.Client, options *linodego.InstanceCreateOptions) { options.Region = pg.Region }) require.NoError(t, err) From 9bb3d96f51b46791a2f1969decf446a78052eceb Mon Sep 17 00:00:00 2001 From: Lena Garber <114949949+lgarber-akamai@users.noreply.github.com> Date: Thu, 20 Jun 2024 09:08:31 -0400 Subject: [PATCH 5/6] Add documentation snippets for PG LA (#530) --- instances.go | 46 ++++++++++++++++++++++++--------------------- placement_groups.go | 8 ++++++++ 2 files changed, 33 insertions(+), 21 deletions(-) diff --git a/instances.go b/instances.go index 9122478cd..402981050 100644 --- a/instances.go +++ b/instances.go @@ -43,26 +43,28 @@ const ( // Instance represents a linode object type Instance struct { - ID int `json:"id"` - Created *time.Time `json:"-"` - Updated *time.Time `json:"-"` - Region string `json:"region"` - Alerts *InstanceAlert `json:"alerts"` - Backups *InstanceBackup `json:"backups"` - Image string `json:"image"` - Group string `json:"group"` - IPv4 []*net.IP `json:"ipv4"` - IPv6 string `json:"ipv6"` - Label string `json:"label"` - Type string `json:"type"` - Status InstanceStatus `json:"status"` - HasUserData bool `json:"has_user_data"` - Hypervisor string `json:"hypervisor"` - HostUUID string `json:"host_uuid"` - Specs *InstanceSpec `json:"specs"` - WatchdogEnabled bool `json:"watchdog_enabled"` - Tags []string `json:"tags"` - PlacementGroup *InstancePlacementGroup `json:"placement_group"` + ID int `json:"id"` + Created *time.Time `json:"-"` + Updated *time.Time `json:"-"` + Region string `json:"region"` + Alerts *InstanceAlert `json:"alerts"` + Backups *InstanceBackup `json:"backups"` + Image string `json:"image"` + Group string `json:"group"` + IPv4 []*net.IP `json:"ipv4"` + IPv6 string `json:"ipv6"` + Label string `json:"label"` + Type string `json:"type"` + Status InstanceStatus `json:"status"` + HasUserData bool `json:"has_user_data"` + Hypervisor string `json:"hypervisor"` + HostUUID string `json:"host_uuid"` + Specs *InstanceSpec `json:"specs"` + WatchdogEnabled bool `json:"watchdog_enabled"` + Tags []string `json:"tags"` + + // NOTE: Placement Groups may not currently be available to all users. + PlacementGroup *InstancePlacementGroup `json:"placement_group"` } // InstanceSpec represents a linode spec @@ -139,7 +141,9 @@ type InstanceCreateOptions struct { Tags []string `json:"tags,omitempty"` Metadata *InstanceMetadataOptions `json:"metadata,omitempty"` FirewallID int `json:"firewall_id,omitempty"` - PlacementGroup *InstanceCreatePlacementGroupOptions `json:"placement_group,omitempty"` + + // NOTE: Placement Groups may not currently be available to all users. + PlacementGroup *InstanceCreatePlacementGroupOptions `json:"placement_group,omitempty"` // Creation fields that need to be set explicitly false, "", or 0 use pointers SwapSize *int `json:"swap_size,omitempty"` diff --git a/placement_groups.go b/placement_groups.go index eaa5e4b22..3987adca9 100644 --- a/placement_groups.go +++ b/placement_groups.go @@ -18,6 +18,7 @@ type PlacementGroupMember struct { } // PlacementGroup represents a Linode placement group. +// NOTE: Placement Groups may not currently be available to all users. type PlacementGroup struct { ID int `json:"id"` Label string `json:"label"` @@ -58,6 +59,7 @@ type PlacementGroupUnAssignOptions struct { // ListPlacementGroups lists placement groups under the current account // matching the given list options. +// NOTE: Placement Groups may not currently be available to all users. func (c *Client) ListPlacementGroups( ctx context.Context, options *ListOptions, @@ -71,6 +73,7 @@ func (c *Client) ListPlacementGroups( } // GetPlacementGroup gets a placement group with the specified ID. +// NOTE: Placement Groups may not currently be available to all users. func (c *Client) GetPlacementGroup( ctx context.Context, id int, @@ -83,6 +86,7 @@ func (c *Client) GetPlacementGroup( } // CreatePlacementGroup creates a placement group with the specified options. +// NOTE: Placement Groups may not currently be available to all users. func (c *Client) CreatePlacementGroup( ctx context.Context, options PlacementGroupCreateOptions, @@ -96,6 +100,7 @@ func (c *Client) CreatePlacementGroup( } // UpdatePlacementGroup updates a placement group with the specified ID using the provided options. +// NOTE: Placement Groups may not currently be available to all users. func (c *Client) UpdatePlacementGroup( ctx context.Context, id int, @@ -111,6 +116,7 @@ func (c *Client) UpdatePlacementGroup( // AssignPlacementGroupLinodes assigns the specified Linodes to the given // placement group. +// NOTE: Placement Groups may not currently be available to all users. func (c *Client) AssignPlacementGroupLinodes( ctx context.Context, id int, @@ -126,6 +132,7 @@ func (c *Client) AssignPlacementGroupLinodes( // UnassignPlacementGroupLinodes un-assigns the specified Linodes from the given // placement group. +// NOTE: Placement Groups may not currently be available to all users. func (c *Client) UnassignPlacementGroupLinodes( ctx context.Context, id int, @@ -140,6 +147,7 @@ func (c *Client) UnassignPlacementGroupLinodes( } // DeletePlacementGroup deletes a placement group with the specified ID. +// NOTE: Placement Groups may not currently be available to all users. func (c *Client) DeletePlacementGroup( ctx context.Context, id int, From 1acdbeb71c2767905bbe28ad9d8fb9f7acc67dee Mon Sep 17 00:00:00 2001 From: ErikZilber Date: Thu, 20 Jun 2024 10:52:16 -0400 Subject: [PATCH 6/6] Renamed capability consts (#529) --- regions.go | 50 +++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/regions.go b/regions.go index b68053b35..cecc8ea14 100644 --- a/regions.go +++ b/regions.go @@ -14,31 +14,31 @@ import ( // Defined as strings rather than a custom type to avoid breaking change. // Can be changed in the potential v2 version. const ( - Linodes string = "Linodes" - NodeBalancers string = "NodeBalancers" - BlockStorage string = "Block Storage" - ObjectStorage string = "Object Storage" - ObjectStorageRegions string = "Object Storage Access Key Regions" - LKE string = "Kubernetes" - LkeHaControlPlanes string = "LKE HA Control Planes" - CloudFirewall string = "Cloud Firewall" - GPU string = "GPU Linodes" - Vlans string = "Vlans" - VPCs string = "VPCs" - VPCsExtra string = "VPCs Extra" - MachineImages string = "Machine Images" - BareMetal string = "Bare Metal" - DBAAS string = "Managed Databases" - BlockStorageMigrations string = "Block Storage Migrations" - Metadata string = "Metadata" - PremiumPlans string = "Premium Plans" - EdgePlans string = "Edge Plans" - LKEControlPlaneACL string = "LKE Network Access Control List (IP ACL)" - ACLB string = "Akamai Cloud Load Balancer" - SupportTicketSeverity string = "Support Ticket Severity" - Backups string = "Backups" - PlacementGroup string = "Placement Group" - DiskEncryption string = "Disk Encryption" + CapabilityLinodes string = "Linodes" + CapabilityNodeBalancers string = "NodeBalancers" + CapabilityBlockStorage string = "Block Storage" + CapabilityObjectStorage string = "Object Storage" + CapabilityObjectStorageRegions string = "Object Storage Access Key Regions" + CapabilityLKE string = "Kubernetes" + CapabilityLkeHaControlPlanes string = "LKE HA Control Planes" + CapabilityCloudFirewall string = "Cloud Firewall" + CapabilityGPU string = "GPU Linodes" + CapabilityVlans string = "Vlans" + CapabilityVPCs string = "VPCs" + CapabilityVPCsExtra string = "VPCs Extra" + CapabilityMachineImages string = "Machine Images" + CapabilityBareMetal string = "Bare Metal" + CapabilityDBAAS string = "Managed Databases" + CapabilityBlockStorageMigrations string = "Block Storage Migrations" + CapabilityMetadata string = "Metadata" + CapabilityPremiumPlans string = "Premium Plans" + CapabilityEdgePlans string = "Edge Plans" + CapabilityLKEControlPlaneACL string = "LKE Network Access Control List (IP ACL)" + CapabilityACLB string = "Akamai Cloud Load Balancer" + CapabilitySupportTicketSeverity string = "Support Ticket Severity" + CapabilityBackups string = "Backups" + CapabilityPlacementGroup string = "Placement Group" + CapabilityDiskEncryption string = "Disk Encryption" ) // Region-related endpoints have a custom expiry time as the