From acd6936ba8926160b52276397478145f0e9080ce Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 5 Sep 2024 08:03:02 -0700 Subject: [PATCH 1/9] build(deps): bump golang.org/x/oauth2 from 0.22.0 to 0.23.0 (#574) * build(deps): bump golang.org/x/oauth2 from 0.22.0 to 0.23.0 Bumps [golang.org/x/oauth2](https://github.com/golang/oauth2) from 0.22.0 to 0.23.0. - [Commits](https://github.com/golang/oauth2/compare/v0.22.0...v0.23.0) --- updated-dependencies: - dependency-name: golang.org/x/oauth2 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Ran make tidy --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: ezilber-akamai --- go.mod | 2 +- go.sum | 4 ++-- k8s/go.mod | 2 +- k8s/go.sum | 4 ++-- test/go.mod | 2 +- test/go.sum | 4 ++-- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 2b4ef831..ab843153 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ require ( github.com/google/go-cmp v0.6.0 github.com/jarcoal/httpmock v1.3.1 golang.org/x/net v0.28.0 - golang.org/x/oauth2 v0.22.0 + golang.org/x/oauth2 v0.23.0 golang.org/x/text v0.17.0 gopkg.in/ini.v1 v1.66.6 ) diff --git a/go.sum b/go.sum index 7491ec6f..3e6284a7 100644 --- a/go.sum +++ b/go.sum @@ -28,8 +28,8 @@ golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= -golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA= -golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= +golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= diff --git a/k8s/go.mod b/k8s/go.mod index b9e7aa28..6a889d32 100644 --- a/k8s/go.mod +++ b/k8s/go.mod @@ -29,7 +29,7 @@ require ( github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/spf13/pflag v1.0.5 // indirect golang.org/x/net v0.28.0 // indirect - golang.org/x/oauth2 v0.22.0 // indirect + golang.org/x/oauth2 v0.23.0 // indirect golang.org/x/sys v0.23.0 // indirect golang.org/x/term v0.23.0 // indirect golang.org/x/text v0.17.0 // indirect diff --git a/k8s/go.sum b/k8s/go.sum index e240af74..f805c937 100644 --- a/k8s/go.sum +++ b/k8s/go.sum @@ -102,8 +102,8 @@ golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= -golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA= -golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= +golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= diff --git a/test/go.mod b/test/go.mod index c3b6dedb..316e5c93 100644 --- a/test/go.mod +++ b/test/go.mod @@ -8,7 +8,7 @@ require ( github.com/linode/linodego/k8s v0.0.0-00010101000000-000000000000 github.com/stretchr/testify v1.9.0 golang.org/x/net v0.28.0 - golang.org/x/oauth2 v0.22.0 + golang.org/x/oauth2 v0.23.0 k8s.io/client-go v0.29.4 ) diff --git a/test/go.sum b/test/go.sum index 96d01a52..12970593 100644 --- a/test/go.sum +++ b/test/go.sum @@ -107,8 +107,8 @@ golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= -golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA= -golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= +golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= From 881108aae7758985a7f99c67fab4772849f589de Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 5 Sep 2024 12:49:28 -0400 Subject: [PATCH 2/9] build(deps): bump golang.org/x/text from 0.17.0 to 0.18.0 (#575) * build(deps): bump golang.org/x/text from 0.17.0 to 0.18.0 Bumps [golang.org/x/text](https://github.com/golang/text) from 0.17.0 to 0.18.0. - [Release notes](https://github.com/golang/text/releases) - [Commits](https://github.com/golang/text/compare/v0.17.0...v0.18.0) --- updated-dependencies: - dependency-name: golang.org/x/text dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * make tidy --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Ye Chen --- go.mod | 2 +- go.sum | 4 ++-- k8s/go.mod | 2 +- k8s/go.sum | 4 ++-- test/go.mod | 2 +- test/go.sum | 4 ++-- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index ab843153..5d14b6bb 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/jarcoal/httpmock v1.3.1 golang.org/x/net v0.28.0 golang.org/x/oauth2 v0.23.0 - golang.org/x/text v0.17.0 + golang.org/x/text v0.18.0 gopkg.in/ini.v1 v1.66.6 ) diff --git a/go.sum b/go.sum index 3e6284a7..34fdd1af 100644 --- a/go.sum +++ b/go.sum @@ -55,8 +55,8 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= -golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/k8s/go.mod b/k8s/go.mod index 6a889d32..9675da00 100644 --- a/k8s/go.mod +++ b/k8s/go.mod @@ -32,7 +32,7 @@ require ( golang.org/x/oauth2 v0.23.0 // indirect golang.org/x/sys v0.23.0 // indirect golang.org/x/term v0.23.0 // indirect - golang.org/x/text v0.17.0 // indirect + golang.org/x/text v0.18.0 // indirect golang.org/x/time v0.5.0 // indirect google.golang.org/protobuf v1.33.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect diff --git a/k8s/go.sum b/k8s/go.sum index f805c937..b9158ed1 100644 --- a/k8s/go.sum +++ b/k8s/go.sum @@ -137,8 +137,8 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= -golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/test/go.mod b/test/go.mod index 316e5c93..c89aa65a 100644 --- a/test/go.mod +++ b/test/go.mod @@ -36,7 +36,7 @@ require ( github.com/spf13/pflag v1.0.5 // indirect golang.org/x/sys v0.23.0 // indirect golang.org/x/term v0.23.0 // indirect - golang.org/x/text v0.17.0 // indirect + golang.org/x/text v0.18.0 // indirect golang.org/x/time v0.5.0 // indirect google.golang.org/protobuf v1.33.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect diff --git a/test/go.sum b/test/go.sum index 12970593..969ec019 100644 --- a/test/go.sum +++ b/test/go.sum @@ -142,8 +142,8 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= -golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= From 890ff1e46064bab6a53d46ee795a6f40cece83f1 Mon Sep 17 00:00:00 2001 From: Lena Garber <114949949+lgarber-akamai@users.noreply.github.com> Date: Fri, 6 Sep 2024 15:15:20 -0400 Subject: [PATCH 3/9] new: Add support LKE, Volume, NodeBalancer, and network transfer pricing endpoints (#573) * Add LKE types endpoints * Support base struct; add NB types endpoints * Add volume types * Add network transfer prices * Add price and region price structs * Revert IPv6 fixtures * Add missing fixtures --- base_types.go | 29 ++++++++ lke_types.go | 47 +++++++++++++ network_transfer_prices.go | 45 ++++++++++++ nodebalancer_types.go | 45 ++++++++++++ .../fixtures/TestLKEType_List.yaml | 70 +++++++++++++++++++ .../TestNetworkTransferPrice_List.yaml | 70 +++++++++++++++++++ .../fixtures/TestNodeBalancerType_List.yaml | 68 ++++++++++++++++++ .../fixtures/TestVolumeType_List.yaml | 68 ++++++++++++++++++ test/integration/lke_types_test.go | 43 ++++++++++++ .../network_transfer_prices_test.go | 40 +++++++++++ test/integration/nodebalancer_types_test.go | 40 +++++++++++ test/integration/volume_types_test.go | 40 +++++++++++ volumes_types.go | 45 ++++++++++++ 13 files changed, 650 insertions(+) create mode 100644 base_types.go create mode 100644 lke_types.go create mode 100644 network_transfer_prices.go create mode 100644 nodebalancer_types.go create mode 100644 test/integration/fixtures/TestLKEType_List.yaml create mode 100644 test/integration/fixtures/TestNetworkTransferPrice_List.yaml create mode 100644 test/integration/fixtures/TestNodeBalancerType_List.yaml create mode 100644 test/integration/fixtures/TestVolumeType_List.yaml create mode 100644 test/integration/lke_types_test.go create mode 100644 test/integration/network_transfer_prices_test.go create mode 100644 test/integration/nodebalancer_types_test.go create mode 100644 test/integration/volume_types_test.go create mode 100644 volumes_types.go diff --git a/base_types.go b/base_types.go new file mode 100644 index 00000000..dbaafe31 --- /dev/null +++ b/base_types.go @@ -0,0 +1,29 @@ +// This package contains various type-related base classes intended +// to be used in composition across type structures in this project. + +package linodego + +// baseType is a base struct containing the core fields of a resource type +// returned from the Linode API. +type baseType[PriceType any, RegionPriceType any] struct { + ID string `json:"id"` + Label string `json:"label"` + Price PriceType `json:"price"` + RegionPrices []RegionPriceType `json:"region_prices"` + Transfer int `json:"transfer"` +} + +// baseTypePrice is a base struct containing the core fields of a resource type's +// base price. +type baseTypePrice struct { + Hourly float64 `json:"hourly"` + Monthly float64 `json:"monthly"` +} + +// baseTypeRegionPrice is a base struct containing the core fields of a resource type's +// region-specific price. +type baseTypeRegionPrice struct { + baseTypePrice + + ID string `json:"id"` +} diff --git a/lke_types.go b/lke_types.go new file mode 100644 index 00000000..14273bbd --- /dev/null +++ b/lke_types.go @@ -0,0 +1,47 @@ +package linodego + +import ( + "context" +) + +// LKEType represents a single valid LKE type. +// NOTE: This typically corresponds to the availability of a cluster's +// control plane. +type LKEType struct { + baseType[LKETypePrice, LKETypeRegionPrice] +} + +// LKETypePrice represents the base hourly and monthly prices +// for an LKE type entry. +type LKETypePrice struct { + baseTypePrice +} + +// LKETypeRegionPrice represents the regional hourly and monthly prices +// for an LKE type entry. +type LKETypeRegionPrice struct { + baseTypeRegionPrice +} + +// ListLKETypes lists LKE types. This endpoint is cached by default. +func (c *Client) ListLKETypes(ctx context.Context, opts *ListOptions) ([]LKEType, error) { + e := "lke/types" + + endpoint, err := generateListCacheURL(e, opts) + if err != nil { + return nil, err + } + + if result := c.getCachedResponse(endpoint); result != nil { + return result.([]LKEType), nil + } + + response, err := getPaginatedResults[LKEType](ctx, c, e, opts) + if err != nil { + return nil, err + } + + c.addCachedResponse(endpoint, response, &cacheExpiryTime) + + return response, nil +} diff --git a/network_transfer_prices.go b/network_transfer_prices.go new file mode 100644 index 00000000..daa25e88 --- /dev/null +++ b/network_transfer_prices.go @@ -0,0 +1,45 @@ +package linodego + +import ( + "context" +) + +// NetworkTransferPrice represents a single valid network transfer price. +type NetworkTransferPrice struct { + baseType[NetworkTransferTypePrice, NetworkTransferTypeRegionPrice] +} + +// NetworkTransferTypePrice represents the base hourly and monthly prices +// for a network transfer price entry. +type NetworkTransferTypePrice struct { + baseTypePrice +} + +// NetworkTransferTypeRegionPrice represents the regional hourly and monthly prices +// for a network transfer price entry. +type NetworkTransferTypeRegionPrice struct { + baseTypeRegionPrice +} + +// ListNetworkTransferPrices lists network transfer prices. This endpoint is cached by default. +func (c *Client) ListNetworkTransferPrices(ctx context.Context, opts *ListOptions) ([]NetworkTransferPrice, error) { + e := "network-transfer/prices" + + endpoint, err := generateListCacheURL(e, opts) + if err != nil { + return nil, err + } + + if result := c.getCachedResponse(endpoint); result != nil { + return result.([]NetworkTransferPrice), nil + } + + response, err := getPaginatedResults[NetworkTransferPrice](ctx, c, e, opts) + if err != nil { + return nil, err + } + + c.addCachedResponse(endpoint, response, &cacheExpiryTime) + + return response, nil +} diff --git a/nodebalancer_types.go b/nodebalancer_types.go new file mode 100644 index 00000000..879665d4 --- /dev/null +++ b/nodebalancer_types.go @@ -0,0 +1,45 @@ +package linodego + +import ( + "context" +) + +// NodeBalancerType represents a single valid NodeBalancer type. +type NodeBalancerType struct { + baseType[NodeBalancerTypePrice, NodeBalancerTypeRegionPrice] +} + +// NodeBalancerTypePrice represents the base hourly and monthly prices +// for a NodeBalancer type entry. +type NodeBalancerTypePrice struct { + baseTypePrice +} + +// NodeBalancerTypeRegionPrice represents the regional hourly and monthly prices +// for a NodeBalancer type entry. +type NodeBalancerTypeRegionPrice struct { + baseTypeRegionPrice +} + +// ListNodeBalancerTypes lists NodeBalancer types. This endpoint is cached by default. +func (c *Client) ListNodeBalancerTypes(ctx context.Context, opts *ListOptions) ([]NodeBalancerType, error) { + e := "nodebalancers/types" + + endpoint, err := generateListCacheURL(e, opts) + if err != nil { + return nil, err + } + + if result := c.getCachedResponse(endpoint); result != nil { + return result.([]NodeBalancerType), nil + } + + response, err := getPaginatedResults[NodeBalancerType](ctx, c, e, opts) + if err != nil { + return nil, err + } + + c.addCachedResponse(endpoint, response, &cacheExpiryTime) + + return response, nil +} diff --git a/test/integration/fixtures/TestLKEType_List.yaml b/test/integration/fixtures/TestLKEType_List.yaml new file mode 100644 index 00000000..8025faee --- /dev/null +++ b/test/integration/fixtures/TestLKEType_List.yaml @@ -0,0 +1,70 @@ +--- +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/lke/types?page=1 + method: GET + response: + body: '{"data": [{"id": "lke-sa", "label": "LKE Standard Availability", "price": + {"hourly": 0.0, "monthly": 0.0}, "region_prices": [], "transfer": 0}, {"id": + "lke-ha", "label": "LKE High Availability", "price": {"hourly": 0.09, "monthly": + 60.0}, "region_prices": [{"id": "id-cgk", "hourly": 0.108, "monthly": 72.0}, + {"id": "br-gru", "hourly": 0.126, "monthly": 84.0}], "transfer": 0}], "page": + 1, "pages": 1, "results": 2}' + 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "415" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Thu, 05 Sep 2024 17:47:57 GMT + Pragma: + - no-cache + 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/fixtures/TestNetworkTransferPrice_List.yaml b/test/integration/fixtures/TestNetworkTransferPrice_List.yaml new file mode 100644 index 00000000..6ac92925 --- /dev/null +++ b/test/integration/fixtures/TestNetworkTransferPrice_List.yaml @@ -0,0 +1,70 @@ +--- +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/network-transfer/prices?page=1 + method: GET + response: + body: '{"data": [{"id": "distributed_network_transfer", "label": "Distributed + Network Transfer", "price": {"hourly": 0.01, "monthly": null}, "region_prices": + [], "transfer": 0}, {"id": "network_transfer", "label": "Network Transfer", + "price": {"hourly": 0.005, "monthly": null}, "region_prices": [{"id": "id-cgk", + "hourly": 0.015, "monthly": null}, {"id": "br-gru", "hourly": 0.007, "monthly": + null}], "transfer": 0}], "page": 1, "pages": 1, "results": 2}' + 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "448" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Wed, 04 Sep 2024 18:06:01 GMT + Pragma: + - no-cache + 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/fixtures/TestNodeBalancerType_List.yaml b/test/integration/fixtures/TestNodeBalancerType_List.yaml new file mode 100644 index 00000000..e05e369b --- /dev/null +++ b/test/integration/fixtures/TestNodeBalancerType_List.yaml @@ -0,0 +1,68 @@ +--- +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/nodebalancers/types?page=1 + method: GET + response: + body: '{"data": [{"id": "nodebalancer", "label": "NodeBalancer", "price": {"hourly": + 0.015, "monthly": 10.0}, "region_prices": [{"id": "id-cgk", "hourly": 0.018, + "monthly": 12.0}, {"id": "br-gru", "hourly": 0.021, "monthly": 14.0}], "transfer": + 0}], "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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "279" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Wed, 04 Sep 2024 17:52:02 GMT + Pragma: + - no-cache + 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/fixtures/TestVolumeType_List.yaml b/test/integration/fixtures/TestVolumeType_List.yaml new file mode 100644 index 00000000..25e3c324 --- /dev/null +++ b/test/integration/fixtures/TestVolumeType_List.yaml @@ -0,0 +1,68 @@ +--- +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/volumes/types?page=1 + method: GET + response: + body: '{"data": [{"id": "volume", "label": "Storage Volume", "price": {"hourly": + 0.00015, "monthly": 0.1}, "region_prices": [{"id": "id-cgk", "hourly": 0.00018, + "monthly": 0.12}, {"id": "br-gru", "hourly": 0.00021, "monthly": 0.14}], "transfer": + 0}], "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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "280" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Wed, 04 Sep 2024 17:59:26 GMT + Pragma: + - no-cache + 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/lke_types_test.go b/test/integration/lke_types_test.go new file mode 100644 index 00000000..1095e9cd --- /dev/null +++ b/test/integration/lke_types_test.go @@ -0,0 +1,43 @@ +package integration + +import ( + "context" + "testing" + + "github.com/linode/linodego" + "github.com/stretchr/testify/require" +) + +func TestLKEType_List(t *testing.T) { + client, teardown := createTestClient(t, "fixtures/TestLKEType_List") + defer teardown() + + lkeTypes, err := client.ListLKETypes(context.Background(), nil) + require.NoError(t, err) + require.Greater(t, len(lkeTypes), 0) + + for _, lkeType := range lkeTypes { + validateLKEType(t, lkeType) + } +} + +func validateLKEType( + t *testing.T, + lkeType linodego.LKEType, +) { + require.NotEmpty(t, lkeType.ID) + require.NotEmpty(t, lkeType.Label) + + // NOTE: We use >= 0 here because this is treated as an additional + // cost on top of the base LKE cluster price, meaning SA has its + // prices set to 0. + require.GreaterOrEqual(t, lkeType.Price.Hourly, 0.0) + require.GreaterOrEqual(t, lkeType.Price.Monthly, 0.0) + require.GreaterOrEqual(t, lkeType.Transfer, 0) + + for _, regionPrice := range lkeType.RegionPrices { + require.NotEmpty(t, regionPrice.ID) + require.GreaterOrEqual(t, regionPrice.Hourly, 0.0) + require.GreaterOrEqual(t, regionPrice.Monthly, 0.0) + } +} diff --git a/test/integration/network_transfer_prices_test.go b/test/integration/network_transfer_prices_test.go new file mode 100644 index 00000000..641b7c4e --- /dev/null +++ b/test/integration/network_transfer_prices_test.go @@ -0,0 +1,40 @@ +package integration + +import ( + "context" + "testing" + + "github.com/linode/linodego" + "github.com/stretchr/testify/require" +) + +func TestNetworkTransferPrice_List(t *testing.T) { + client, teardown := createTestClient(t, "fixtures/TestNetworkTransferPrice_List") + defer teardown() + + prices, err := client.ListNetworkTransferPrices(context.Background(), nil) + require.NoError(t, err) + require.Greater(t, len(prices), 0) + + for _, price := range prices { + validateNetworkTransferPrice(t, price) + } +} + +func validateNetworkTransferPrice( + t *testing.T, + price linodego.NetworkTransferPrice, +) { + require.NotEmpty(t, price.ID) + require.NotEmpty(t, price.Label) + + // NOTE: We do not check for monthly prices here because it is + // explicitly set to null. + require.Greater(t, price.Price.Hourly, 0.0) + require.GreaterOrEqual(t, price.Transfer, 0) + + for _, regionPrice := range price.RegionPrices { + require.NotEmpty(t, regionPrice.ID) + require.Greater(t, regionPrice.Hourly, 0.0) + } +} diff --git a/test/integration/nodebalancer_types_test.go b/test/integration/nodebalancer_types_test.go new file mode 100644 index 00000000..f764e8e3 --- /dev/null +++ b/test/integration/nodebalancer_types_test.go @@ -0,0 +1,40 @@ +package integration + +import ( + "context" + "testing" + + "github.com/linode/linodego" + "github.com/stretchr/testify/require" +) + +func TestNodeBalancerType_List(t *testing.T) { + client, teardown := createTestClient(t, "fixtures/TestNodeBalancerType_List") + defer teardown() + + nbTypes, err := client.ListNodeBalancerTypes(context.Background(), nil) + require.NoError(t, err) + require.Greater(t, len(nbTypes), 0) + + for _, nbType := range nbTypes { + validateNodeBalancerType(t, nbType) + } +} + +func validateNodeBalancerType( + t *testing.T, + nbType linodego.NodeBalancerType, +) { + require.NotEmpty(t, nbType.ID) + require.NotEmpty(t, nbType.Label) + + require.Greater(t, nbType.Price.Hourly, 0.0) + require.Greater(t, nbType.Price.Monthly, 0.0) + require.GreaterOrEqual(t, nbType.Transfer, 0) + + for _, regionPrice := range nbType.RegionPrices { + require.NotEmpty(t, regionPrice.ID) + require.Greater(t, regionPrice.Hourly, 0.0) + require.Greater(t, regionPrice.Monthly, 0.0) + } +} diff --git a/test/integration/volume_types_test.go b/test/integration/volume_types_test.go new file mode 100644 index 00000000..919ac808 --- /dev/null +++ b/test/integration/volume_types_test.go @@ -0,0 +1,40 @@ +package integration + +import ( + "context" + "testing" + + "github.com/linode/linodego" + "github.com/stretchr/testify/require" +) + +func TestVolumeType_List(t *testing.T) { + client, teardown := createTestClient(t, "fixtures/TestVolumeType_List") + defer teardown() + + volumeTypes, err := client.ListVolumeTypes(context.Background(), nil) + require.NoError(t, err) + require.Greater(t, len(volumeTypes), 0) + + for _, volumeType := range volumeTypes { + validateVolumeType(t, volumeType) + } +} + +func validateVolumeType( + t *testing.T, + volumeType linodego.VolumeType, +) { + require.NotEmpty(t, volumeType.ID) + require.NotEmpty(t, volumeType.Label) + + require.Greater(t, volumeType.Price.Hourly, 0.0) + require.Greater(t, volumeType.Price.Monthly, 0.0) + require.GreaterOrEqual(t, volumeType.Transfer, 0) + + for _, regionPrice := range volumeType.RegionPrices { + require.NotEmpty(t, regionPrice.ID) + require.Greater(t, regionPrice.Hourly, 0.0) + require.Greater(t, regionPrice.Monthly, 0.0) + } +} diff --git a/volumes_types.go b/volumes_types.go new file mode 100644 index 00000000..887a3c5a --- /dev/null +++ b/volumes_types.go @@ -0,0 +1,45 @@ +package linodego + +import ( + "context" +) + +// VolumeType represents a single valid Volume type. +type VolumeType struct { + baseType[VolumeTypePrice, VolumeTypeRegionPrice] +} + +// VolumeTypePrice represents the base hourly and monthly prices +// for a volume type entry. +type VolumeTypePrice struct { + baseTypePrice +} + +// VolumeTypeRegionPrice represents the regional hourly and monthly prices +// for a volume type entry. +type VolumeTypeRegionPrice struct { + baseTypeRegionPrice +} + +// ListVolumeTypes lists Volume types. This endpoint is cached by default. +func (c *Client) ListVolumeTypes(ctx context.Context, opts *ListOptions) ([]VolumeType, error) { + e := "volumes/types" + + endpoint, err := generateListCacheURL(e, opts) + if err != nil { + return nil, err + } + + if result := c.getCachedResponse(endpoint); result != nil { + return result.([]VolumeType), nil + } + + response, err := getPaginatedResults[VolumeType](ctx, c, e, opts) + if err != nil { + return nil, err + } + + c.addCachedResponse(endpoint, response, &cacheExpiryTime) + + return response, nil +} From 108afdfe5cd4a83c3cb6d9b384a0470c182e14e5 Mon Sep 17 00:00:00 2001 From: AniJ98 Date: Tue, 17 Sep 2024 10:45:33 -0400 Subject: [PATCH 4/9] Support For Managing Reserved IP Addresses (#579) * added reserved field to InstanceIP struct for IP Reservation response * Reserved IP resource for handling IP reservation API's * Added integration test covering multiple scenarios of reserving IP addresses * The fixture files for different scenarios of IP Reservation - EndToEnd, InsuffecientPermission, ReserveIP, GetReservedIP, getReservedIPs, DeleteReservedIPs * Updated the fixture files with responses after the user has permissions to reserve IP * Changed the error message to relay invalid token for insufficient permission tests * Updated the error message for Insufficient Permission tests to display appropriate error message along with code * Made changes to Delete, List, Get, Reserve, EndtoEnd fixtures to record user with adequate permissions * changed variable name from id to address to keep it consistent with other functions * Made changes to variable names, achanged logf statements to errorf and fatalf wherever necessary * changed fixture file names to improve consistency, re-recorded fixtures with latest error messages * removed debugging fmt statement * Made changes to reserve IP addresses before listing them using fitler feature. Removed for loop to reserve IPs till limit is reached. * uncommenting unaffected tests * Made changes to error messages, added mandatory checks and re-recorded fixtures to reflect new error messages * Added new middleware system (#571) * build(deps): bump golang.org/x/oauth2 from 0.22.0 to 0.23.0 (#574) * build(deps): bump golang.org/x/oauth2 from 0.22.0 to 0.23.0 Bumps [golang.org/x/oauth2](https://github.com/golang/oauth2) from 0.22.0 to 0.23.0. - [Commits](https://github.com/golang/oauth2/compare/v0.22.0...v0.23.0) --- updated-dependencies: - dependency-name: golang.org/x/oauth2 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Ran make tidy --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: ezilber-akamai * build(deps): bump golang.org/x/text from 0.17.0 to 0.18.0 (#575) * build(deps): bump golang.org/x/text from 0.17.0 to 0.18.0 Bumps [golang.org/x/text](https://github.com/golang/text) from 0.17.0 to 0.18.0. - [Release notes](https://github.com/golang/text/releases) - [Commits](https://github.com/golang/text/compare/v0.17.0...v0.18.0) --- updated-dependencies: - dependency-name: golang.org/x/text dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * make tidy --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Ye Chen * new: Add support LKE, Volume, NodeBalancer, and network transfer pricing endpoints (#573) * Add LKE types endpoints * Support base struct; add NB types endpoints * Add volume types * Add network transfer prices * Add price and region price structs * Revert IPv6 fixtures * Add missing fixtures * Add test case for ip limit exceed * add cleanup for TestReservedIPAddresses_ExceedLimit * added interactions to fixture and changed the ecpected error message * Added note indicating feature is currently not available to all users --------- Signed-off-by: dependabot[bot] Co-authored-by: Erik Zilber Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Ye Chen Co-authored-by: Lena Garber <114949949+lgarber-akamai@users.noreply.github.com> Co-authored-by: ykim-1 --- instance_ips.go | 1 + network_reserved_ips.go | 54 +++ ...edIPAddresses_DeleteIPAddressVariants.yaml | 348 ++++++++++++++ .../TestReservedIPAddresses_EndToEndTest.yaml | 428 ++++++++++++++++++ .../TestReservedIPAddresses_ExceedLimit.yaml | 296 ++++++++++++ ...ervedIPAddresses_GetIPAddressVariants.yaml | 239 ++++++++++ ...edIPAddresses_InsufficientPermissions.yaml | 185 ++++++++ ...edIPAddresses_ListIPAddressesVariants.yaml | 321 +++++++++++++ ...ReservedIPAddresses_ReserveIPVariants.yaml | 383 ++++++++++++++++ test/integration/network_reserved_ips_test.go | 393 ++++++++++++++++ 10 files changed, 2648 insertions(+) create mode 100644 network_reserved_ips.go create mode 100644 test/integration/fixtures/TestReservedIPAddresses_DeleteIPAddressVariants.yaml create mode 100644 test/integration/fixtures/TestReservedIPAddresses_EndToEndTest.yaml create mode 100644 test/integration/fixtures/TestReservedIPAddresses_ExceedLimit.yaml create mode 100644 test/integration/fixtures/TestReservedIPAddresses_GetIPAddressVariants.yaml create mode 100644 test/integration/fixtures/TestReservedIPAddresses_InsufficientPermissions.yaml create mode 100644 test/integration/fixtures/TestReservedIPAddresses_ListIPAddressesVariants.yaml create mode 100644 test/integration/fixtures/TestReservedIPAddresses_ReserveIPVariants.yaml create mode 100644 test/integration/network_reserved_ips_test.go diff --git a/instance_ips.go b/instance_ips.go index 0d86bd91..568be05e 100644 --- a/instance_ips.go +++ b/instance_ips.go @@ -31,6 +31,7 @@ type InstanceIP struct { LinodeID int `json:"linode_id"` Region string `json:"region"` VPCNAT1To1 *InstanceIPNAT1To1 `json:"vpc_nat_1_1"` + Reserved bool `json:"reserved"` } // VPCIP represents a private IP address in a VPC subnet with additional networking details diff --git a/network_reserved_ips.go b/network_reserved_ips.go new file mode 100644 index 00000000..56f343f8 --- /dev/null +++ b/network_reserved_ips.go @@ -0,0 +1,54 @@ +package linodego + +import ( + "context" +) + +// ReserveIPOptions represents the options for reserving an IP address +// NOTE: Reserved IP feature may not currently be available to all users. +type ReserveIPOptions struct { + Region string `json:"region"` +} + +// ListReservedIPAddresses retrieves a list of reserved IP addresses +// NOTE: Reserved IP feature may not currently be available to all users. +func (c *Client) ListReservedIPAddresses(ctx context.Context, opts *ListOptions) ([]InstanceIP, error) { + e := formatAPIPath("networking/reserved/ips") + response, err := getPaginatedResults[InstanceIP](ctx, c, e, opts) + if err != nil { + return nil, err + } + + return response, nil +} + +// GetReservedIPAddress retrieves details of a specific reserved IP address +// NOTE: Reserved IP feature may not currently be available to all users. +func (c *Client) GetReservedIPAddress(ctx context.Context, ipAddress string) (*InstanceIP, error) { + e := formatAPIPath("networking/reserved/ips/%s", ipAddress) + response, err := doGETRequest[InstanceIP](ctx, c, e) + if err != nil { + return nil, err + } + + return response, nil +} + +// ReserveIPAddress reserves a new IP address +// NOTE: Reserved IP feature may not currently be available to all users. +func (c *Client) ReserveIPAddress(ctx context.Context, opts ReserveIPOptions) (*InstanceIP, error) { + e := "networking/reserved/ips" + response, err := doPOSTRequest[InstanceIP](ctx, c, e, opts) + if err != nil { + return nil, err + } + + return response, nil +} + +// DeleteReservedIPAddress deletes a reserved IP address +// NOTE: Reserved IP feature may not currently be available to all users. +func (c *Client) DeleteReservedIPAddress(ctx context.Context, ipAddress string) error { + e := formatAPIPath("networking/reserved/ips/%s", ipAddress) + return doDELETERequest(ctx, c, e) +} diff --git a/test/integration/fixtures/TestReservedIPAddresses_DeleteIPAddressVariants.yaml b/test/integration/fixtures/TestReservedIPAddresses_DeleteIPAddressVariants.yaml new file mode 100644 index 00000000..a033a961 --- /dev/null +++ b/test/integration/fixtures/TestReservedIPAddresses_DeleteIPAddressVariants.yaml @@ -0,0 +1,348 @@ +--- +version: 1 +interactions: +- request: + body: '{"region":"us-east"}' + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - linodego/dev https://github.com/linode/linodego + url: https://api.linode.com/v4beta/networking/reserved/ips + method: POST + response: + body: '{"address": "66.175.209.178", "gateway": "66.175.209.1", "subnet_mask": + "255.255.255.0", "prefix": 24, "type": "ipv4", "public": true, "rdns": "66-175-209-178.ip.linodeusercontent.com", + "linode_id": null, "region": "us-east", "vpc_nat_1_1": null, "reserved": 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "264" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Thu, 05 Sep 2024 17:52:50 GMT + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - ips: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/networking/reserved/ips?page=1 + method: GET + response: + body: '{"data": [{"address": "66.175.209.178", "gateway": "66.175.209.1", "subnet_mask": + "255.255.255.0", "prefix": 24, "type": "ipv4", "public": true, "rdns": "66-175-209-178.ip.linodeusercontent.com", + "linode_id": null, "region": "us-east", "vpc_nat_1_1": null, "reserved": true}], + "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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "313" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Thu, 05 Sep 2024 17:52:50 GMT + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - ips:read_only + 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/networking/reserved/ips/66.175.209.178 + 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "2" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Thu, 05 Sep 2024 17:52:50 GMT + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - ips: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/networking/reserved/ips?page=1 + method: GET + response: + body: '{"data": [], "page": 1, "pages": 1, "results": 0}' + 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "49" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Thu, 05 Sep 2024 17:52:50 GMT + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - ips:read_only + 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/networking/reserved/ips/66.175.209.178 + method: GET + response: + body: '{"errors": [{"reason": "Not found"}]}' + headers: + 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: + - '*' + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "37" + Content-Type: + - application/json + Expires: + - Thu, 05 Sep 2024 17:52:51 GMT + Pragma: + - no-cache + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - ips:read_only + X-Frame-Options: + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "10" + status: 404 Not Found + code: 404 + 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/networking/reserved/ips/255.255.255.4 + method: DELETE + response: + body: '{"errors": [{"reason": "Not found"}]}' + headers: + 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: + - '*' + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "37" + Content-Type: + - application/json + Expires: + - Thu, 05 Sep 2024 17:52:51 GMT + Pragma: + - no-cache + X-Accepted-Oauth-Scopes: + - ips:read_write + X-Frame-Options: + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "10" + status: 404 Not Found + code: 404 + duration: "" diff --git a/test/integration/fixtures/TestReservedIPAddresses_EndToEndTest.yaml b/test/integration/fixtures/TestReservedIPAddresses_EndToEndTest.yaml new file mode 100644 index 00000000..1dcbe2b2 --- /dev/null +++ b/test/integration/fixtures/TestReservedIPAddresses_EndToEndTest.yaml @@ -0,0 +1,428 @@ +--- +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/networking/reserved/ips?page=1 + method: GET + response: + body: '{"data": [], "page": 1, "pages": 1, "results": 0}' + 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "49" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Thu, 05 Sep 2024 17:52:47 GMT + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - ips:read_only + 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: '{"region":"us-east"}' + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - linodego/dev https://github.com/linode/linodego + url: https://api.linode.com/v4beta/networking/reserved/ips + method: POST + response: + body: '{"address": "66.175.209.178", "gateway": "66.175.209.1", "subnet_mask": + "255.255.255.0", "prefix": 24, "type": "ipv4", "public": true, "rdns": "66-175-209-178.ip.linodeusercontent.com", + "linode_id": null, "region": "us-east", "vpc_nat_1_1": null, "reserved": 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "264" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Thu, 05 Sep 2024 17:52:48 GMT + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - ips: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/networking/reserved/ips/66.175.209.178 + method: GET + response: + body: '{"address": "66.175.209.178", "gateway": "66.175.209.1", "subnet_mask": + "255.255.255.0", "prefix": 24, "type": "ipv4", "public": true, "rdns": "66-175-209-178.ip.linodeusercontent.com", + "linode_id": null, "region": "us-east", "vpc_nat_1_1": null, "reserved": 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "264" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Thu, 05 Sep 2024 17:52:48 GMT + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - ips:read_only + 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/networking/reserved/ips?page=1 + method: GET + response: + body: '{"data": [{"address": "66.175.209.178", "gateway": "66.175.209.1", "subnet_mask": + "255.255.255.0", "prefix": 24, "type": "ipv4", "public": true, "rdns": "66-175-209-178.ip.linodeusercontent.com", + "linode_id": null, "region": "us-east", "vpc_nat_1_1": null, "reserved": true}], + "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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "313" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Thu, 05 Sep 2024 17:52:48 GMT + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - ips:read_only + 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/networking/reserved/ips/66.175.209.178 + 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "2" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Thu, 05 Sep 2024 17:52:49 GMT + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - ips: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/networking/reserved/ips/66.175.209.178 + method: GET + response: + body: '{"errors": [{"reason": "Not found"}]}' + headers: + 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: + - '*' + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "37" + Content-Type: + - application/json + Expires: + - Thu, 05 Sep 2024 17:52:49 GMT + Pragma: + - no-cache + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - ips:read_only + X-Frame-Options: + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "10" + status: 404 Not Found + code: 404 + 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/networking/reserved/ips?page=1 + method: GET + response: + body: '{"data": [], "page": 1, "pages": 1, "results": 0}' + 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "49" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Thu, 05 Sep 2024 17:52:49 GMT + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - ips:read_only + 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: "" diff --git a/test/integration/fixtures/TestReservedIPAddresses_ExceedLimit.yaml b/test/integration/fixtures/TestReservedIPAddresses_ExceedLimit.yaml new file mode 100644 index 00000000..57449d24 --- /dev/null +++ b/test/integration/fixtures/TestReservedIPAddresses_ExceedLimit.yaml @@ -0,0 +1,296 @@ +--- +version: 1 +interactions: +- request: + body: '{"region":"us-east"}' + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - linodego/dev https://github.com/linode/linodego + url: https://api.linode.com/v4beta/networking/reserved/ips + method: POST + response: + body: '{"address": "69.164.208.243", "gateway": "69.164.208.1", "subnet_mask": + "255.255.255.0", "prefix": 24, "type": "ipv4", "public": true, "rdns": "69-164-208-243.ip.linodeusercontent.com", + "linode_id": null, "region": "us-east", "vpc_nat_1_1": null, "reserved": 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "264" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Mon, 16 Sep 2024 17:00:22 GMT + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - ips:read_write + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "800" + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: '{"region":"us-east"}' + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - linodego/dev https://github.com/linode/linodego + url: https://api.linode.com/v4beta/networking/reserved/ips + method: POST + response: + body: '{"address": "45.79.130.88", "gateway": "45.79.130.1", "subnet_mask": "255.255.255.0", + "prefix": 24, "type": "ipv4", "public": true, "rdns": "45-79-130-88.ip.linodeusercontent.com", + "linode_id": null, "region": "us-east", "vpc_nat_1_1": null, "reserved": 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "259" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Mon, 16 Sep 2024 17:00:22 GMT + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - ips:read_write + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "800" + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: '{"region":"us-east"}' + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - linodego/dev https://github.com/linode/linodego + url: https://api.linode.com/v4beta/networking/reserved/ips + method: POST + response: + body: '{"errors": [{"reason": "Additional Reserved IPv4 addresses require technical + justification. Please contact support describing your requirement."}]}' + headers: + 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: + - '*' + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Content-Length: + - "147" + Content-Type: + - application/json + Expires: + - Mon, 16 Sep 2024 17:00:22 GMT + Pragma: + - no-cache + X-Accepted-Oauth-Scopes: + - ips:read_write + X-Frame-Options: + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "800" + status: 400 Bad Request + code: 400 + 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/networking/reserved/ips/69.164.208.243 + 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "2" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Mon, 16 Sep 2024 17:00:22 GMT + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - ips: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/networking/reserved/ips/45.79.130.88 + 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "2" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Mon, 16 Sep 2024 17:00:23 GMT + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - ips: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: "" diff --git a/test/integration/fixtures/TestReservedIPAddresses_GetIPAddressVariants.yaml b/test/integration/fixtures/TestReservedIPAddresses_GetIPAddressVariants.yaml new file mode 100644 index 00000000..6a4bf9cd --- /dev/null +++ b/test/integration/fixtures/TestReservedIPAddresses_GetIPAddressVariants.yaml @@ -0,0 +1,239 @@ +--- +version: 1 +interactions: +- request: + body: '{"region":"us-east"}' + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - linodego/dev https://github.com/linode/linodego + url: https://api.linode.com/v4beta/networking/reserved/ips + method: POST + response: + body: '{"address": "45.56.109.241", "gateway": "45.56.109.1", "subnet_mask": "255.255.255.0", + "prefix": 24, "type": "ipv4", "public": true, "rdns": "45-56-109-241.ip.linodeusercontent.com", + "linode_id": null, "region": "us-east", "vpc_nat_1_1": null, "reserved": 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "261" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Thu, 29 Aug 2024 15:39:20 GMT + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - ips: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/networking/reserved/ips/45.56.109.241 + method: GET + response: + body: '{"address": "45.56.109.241", "gateway": "45.56.109.1", "subnet_mask": "255.255.255.0", + "prefix": 24, "type": "ipv4", "public": true, "rdns": "45-56-109-241.ip.linodeusercontent.com", + "linode_id": null, "region": "us-east", "vpc_nat_1_1": null, "reserved": 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "261" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Thu, 29 Aug 2024 15:39:20 GMT + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - ips:read_only + 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/networking/reserved/ips/999.999.999.999 + method: GET + response: + body: '{"errors": [{"reason": "Not found"}]}' + headers: + 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: + - '*' + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "37" + Content-Type: + - application/json + Expires: + - Thu, 29 Aug 2024 15:39:20 GMT + Pragma: + - no-cache + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - ips:read_only + X-Frame-Options: + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "10" + status: 404 Not Found + code: 404 + 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/networking/reserved/ips/45.56.109.241 + 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "2" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Thu, 29 Aug 2024 15:39:21 GMT + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - ips: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: "" diff --git a/test/integration/fixtures/TestReservedIPAddresses_InsufficientPermissions.yaml b/test/integration/fixtures/TestReservedIPAddresses_InsufficientPermissions.yaml new file mode 100644 index 00000000..764d3ac0 --- /dev/null +++ b/test/integration/fixtures/TestReservedIPAddresses_InsufficientPermissions.yaml @@ -0,0 +1,185 @@ +--- +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/networking/reserved/ips?page=1 + method: GET + response: + body: '{"errors": [{"reason": "Account doesn''t have permission to access the + ''Reserved IPs'' feature."}]}' + headers: + 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: + - '*' + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "97" + Content-Type: + - application/json + Expires: + - Thu, 22 Aug 2024 15:37:02 GMT + Pragma: + - no-cache + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - ips:read_only + X-Frame-Options: + - DENY + X-Oauth-Scopes: + - '*' + status: 404 Not Found + code: 404 + duration: "" +- request: + body: '{"region":"us-east"}' + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - linodego/dev https://github.com/linode/linodego + url: https://api.linode.com/v4beta/networking/reserved/ips + method: POST + response: + body: '{"errors": [{"reason": "Account doesn''t have permission to access the + ''Reserved IPs'' feature."}]}' + headers: + 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: + - '*' + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Content-Length: + - "97" + Content-Type: + - application/json + Expires: + - Thu, 22 Aug 2024 15:37:02 GMT + Pragma: + - no-cache + X-Accepted-Oauth-Scopes: + - ips:read_write + X-Frame-Options: + - DENY + X-Oauth-Scopes: + - '*' + status: 404 Not Found + code: 404 + 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/networking/reserved/ips/172.28.3.4 + method: GET + response: + body: '{"errors": [{"reason": "Account doesn''t have permission to access the + ''Reserved IPs'' feature."}]}' + headers: + 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: + - '*' + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "97" + Content-Type: + - application/json + Expires: + - Thu, 22 Aug 2024 15:37:03 GMT + Pragma: + - no-cache + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - ips:read_only + X-Frame-Options: + - DENY + X-Oauth-Scopes: + - '*' + status: 404 Not Found + code: 404 + 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/networking/reserved/ips/172.28.3.4 + method: DELETE + response: + body: '{"errors": [{"reason": "Account doesn''t have permission to access the + ''Reserved IPs'' feature."}]}' + headers: + 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: + - '*' + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "97" + Content-Type: + - application/json + Expires: + - Thu, 22 Aug 2024 15:37:03 GMT + Pragma: + - no-cache + X-Accepted-Oauth-Scopes: + - ips:read_write + X-Frame-Options: + - DENY + X-Oauth-Scopes: + - '*' + status: 404 Not Found + code: 404 + duration: "" diff --git a/test/integration/fixtures/TestReservedIPAddresses_ListIPAddressesVariants.yaml b/test/integration/fixtures/TestReservedIPAddresses_ListIPAddressesVariants.yaml new file mode 100644 index 00000000..bffe1222 --- /dev/null +++ b/test/integration/fixtures/TestReservedIPAddresses_ListIPAddressesVariants.yaml @@ -0,0 +1,321 @@ +--- +version: 1 +interactions: +- request: + body: '{"region":"us-east"}' + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - linodego/dev https://github.com/linode/linodego + url: https://api.linode.com/v4beta/networking/reserved/ips + method: POST + response: + body: '{"address": "66.175.209.108", "gateway": "66.175.209.1", "subnet_mask": + "255.255.255.0", "prefix": 24, "type": "ipv4", "public": true, "rdns": "66-175-209-108.ip.linodeusercontent.com", + "linode_id": null, "region": "us-east", "vpc_nat_1_1": null, "reserved": 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "264" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Thu, 05 Sep 2024 17:52:49 GMT + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - ips: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":"us-east"}' + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - linodego/dev https://github.com/linode/linodego + url: https://api.linode.com/v4beta/networking/reserved/ips + method: POST + response: + body: '{"address": "66.175.209.141", "gateway": "66.175.209.1", "subnet_mask": + "255.255.255.0", "prefix": 24, "type": "ipv4", "public": true, "rdns": "66-175-209-141.ip.linodeusercontent.com", + "linode_id": null, "region": "us-east", "vpc_nat_1_1": null, "reserved": 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "264" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Thu, 05 Sep 2024 17:52:49 GMT + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - ips: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 + X-Filter: + - '{"reserved":true,"region":"us-east"}' + url: https://api.linode.com/v4beta/networking/ips?page=1 + method: GET + response: + body: '{"page": 1, "pages": 1, "results": 2, "data": [{"address": "66.175.209.108", + "gateway": "66.175.209.1", "subnet_mask": "255.255.255.0", "prefix": 24, "type": + "ipv4", "public": true, "rdns": "66-175-209-108.ip.linodeusercontent.com", "linode_id": + null, "region": "us-east", "vpc_nat_1_1": null, "reserved": true}, {"address": + "66.175.209.141", "gateway": "66.175.209.1", "subnet_mask": "255.255.255.0", + "prefix": 24, "type": "ipv4", "public": true, "rdns": "66-175-209-141.ip.linodeusercontent.com", + "linode_id": null, "region": "us-east", "vpc_nat_1_1": null, "reserved": 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "579" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Thu, 05 Sep 2024 17:52:49 GMT + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - ips: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/networking/reserved/ips/66.175.209.108 + 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "2" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Thu, 05 Sep 2024 17:52:50 GMT + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - ips: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/networking/reserved/ips/66.175.209.141 + 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "2" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Thu, 05 Sep 2024 17:52:50 GMT + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - ips: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: "" diff --git a/test/integration/fixtures/TestReservedIPAddresses_ReserveIPVariants.yaml b/test/integration/fixtures/TestReservedIPAddresses_ReserveIPVariants.yaml new file mode 100644 index 00000000..2ff00f7a --- /dev/null +++ b/test/integration/fixtures/TestReservedIPAddresses_ReserveIPVariants.yaml @@ -0,0 +1,383 @@ +--- +version: 1 +interactions: +- request: + body: '{"region":""}' + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - linodego/dev https://github.com/linode/linodego + url: https://api.linode.com/v4beta/networking/reserved/ips + method: POST + response: + body: '{"errors": [{"reason": "region is not valid", "field": "region"}]}' + headers: + 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: + - '*' + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Content-Length: + - "66" + Content-Type: + - application/json + Expires: + - Mon, 16 Sep 2024 17:00:20 GMT + Pragma: + - no-cache + X-Accepted-Oauth-Scopes: + - ips:read_write + X-Frame-Options: + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "800" + status: 400 Bad Request + code: 400 + duration: "" +- request: + body: '{"region":"us"}' + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - linodego/dev https://github.com/linode/linodego + url: https://api.linode.com/v4beta/networking/reserved/ips + method: POST + response: + body: '{"errors": [{"reason": "region is not valid", "field": "region"}]}' + headers: + 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: + - '*' + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Content-Length: + - "66" + Content-Type: + - application/json + Expires: + - Mon, 16 Sep 2024 17:00:20 GMT + Pragma: + - no-cache + X-Accepted-Oauth-Scopes: + - ips:read_write + X-Frame-Options: + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "800" + status: 400 Bad Request + code: 400 + duration: "" +- request: + body: '{"region":""}' + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - linodego/dev https://github.com/linode/linodego + url: https://api.linode.com/v4beta/networking/reserved/ips + method: POST + response: + body: '{"errors": [{"reason": "region is not valid", "field": "region"}]}' + headers: + 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: + - '*' + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Content-Length: + - "66" + Content-Type: + - application/json + Expires: + - Mon, 16 Sep 2024 17:00:20 GMT + Pragma: + - no-cache + X-Accepted-Oauth-Scopes: + - ips:read_write + X-Frame-Options: + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "800" + status: 400 Bad Request + code: 400 + duration: "" +- request: + body: '{"region":"us-east"}' + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - linodego/dev https://github.com/linode/linodego + url: https://api.linode.com/v4beta/networking/reserved/ips + method: POST + response: + body: '{"address": "69.164.208.243", "gateway": "69.164.208.1", "subnet_mask": + "255.255.255.0", "prefix": 24, "type": "ipv4", "public": true, "rdns": "69-164-208-243.ip.linodeusercontent.com", + "linode_id": null, "region": "us-east", "vpc_nat_1_1": null, "reserved": 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "264" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Mon, 16 Sep 2024 17:00:21 GMT + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - ips:read_write + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "800" + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: '{"region":"us-east"}' + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - linodego/dev https://github.com/linode/linodego + url: https://api.linode.com/v4beta/networking/reserved/ips + method: POST + response: + body: '{"address": "45.79.130.88", "gateway": "45.79.130.1", "subnet_mask": "255.255.255.0", + "prefix": 24, "type": "ipv4", "public": true, "rdns": "45-79-130-88.ip.linodeusercontent.com", + "linode_id": null, "region": "us-east", "vpc_nat_1_1": null, "reserved": 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "259" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Mon, 16 Sep 2024 17:00:21 GMT + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - ips:read_write + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "800" + 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/networking/reserved/ips/69.164.208.243 + 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "2" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Mon, 16 Sep 2024 17:00:21 GMT + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - ips: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/networking/reserved/ips/45.79.130.88 + 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "2" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Mon, 16 Sep 2024 17:00:21 GMT + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - ips: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: "" diff --git a/test/integration/network_reserved_ips_test.go b/test/integration/network_reserved_ips_test.go new file mode 100644 index 00000000..a9b8c8b8 --- /dev/null +++ b/test/integration/network_reserved_ips_test.go @@ -0,0 +1,393 @@ +package integration + +import ( + "context" + "strings" + + "testing" + + "github.com/linode/linodego" + . "github.com/linode/linodego" +) + +// TestReservedIPAddresses_InsufficientPermissions tests the behavior when a user account +// doesn't have the permission to use the Reserved IP feature +func TestReservedIPAddresses_InsufficientPermissions(t *testing.T) { + original := validTestAPIKey + dummyToken := "badtoken" + validTestAPIKey = dummyToken + + client, teardown := createTestClient(t, "fixtures/TestReservedIPAddresses_InsufficientPermissions") + defer teardown() + defer func() { validTestAPIKey = original }() + + filter := "" + ips, listErr := client.ListReservedIPAddresses(context.Background(), NewListOptions(0, filter)) + if listErr == nil { + t.Errorf("Expected error due to insufficient permissions, but got none %v", ips) + } else { + t.Logf("Correctly received error when listing IP addresses: %v", listErr) + } + + if len(ips) != 0 { + t.Errorf("Expected no IP addresses due to insufficient permissions, but got some: %v", ips) + } + + // Attempt to reserve an IP address + resIP, resErr := client.ReserveIPAddress(context.Background(), ReserveIPOptions{ + Region: "us-east", + }) + if resErr == nil { + t.Errorf("Expected error when reserving IP due to insufficient permissions, but got none") + } else { + t.Logf("Correctly received %v and error when reserving IP: %v", resIP, resErr) + } + + // Attempt to get a reserved IP address + address := "172.28.3.4" + ip, getErr := client.GetReservedIPAddress(context.Background(), address) + if getErr == nil { + t.Errorf("Expected error when getting IP address due to insufficient permissions, but got none") + } else { + t.Logf("Correctly received %v for IP Address and error when getting IP address: %v", ip, getErr) + } + + // Attempt to delete a reserved IP address + delAddr := "172.28.3.4" + delErr := client.DeleteReservedIPAddress(context.Background(), delAddr) + if delErr == nil { + t.Errorf("Expected error when deleting IP address due to insufficient permissions, but got none") + } else { + t.Logf("Correctly received error when deleting IP address: %v", delErr) + } +} + +// TestReservedIPAddresses_EndToEndTest performs an end-to-end test of the Reserved IP functionality +// for users with the can_reserve_ip flag enabled +func TestReservedIPAddresses_EndToEndTest(t *testing.T) { + client, teardown := createTestClient(t, "fixtures/TestReservedIPAddresses_EndToEndTest") + defer teardown() + + filter := "" + + ipList, err := client.ListReservedIPAddresses(context.Background(), NewListOptions(0, filter)) + + if err != nil { + t.Fatalf("Error listing IP addresses: %v", err) + } + + initialCount := len(ipList) + + // Attempt to reserve an IP + resIP, resErr := client.ReserveIPAddress(context.Background(), ReserveIPOptions{ + Region: "us-east", + }) + + if resErr != nil { + t.Fatalf("Failed to reserve IP. This test expects the user to have 0 prior reservations and the ip_reservation_limit to be 2. Error from the API: %v", resErr) + } + + t.Logf("Successfully reserved IP: %+v", resIP) + + // Fetch the reserved IP + fetchedIP, fetchErr := client.GetReservedIPAddress(context.Background(), resIP.Address) + if fetchErr != nil { + t.Errorf("Error getting reserved IP address: %v", fetchErr) + } + + if fetchedIP == nil { + t.Errorf("Expected %s but got nil indicating a failure in fetching the reserved IP", resIP.Address) + } + + // Verify the list of IPs has increased + verifyList, verifyErr := client.ListReservedIPAddresses(context.Background(), NewListOptions(0, filter)) + if verifyErr != nil { + t.Fatalf("Error listing IP addresses after reservation: %v", verifyErr) + } + + if len(verifyList) != initialCount+1 { + t.Errorf("Expected IP count to increase by 1, got %d, want %d", len(verifyList), initialCount+1) + } + + // Delete the reserved IP + delErr := client.DeleteReservedIPAddress(context.Background(), resIP.Address) + if delErr != nil { + t.Fatalf("Error deleting reserved IP address: %v", delErr) + } + + // Verify the IP has been deleted + _, fetchDelErr := client.GetReservedIPAddress(context.Background(), resIP.Address) + if fetchDelErr == nil { + t.Errorf("Expected error when fetching %s, got nil", resIP.Address) + } + + verifyDelList, verifyDelErr := client.ListReservedIPAddresses(context.Background(), NewListOptions(0, filter)) + if verifyDelErr != nil { + t.Fatalf("Error listing IP addresses after deletion: %v", verifyDelErr) + } + + if len(verifyDelList) != initialCount { + t.Errorf("Expected IP count to return to initial count, got %d, want %d", len(verifyDelList), initialCount) + } +} + +// TestReservedIPAddresses_ListIPAddressesVariants tests filters for listing IP addresses +func TestReservedIPAddresses_ListIPAddressesVariants(t *testing.T) { + client, teardown := createTestClient(t, "fixtures/TestReservedIPAddresses_ListIPAddressesVariants") + defer teardown() + + expected_ips := 2 + + // Reserve two IP addresses in us-east region + reservedIPs := make([]string, expected_ips) + for i := 0; i < expected_ips; i++ { + reserveIP, err := client.ReserveIPAddress(context.Background(), linodego.ReserveIPOptions{ + Region: "us-east", + }) + if err != nil { + t.Fatalf("Failed to reserve IP %d: %v", i+1, err) + } + reservedIPs[i] = reserveIP.Address + t.Logf("Successfully reserved IP %d: %s", i+1, reserveIP.Address) + } + + // Defer cleanup of reserved IPs + defer func() { + for _, ip := range reservedIPs { + err := client.DeleteReservedIPAddress(context.Background(), ip) + if err != nil { + t.Errorf("Failed to delete reserved IP %s: %v", ip, err) + } + } + }() + + // Create ListOptions with the filter for reserved IPs in us-east region + listOptions := linodego.ListOptions{ + PageOptions: &linodego.PageOptions{ + Page: 0, + }, + Filter: "{\"reserved\":true,\"region\":\"us-east\"}", + } + + ipList, err := client.ListIPAddresses(context.Background(), &listOptions) + + if err != nil { + t.Fatalf("Error listing reserved IP addresses in us-east: %v", err) + } + + t.Logf("Retrieved %d reserved IP addresses in us-east", len(ipList)) + + // Check if at least the two reserved IPs are in the list + foundReservedIPs := 0 + for _, ip := range ipList { + if !ip.Reserved { + t.Errorf("Expected all IPs to be reserved, but found non-reserved IP: %s", ip.Address) + } + if ip.Region != "us-east" { + t.Errorf("Expected all IPs to be in us-east region, but found IP in %s region: %s", ip.Region, ip.Address) + } + for _, reservedIP := range reservedIPs { + if ip.Address == reservedIP { + foundReservedIPs++ + break + } + } + } + if foundReservedIPs != expected_ips { + t.Errorf("Expected %d but found %d while listing reserved IP addresses", expected_ips, foundReservedIPs) + } + +} + +// TestReservedIPAddresses_GetIPAddressVariants tests various scenarios for getting a specific IP address +func TestReservedIPAddresses_GetIPAddressVariants(t *testing.T) { + client, teardown := createTestClient(t, "fixtures/TestReservedIPAddresses_GetIPAddressVariants") + defer teardown() + + // Reserve an IP for testing + resIP, resErr := client.ReserveIPAddress(context.Background(), ReserveIPOptions{ + Region: "us-east", + }) + + if resErr != nil { + t.Fatalf("Failed to reserve IP. This test expects the user to have 0 prior reservations and the ip_reservation_limit to be 2. Error from the API: %v", resErr) + } + + if resIP == nil { + t.Fatalf("Reserved IP is nil") + } + + t.Logf("Successfully reserved IP: %+v", resIP) + + // Test getting a valid reserved IP + validIP, fetchErr := client.GetReservedIPAddress(context.Background(), resIP.Address) + if fetchErr != nil { + t.Errorf("Error getting valid reserved IP address: %v", fetchErr) + } + + if validIP == nil { + t.Errorf("Retrieved valid reserved IP is nil") + } else { + if validIP.Address != resIP.Address { + t.Errorf("Retrieved IP address does not match reserved IP address. Got %s, want %s", validIP.Address, resIP.Address) + } + } + + // Test getting an invalid IP + invalidIP := "999.999.999.999" + _, invalidFetchErr := client.GetReservedIPAddress(context.Background(), invalidIP) + if invalidFetchErr == nil { + t.Errorf("Expected error when fetching invalid IP, got nil") + } + + // Clean up: Delete the reserved IP + delErr := client.DeleteReservedIPAddress(context.Background(), resIP.Address) + if delErr != nil { + t.Errorf("Failed to delete reserved IP: %v", delErr) + } +} + +// TestReservedIPAddresses_ReserveIPVariants tests various scenarios for reserving an IP address +func TestReservedIPAddresses_ReserveIPAddressVariants(t *testing.T) { + client, teardown := createTestClient(t, "fixtures/TestReservedIPAddresses_ReserveIPVariants") + defer teardown() + + // Slice to keep track of all reserved IPs + var reservedIPs []string + + // Helper function to clean up reserved IPs + cleanupIPs := func() { + for _, ip := range reservedIPs { + err := client.DeleteReservedIPAddress(context.Background(), ip) + if err != nil { + t.Errorf("Failed to delete reserved IP %s: %v", ip, err) + } + } + } + defer cleanupIPs() + + // Test reserving IP with omitted region + _, omitErr := client.ReserveIPAddress(context.Background(), ReserveIPOptions{}) + if omitErr == nil { + t.Errorf("Expected error when reserving IP with omitted region, got nil") + } + + // Test reserving IP with invalid region + _, invalidErr := client.ReserveIPAddress(context.Background(), ReserveIPOptions{Region: "us"}) + if invalidErr == nil { + t.Errorf("Expected error when reserving IP with invalid region, got nil") + } + + // Test reserving IP with empty region + _, emptyErr := client.ReserveIPAddress(context.Background(), ReserveIPOptions{Region: ""}) + if emptyErr == nil { + t.Errorf("Expected error when reserving IP with empty region, got nil") + } + + // Make 2 valid IP Reservations + for i := 0; i < 2; i++ { + reserveIP, err := client.ReserveIPAddress(context.Background(), linodego.ReserveIPOptions{ + Region: "us-east", + }) + if err != nil { + t.Fatalf("Failed to reserve IP %d: %v", i+1, err) + } + reservedIPs = append(reservedIPs, reserveIP.Address) + t.Logf("Successfully reserved IP %d: %s", i+1, reserveIP.Address) + } +} + +func TestReservedIPAddresses_ExceedLimit(t *testing.T) { + client, teardown := createTestClient(t, "fixtures/TestReservedIPAddresses_ExceedLimit") + defer teardown() + + // Slice to keep track of all reserved IPs + var reservedIPs []string + + // Helper function to clean up reserved IPs + cleanupIPs := func() { + for _, ip := range reservedIPs { + err := client.DeleteReservedIPAddress(context.Background(), ip) + if err != nil { + t.Errorf("Failed to delete reserved IP %s: %v", ip, err) + } + } + } + defer cleanupIPs() + + // Reserve IPs until the limit is reached and assert the error message + for i := 0; i < 100; i++ { + reservedIP, err := client.ReserveIPAddress(context.Background(), linodego.ReserveIPOptions{ + Region: "us-east", + }) + if err != nil { + expectedErrorMessage := "[400] Additional Reserved IPv4 addresses require technical justification." + if !strings.Contains(err.Error(), expectedErrorMessage) { + t.Errorf("Expected error message to contain '%s', but got: %v", expectedErrorMessage, err) + } else { + t.Logf("Failed to reserve IP %d as expected: %v", i+1, err) + } + break + } + + reservedIPs = append(reservedIPs, reservedIP.Address) + + if i == 99 { + t.Errorf("Expected to hit reservation limit, but did not reach it after 100 attempts") + } + } +} + +// TestReservedIPAddresses_DeleteIPAddressVariants tests various scenarios for deleting a reserved IP address +func TestReservedIPAddresses_DeleteIPAddressVariants(t *testing.T) { + client, teardown := createTestClient(t, "fixtures/TestReservedIPAddresses_DeleteIPAddressVariants") + defer teardown() + + validRes, validErr := client.ReserveIPAddress(context.Background(), ReserveIPOptions{Region: "us-east"}) + if validErr != nil { + t.Fatalf("Failed to reserve IP. This test should start with 0 reservations or reservations < limit. Error from the API: %v", validErr) + } + + if validRes == nil { + t.Fatalf("Valid reservation returned nil IP") + } + + t.Logf("Successfully reserved IP: %+v", validRes) + + filter := "" + ipList, listErr := client.ListReservedIPAddresses(context.Background(), NewListOptions(0, filter)) + if listErr != nil { + t.Fatalf("Error listing IP addresses: %v", listErr) + } + + if len(ipList) == 0 { + t.Fatalf("No reserved IPs available for testing deletion") + } + + delErr := client.DeleteReservedIPAddress(context.Background(), validRes.Address) + if delErr != nil { + t.Fatalf("Failed to delete reserved IP address: %v", delErr) + } + + // Verify deletion + verifyDelList, verifyDelErr := client.ListReservedIPAddresses(context.Background(), NewListOptions(0, filter)) + if verifyDelErr != nil { + t.Fatalf("Error listing IP addresses after deletion: %v", verifyDelErr) + } + + if len(verifyDelList) >= len(ipList) { + t.Errorf("IP address deletion not confirmed. Expected count < %d, got %d", len(ipList), len(verifyDelList)) + } + + _, fetchDelErr := client.GetReservedIPAddress(context.Background(), validRes.Address) + if fetchDelErr == nil { + t.Errorf("Expected error when fetching deleted IP, got nil") + } + + // Test deleting an unowned IP + unownedIP := "255.255.255.4" + delUnownedErr := client.DeleteReservedIPAddress(context.Background(), unownedIP) + if delUnownedErr == nil { + t.Errorf("Expected error when deleting unowned IP, got nil") + } +} From a424a084dc4613ec01503aa40c17f4338901bc1a Mon Sep 17 00:00:00 2001 From: Zhiwei Liang <121905282+zliang-akamai@users.noreply.github.com> Date: Thu, 19 Sep 2024 11:10:08 -0400 Subject: [PATCH 5/9] Add `last_login` support in `User` struct (#583) --- account_users.go | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/account_users.go b/account_users.go index e01e6dde..88615fa8 100644 --- a/account_users.go +++ b/account_users.go @@ -17,10 +17,17 @@ const ( UserTypeDefault UserType = "default" ) +// LastLogin represents a LastLogin object +type LastLogin struct { + LoginDatetime *time.Time `json:"-"` + Status string `json:"status"` +} + // User represents a User object type User struct { Username string `json:"username"` Email string `json:"email"` + LastLogin *LastLogin `json:"last_login"` UserType UserType `json:"user_type"` Restricted bool `json:"restricted"` TFAEnabled bool `json:"tfa_enabled"` @@ -42,6 +49,26 @@ type UserUpdateOptions struct { Restricted *bool `json:"restricted,omitempty"` } +// UnmarshalJSON implements the json.Unmarshaler interface +func (ll *LastLogin) UnmarshalJSON(b []byte) error { + type Mask LastLogin + + p := struct { + *Mask + LoginDatetime *parseabletime.ParseableTime `json:"login_datetime"` + }{ + Mask: (*Mask)(ll), + } + + if err := json.Unmarshal(b, &p); err != nil { + return err + } + + ll.LoginDatetime = (*time.Time)(p.LoginDatetime) + + return nil +} + // UnmarshalJSON implements the json.Unmarshaler interface func (i *User) UnmarshalJSON(b []byte) error { type Mask User From 2710f506fe284315932ddbab20e71a1188ff4741 Mon Sep 17 00:00:00 2001 From: Ye Chen <127243817+yec-akamai@users.noreply.github.com> Date: Fri, 20 Sep 2024 13:49:15 -0400 Subject: [PATCH 6/9] Improve image replication test region; Add LA notice (#582) * improve test region * fix fixture * improve regionHasCaps --- images.go | 1 + .../fixtures/TestImage_Replicate.yaml | 535 +++++++++++------- test/integration/images_test.go | 15 +- test/integration/integration_suite_test.go | 54 +- 4 files changed, 369 insertions(+), 236 deletions(-) diff --git a/images.go b/images.go index dd1d5f3f..9bbb2075 100644 --- a/images.go +++ b/images.go @@ -183,6 +183,7 @@ func (c *Client) UpdateImage(ctx context.Context, imageID string, opts ImageUpda } // ReplicateImage replicates an image to a given set of regions. +// NOTE: Image replication may not currently be available to all users. func (c *Client) ReplicateImage(ctx context.Context, imageID string, opts ImageReplicateOptions) (*Image, error) { return doPOSTRequest[Image]( ctx, diff --git a/test/integration/fixtures/TestImage_Replicate.yaml b/test/integration/fixtures/TestImage_Replicate.yaml index 19e833a6..aef3ee04 100644 --- a/test/integration/fixtures/TestImage_Replicate.yaml +++ b/test/integration/fixtures/TestImage_Replicate.yaml @@ -1,75 +1,6 @@ --- version: 1 interactions: -- request: - body: '{"region":"us-east","label":"linodego-image-replication","description":"An - image that does stuff."}' - form: {} - headers: - Accept: - - application/json - Content-Type: - - application/json - User-Agent: - - linodego/dev https://github.com/linode/linodego - url: https://api.linode.com/v4beta/images/upload - method: POST - response: - body: '{"upload_to": "https://us-east-1.linodeobjects.com:443/linode-production-machine-images-uploads/26428975?Signature=qRpBKGnJQWZYB7YGXwcW%2BAg3EbQ%3D&Expires=1722022419&AWSAccessKeyID=SANITIZED", - "image": {"id": "private/26428975", "label": "linodego-image-replication", "description": - "An image that does stuff.", "created": "2018-01-02T03:04:05", "updated": "2018-01-02T03:04:05", - "size": 0, "created_by": "ychen123", "type": "manual", "tags": [], "is_public": - false, "deprecated": false, "vendor": null, "expiry": null, "eol": null, "status": - "pending_upload", "capabilities": [], "regions": [], "total_size": 0}}' - 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 - Akamai-Internal-Account: - - '*' - Cache-Control: - - private, max-age=60, s-maxage=60 - Connection: - - keep-alive - Content-Length: - - "625" - Content-Security-Policy: - - default-src 'none' - Content-Type: - - application/json - Server: - - nginx/1.14.2 - Strict-Transport-Security: - - max-age=31536000 - - max-age=31536000 - Vary: - - Authorization, X-Filter - X-Accepted-Oauth-Scopes: - - images:read_write - X-Content-Type-Options: - - nosniff - X-Frame-Options: - - DENY - - DENY - X-Oauth-Scopes: - - account:read_write databases:read_write domains:read_write events:read_write - firewall:read_write images:read_write ips:read_write linodes:read_write lke:read_write - longview:read_write nodebalancers:read_write object_storage:read_write stackscripts:read_write - volumes:read_write vpc:read_write - X-Ratelimit-Limit: - - "400" - X-Xss-Protection: - - 1; mode=block - status: 200 OK - code: 200 - duration: "" - request: body: "" form: {} @@ -80,14 +11,263 @@ interactions: - application/json User-Agent: - linodego/dev https://github.com/linode/linodego - url: https://api.linode.com/v4beta/images/private%2F26428975 + url: https://api.linode.com/v4beta/regions?page=1 method: GET response: - body: '{"id": "private/26428975", "label": "linodego-image-replication", "description": - "An image that does stuff.", "created": "2018-01-02T03:04:05", "updated": "2018-01-02T03:04:05", - "size": 0, "created_by": "ychen123", "type": "manual", "tags": [], "is_public": - false, "deprecated": false, "vendor": null, "expiry": null, "eol": null, "status": - "pending_upload", "capabilities": [], "regions": [], "total_size": 0}' + body: '{"data": [{"id": "ap-west", "label": "Mumbai, IN", "country": "in", "capabilities": + ["Linodes", "Disk Encryption", "Backups", "NodeBalancers", "Block Storage", + "GPU Linodes", "Kubernetes", "Cloud Firewall", "Vlans", "Block Storage Migrations", + "Managed Databases", "Metadata", "Placement Group"], "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": + null, "maximum_linodes_per_pg": 5}, "site_type": "core"}, {"id": "ca-central", + "label": "Toronto, CA", "country": "ca", "capabilities": ["Linodes", "Disk Encryption", + "Backups", "NodeBalancers", "Block Storage", "Kubernetes", "Cloud Firewall", + "Vlans", "Block Storage Migrations", "Managed Databases", "Metadata", "Placement + Group"], "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": null, "maximum_linodes_per_pg": 5}, "site_type": + "core"}, {"id": "ap-southeast", "label": "Sydney, AU", "country": "au", "capabilities": + ["Linodes", "Backups", "NodeBalancers", "Block Storage", "Kubernetes", "Cloud + Firewall", "Vlans", "Block Storage Migrations", "Managed Databases", "Metadata", + "Placement Group"], "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": null, "maximum_linodes_per_pg": 5}, "site_type": + "core"}, {"id": "us-iad", "label": "Washington, DC", "country": "us", "capabilities": + ["Linodes", "Disk Encryption", "Backups", "NodeBalancers", "Block Storage", + "Object Storage", "Kubernetes", "Cloud Firewall", "Vlans", "VPCs", "Managed + Databases", "Metadata", "Premium Plans", "Placement Group"], "status": "ok", + "resolvers": {"ipv4": "139.144.192.62, 139.144.192.60, 139.144.192.61, 139.144.192.53, + 139.144.192.54, 139.144.192.67, 139.144.192.69, 139.144.192.66, 139.144.192.52, + 139.144.192.68", "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": null, "maximum_linodes_per_pg": 5}, "site_type": + "core"}, {"id": "us-ord", "label": "Chicago, IL", "country": "us", "capabilities": + ["Linodes", "Disk Encryption", "Backups", "NodeBalancers", "Block Storage", + "Object Storage", "GPU Linodes", "Kubernetes", "Cloud Firewall", "Vlans", "VPCs", + "Managed Databases", "Metadata", "Premium Plans", "Placement Group"], "status": + "ok", "resolvers": {"ipv4": "172.232.0.17, 172.232.0.16, 172.232.0.21, 172.232.0.13, + 172.232.0.22, 172.232.0.9, 172.232.0.19, 172.232.0.20, 172.232.0.15, 172.232.0.18", + "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": + null, "maximum_linodes_per_pg": 5}, "site_type": "core"}, {"id": "fr-par", "label": + "Paris, FR", "country": "fr", "capabilities": ["Linodes", "Disk Encryption", + "Backups", "NodeBalancers", "Block Storage", "Object Storage", "GPU Linodes", + "Kubernetes", "Cloud Firewall", "Vlans", "VPCs", "Managed Databases", "Metadata", + "Premium Plans", "Placement Group"], "status": "ok", "resolvers": {"ipv4": "172.232.32.21, + 172.232.32.23, 172.232.32.17, 172.232.32.18, 172.232.32.16, 172.232.32.22, 172.232.32.20, + 172.232.32.14, 172.232.32.11, 172.232.32.12", "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": null, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "us-sea", "label": "Seattle, WA", "country": + "us", "capabilities": ["Linodes", "Disk Encryption", "Backups", "NodeBalancers", + "Block Storage", "Object Storage", "GPU Linodes", "Kubernetes", "Cloud Firewall", + "Vlans", "VPCs", "Metadata", "Premium Plans", "Placement Group"], "status": + "ok", "resolvers": {"ipv4": "172.232.160.19, 172.232.160.21, 172.232.160.17, + 172.232.160.15, 172.232.160.18, 172.232.160.8, 172.232.160.12, 172.232.160.11, + 172.232.160.14, 172.232.160.16", "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": null, "maximum_linodes_per_pg": 5}, "site_type": + "core"}, {"id": "br-gru", "label": "Sao Paulo, BR", "country": "br", "capabilities": + ["Linodes", "Backups", "NodeBalancers", "Block Storage", "Object Storage", "Kubernetes", + "Cloud Firewall", "Vlans", "VPCs", "Metadata", "Premium Plans", "Placement Group"], + "status": "ok", "resolvers": {"ipv4": "172.233.0.4, 172.233.0.9, 172.233.0.7, + 172.233.0.12, 172.233.0.5, 172.233.0.13, 172.233.0.10, 172.233.0.6, 172.233.0.8, + 172.233.0.11", "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": null, "maximum_linodes_per_pg": 5}, "site_type": + "core"}, {"id": "nl-ams", "label": "Amsterdam, NL", "country": "nl", "capabilities": + ["Linodes", "Disk Encryption", "Backups", "NodeBalancers", "Block Storage", + "Object Storage", "Kubernetes", "Cloud Firewall", "Vlans", "VPCs", "Metadata", + "Premium Plans", "Placement Group"], "status": "ok", "resolvers": {"ipv4": "172.233.33.36, + 172.233.33.38, 172.233.33.35, 172.233.33.39, 172.233.33.34, 172.233.33.33, 172.233.33.31, + 172.233.33.30, 172.233.33.37, 172.233.33.32", "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": null, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "se-sto", "label": "Stockholm, SE", "country": + "se", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Block Storage", + "Object Storage", "Kubernetes", "Cloud Firewall", "Vlans", "VPCs", "Metadata", + "Premium Plans", "Placement Group"], "status": "ok", "resolvers": {"ipv4": "172.232.128.24, + 172.232.128.26, 172.232.128.20, 172.232.128.22, 172.232.128.25, 172.232.128.19, + 172.232.128.23, 172.232.128.18, 172.232.128.21, 172.232.128.27", "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": null, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "es-mad", "label": "Madrid, ES", "country": + "es", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Block Storage", + "Object Storage", "Kubernetes", "Cloud Firewall", "Vlans", "VPCs", "Metadata", + "Premium Plans", "Placement Group"], "status": "ok", "resolvers": {"ipv4": "172.233.111.6, + 172.233.111.17, 172.233.111.21, 172.233.111.25, 172.233.111.19, 172.233.111.12, + 172.233.111.26, 172.233.111.16, 172.233.111.18, 172.233.111.9", "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": null, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "in-maa", "label": "Chennai, IN", "country": + "in", "capabilities": ["Linodes", "Disk Encryption", "Backups", "NodeBalancers", + "Block Storage", "Object Storage", "Kubernetes", "Cloud Firewall", "Vlans", + "VPCs", "Metadata", "Premium Plans", "Placement Group"], "status": "ok", "resolvers": + {"ipv4": "172.232.96.17, 172.232.96.26, 172.232.96.19, 172.232.96.20, 172.232.96.25, + 172.232.96.21, 172.232.96.18, 172.232.96.22, 172.232.96.23, 172.232.96.24", + "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": + null, "maximum_linodes_per_pg": 5}, "site_type": "core"}, {"id": "jp-osa", "label": + "Osaka, JP", "country": "jp", "capabilities": ["Linodes", "Disk Encryption", + "Backups", "NodeBalancers", "Block Storage", "Object Storage", "GPU Linodes", + "Kubernetes", "Cloud Firewall", "Vlans", "VPCs", "Metadata", "Premium Plans", + "Placement Group"], "status": "ok", "resolvers": {"ipv4": "172.233.64.44, 172.233.64.43, + 172.233.64.37, 172.233.64.40, 172.233.64.46, 172.233.64.41, 172.233.64.39, 172.233.64.42, + 172.233.64.45, 172.233.64.38", "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": null, "maximum_linodes_per_pg": 5}, "site_type": + "core"}, {"id": "it-mil", "label": "Milan, IT", "country": "it", "capabilities": + ["Linodes", "Disk Encryption", "Backups", "NodeBalancers", "Block Storage", + "Object Storage", "Kubernetes", "Cloud Firewall", "Vlans", "VPCs", "Metadata", + "Premium Plans", "Placement Group"], "status": "ok", "resolvers": {"ipv4": "172.232.192.19, + 172.232.192.18, 172.232.192.16, 172.232.192.20, 172.232.192.24, 172.232.192.21, + 172.232.192.22, 172.232.192.17, 172.232.192.15, 172.232.192.23", "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": null, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "us-mia", "label": "Miami, FL", "country": + "us", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Block Storage", + "Object Storage", "Kubernetes", "Cloud Firewall", "Vlans", "VPCs", "Metadata", + "Premium Plans", "Placement Group"], "status": "ok", "resolvers": {"ipv4": "172.233.160.34, + 172.233.160.27, 172.233.160.30, 172.233.160.29, 172.233.160.32, 172.233.160.28, + 172.233.160.33, 172.233.160.26, 172.233.160.25, 172.233.160.31", "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": null, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "id-cgk", "label": "Jakarta, ID", "country": + "id", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Block Storage", + "Object Storage", "Kubernetes", "Cloud Firewall", "Vlans", "VPCs", "Metadata", + "Premium Plans", "Placement Group"], "status": "ok", "resolvers": {"ipv4": "172.232.224.23, + 172.232.224.32, 172.232.224.26, 172.232.224.27, 172.232.224.21, 172.232.224.24, + 172.232.224.22, 172.232.224.20, 172.232.224.31, 172.232.224.28", "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": null, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "us-lax", "label": "Los Angeles, CA", "country": + "us", "capabilities": ["Linodes", "Disk Encryption", "Backups", "NodeBalancers", + "Block Storage", "Object Storage", "Kubernetes", "Cloud Firewall", "Vlans", + "VPCs", "Metadata", "Premium Plans", "Placement Group"], "status": "ok", "resolvers": + {"ipv4": "172.233.128.45, 172.233.128.38, 172.233.128.53, 172.233.128.37, 172.233.128.34, + 172.233.128.36, 172.233.128.33, 172.233.128.39, 172.233.128.43, 172.233.128.44", + "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": + null, "maximum_linodes_per_pg": 5}, "site_type": "core"}, {"id": "gb-lon", "label": + "London 2, UK", "country": "gb", "capabilities": ["Linodes", "Backups", "NodeBalancers", + "Block Storage", "Kubernetes", "Cloud Firewall", "Vlans", "VPCs", "Metadata", + "Premium Plans", "Placement Group"], "status": "ok", "resolvers": {"ipv4": "172.236.0.46,172.236.0.50,172.236.0.47,172.236.0.53,172.236.0.52,172.236.0.45,172.236.0.49,172.236.0.51,172.236.0.54,172.236.0.48", + "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": null, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "au-mel", "label": "Melbourne, AU", "country": + "au", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Block Storage", + "Kubernetes", "Cloud Firewall", "Vlans", "VPCs", "Metadata", "Premium Plans", + "Placement Group"], "status": "ok", "resolvers": {"ipv4": "172.236.32.23,172.236.32.35,172.236.32.30,172.236.32.28,172.236.32.32,172.236.32.33,172.236.32.27,172.236.32.37,172.236.32.29,172.236.32.34", + "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": null, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "us-central", "label": "Dallas, TX", "country": + "us", "capabilities": ["Linodes", "Disk Encryption", "Backups", "NodeBalancers", + "Block Storage", "Kubernetes", "Cloud Firewall", "Vlans", "Block Storage Migrations", + "Managed Databases", "Metadata", "Placement Group"], "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": null, "maximum_linodes_per_pg": 5}, "site_type": + "core"}, {"id": "us-west", "label": "Fremont, CA", "country": "us", "capabilities": + ["Linodes", "Backups", "NodeBalancers", "Block Storage", "Kubernetes", "Cloud + Firewall", "Vlans", "Block Storage Migrations", "Managed Databases", "Metadata", + "Placement Group"], "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": null, + "maximum_linodes_per_pg": 5}, "site_type": "core"}, {"id": "us-southeast", "label": + "Atlanta, GA", "country": "us", "capabilities": ["Linodes", "Backups", "NodeBalancers", + "Block Storage", "Object Storage", "GPU Linodes", "Kubernetes", "Cloud Firewall", + "Vlans", "Block Storage Migrations", "Managed Databases", "Metadata", "Placement + Group"], "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": null, + "maximum_linodes_per_pg": 5}, "site_type": "core"}, {"id": "us-east", "label": + "Newark, NJ", "country": "us", "capabilities": ["Linodes", "Backups", "NodeBalancers", + "Block Storage", "Object Storage", "GPU Linodes", "Kubernetes", "Cloud Firewall", + "Vlans", "Block Storage Migrations", "Managed Databases", "Metadata", "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": null, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "eu-west", "label": "London, UK", "country": + "gb", "capabilities": ["Linodes", "Backups", "NodeBalancers", "Block Storage", + "Kubernetes", "Cloud Firewall", "Vlans", "Block Storage Migrations", "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": + null, "maximum_linodes_per_pg": 5}, "site_type": "core"}, {"id": "ap-south", + "label": "Singapore, SG", "country": "sg", "capabilities": ["Linodes", "Backups", + "NodeBalancers", "Block Storage", "Object Storage", "GPU Linodes", "Kubernetes", + "Cloud Firewall", "Vlans", "Block Storage Migrations", "Managed Databases", + "Metadata", "Placement Group"], "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": + null, "maximum_linodes_per_pg": 5}, "site_type": "core"}, {"id": "eu-central", + "label": "Frankfurt, DE", "country": "de", "capabilities": ["Linodes", "Backups", + "NodeBalancers", "Block Storage", "Object Storage", "GPU Linodes", "Kubernetes", + "Cloud Firewall", "Vlans", "Block Storage Migrations", "Managed Databases", + "Metadata", "Placement Group"], "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": null, "maximum_linodes_per_pg": + 5}, "site_type": "core"}, {"id": "ap-northeast", "label": "Tokyo 2, JP", "country": + "jp", "capabilities": ["Linodes", "Disk Encryption", "Backups", "NodeBalancers", + "Block Storage", "Kubernetes", "Cloud Firewall", "Vlans", "Block Storage Migrations", + "Managed Databases", "Metadata", "Placement Group"], "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": null, "maximum_linodes_per_pg": + 5}, "site_type": "core"}], "page": 1, "pages": 1, "results": 27}' headers: Access-Control-Allow-Credentials: - "true" @@ -102,95 +282,25 @@ interactions: Akamai-Internal-Account: - '*' Cache-Control: - - private, max-age=0, s-maxage=0, no-cache, no-store - - private, max-age=60, s-maxage=60 + - max-age=0, no-cache, no-store Connection: - keep-alive - Content-Length: - - "410" Content-Security-Policy: - default-src 'none' Content-Type: - application/json - Server: - - nginx/1.14.2 + Expires: + - Fri, 20 Sep 2024 15:19:48 GMT + Pragma: + - no-cache Strict-Transport-Security: - max-age=31536000 - - max-age=31536000 Vary: - Authorization, X-Filter - Authorization, X-Filter + - Accept-Encoding X-Accepted-Oauth-Scopes: - - images:read_only - X-Content-Type-Options: - - nosniff - X-Frame-Options: - - DENY - - DENY - X-Oauth-Scopes: - - account:read_write databases:read_write domains:read_write events:read_write - firewall:read_write images:read_write ips:read_write linodes:read_write lke:read_write - longview:read_write nodebalancers:read_write object_storage:read_write stackscripts:read_write - volumes:read_write vpc:read_write - 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/images/private%2F26428975 - method: GET - response: - body: '{"id": "private/26428975", "label": "linodego-image-replication", "description": - "An image that does stuff.", "created": "2018-01-02T03:04:05", "updated": "2018-01-02T03:04:05", - "size": 0, "created_by": "ychen123", "type": "manual", "tags": [], "is_public": - false, "deprecated": false, "vendor": null, "expiry": null, "eol": null, "status": - "pending_upload", "capabilities": [], "regions": [], "total_size": 0}' - 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 - Akamai-Internal-Account: - - '*' - 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: - - "410" - Content-Security-Policy: - - default-src 'none' - Content-Type: - - application/json - Server: - - nginx/1.14.2 - Strict-Transport-Security: - - max-age=31536000 - - max-age=31536000 - Vary: - - Authorization, X-Filter - - Authorization, X-Filter - X-Accepted-Oauth-Scopes: - - images:read_only X-Content-Type-Options: - nosniff X-Frame-Options: @@ -202,14 +312,15 @@ interactions: longview:read_write nodebalancers:read_write object_storage:read_write stackscripts:read_write volumes:read_write vpc:read_write X-Ratelimit-Limit: - - "400" + - "800" X-Xss-Protection: - 1; mode=block status: 200 OK code: 200 duration: "" - request: - body: "" + body: '{"region":"us-ord","label":"linodego-image-replication","description":"An + image that does stuff."}' form: {} headers: Accept: @@ -218,14 +329,15 @@ interactions: - application/json User-Agent: - linodego/dev https://github.com/linode/linodego - url: https://api.linode.com/v4beta/images/private%2F26428975 - method: GET + url: https://api.linode.com/v4beta/images/upload + method: POST response: - body: '{"id": "private/26428975", "label": "linodego-image-replication", "description": + body: '{"upload_to": "https://us-ord-1.linodeobjects.com:443/linode-production-machine-images-uploads/27384383?Signature=ij3pJ%2BNEAFkeYB09ACG%2BmAGMbGQ%3D&Expires=1726931989&AWSAccessKeyID=SANITIZED", + "image": {"id": "private/27384383", "label": "linodego-image-replication", "description": "An image that does stuff.", "created": "2018-01-02T03:04:05", "updated": "2018-01-02T03:04:05", "size": 0, "created_by": "ychen123", "type": "manual", "tags": [], "is_public": false, "deprecated": false, "vendor": null, "expiry": null, "eol": null, "status": - "pending_upload", "capabilities": [], "regions": [], "total_size": 0}' + "pending_upload", "capabilities": [], "regions": [], "total_size": 0}}' headers: Access-Control-Allow-Credentials: - "true" @@ -240,26 +352,25 @@ interactions: Akamai-Internal-Account: - '*' Cache-Control: - - private, max-age=0, s-maxage=0, no-cache, no-store - - private, max-age=60, s-maxage=60 + - max-age=0, no-cache, no-store Connection: - keep-alive Content-Length: - - "410" + - "626" Content-Security-Policy: - default-src 'none' Content-Type: - application/json - Server: - - nginx/1.14.2 + Expires: + - Fri, 20 Sep 2024 15:19:49 GMT + Pragma: + - no-cache Strict-Transport-Security: - max-age=31536000 - - max-age=31536000 Vary: - Authorization, X-Filter - - Authorization, X-Filter X-Accepted-Oauth-Scopes: - - images:read_only + - images:read_write X-Content-Type-Options: - nosniff X-Frame-Options: @@ -271,7 +382,7 @@ interactions: longview:read_write nodebalancers:read_write object_storage:read_write stackscripts:read_write volumes:read_write vpc:read_write X-Ratelimit-Limit: - - "400" + - "800" X-Xss-Protection: - 1; mode=block status: 200 OK @@ -287,10 +398,10 @@ interactions: - application/json User-Agent: - linodego/dev https://github.com/linode/linodego - url: https://api.linode.com/v4beta/images/private%2F26428975 + url: https://api.linode.com/v4beta/images/private%2F27384383 method: GET response: - body: '{"id": "private/26428975", "label": "linodego-image-replication", "description": + body: '{"id": "private/27384383", "label": "linodego-image-replication", "description": "An image that does stuff.", "created": "2018-01-02T03:04:05", "updated": "2018-01-02T03:04:05", "size": 0, "created_by": "ychen123", "type": "manual", "tags": [], "is_public": false, "deprecated": false, "vendor": null, "expiry": null, "eol": null, "status": @@ -309,8 +420,7 @@ interactions: Akamai-Internal-Account: - '*' Cache-Control: - - private, max-age=0, s-maxage=0, no-cache, no-store - - private, max-age=60, s-maxage=60 + - max-age=0, no-cache, no-store Connection: - keep-alive Content-Length: @@ -319,11 +429,12 @@ interactions: - default-src 'none' Content-Type: - application/json - Server: - - nginx/1.14.2 + Expires: + - Fri, 20 Sep 2024 15:20:04 GMT + Pragma: + - no-cache Strict-Transport-Security: - max-age=31536000 - - max-age=31536000 Vary: - Authorization, X-Filter - Authorization, X-Filter @@ -340,7 +451,7 @@ interactions: longview:read_write nodebalancers:read_write object_storage:read_write stackscripts:read_write volumes:read_write vpc:read_write X-Ratelimit-Limit: - - "400" + - "800" X-Xss-Protection: - 1; mode=block status: 200 OK @@ -356,10 +467,10 @@ interactions: - application/json User-Agent: - linodego/dev https://github.com/linode/linodego - url: https://api.linode.com/v4beta/images/private%2F26428975 + url: https://api.linode.com/v4beta/images/private%2F27384383 method: GET response: - body: '{"id": "private/26428975", "label": "linodego-image-replication", "description": + body: '{"id": "private/27384383", "label": "linodego-image-replication", "description": "An image that does stuff.", "created": "2018-01-02T03:04:05", "updated": "2018-01-02T03:04:05", "size": 0, "created_by": "ychen123", "type": "manual", "tags": [], "is_public": false, "deprecated": false, "vendor": null, "expiry": null, "eol": null, "status": @@ -378,8 +489,7 @@ interactions: Akamai-Internal-Account: - '*' Cache-Control: - - private, max-age=0, s-maxage=0, no-cache, no-store - - private, max-age=60, s-maxage=60 + - max-age=0, no-cache, no-store Connection: - keep-alive Content-Length: @@ -388,11 +498,12 @@ interactions: - default-src 'none' Content-Type: - application/json - Server: - - nginx/1.14.2 + Expires: + - Fri, 20 Sep 2024 15:20:20 GMT + Pragma: + - no-cache Strict-Transport-Security: - max-age=31536000 - - max-age=31536000 Vary: - Authorization, X-Filter - Authorization, X-Filter @@ -409,7 +520,7 @@ interactions: longview:read_write nodebalancers:read_write object_storage:read_write stackscripts:read_write volumes:read_write vpc:read_write X-Ratelimit-Limit: - - "400" + - "800" X-Xss-Protection: - 1; mode=block status: 200 OK @@ -425,15 +536,15 @@ interactions: - application/json User-Agent: - linodego/dev https://github.com/linode/linodego - url: https://api.linode.com/v4beta/images/private%2F26428975 + url: https://api.linode.com/v4beta/images/private%2F27384383 method: GET response: - body: '{"id": "private/26428975", "label": "linodego-image-replication", "description": + body: '{"id": "private/27384383", "label": "linodego-image-replication", "description": "An image that does stuff.", "created": "2018-01-02T03:04:05", "updated": "2018-01-02T03:04:05", "size": 1, "created_by": "ychen123", "type": "manual", "tags": [], "is_public": false, "deprecated": false, "vendor": null, "expiry": null, "eol": null, "status": - "available", "capabilities": [], "regions": [{"region": "us-east", "status": - "available"}], "total_size": 1}' + "available", "capabilities": ["distributed-sites"], "regions": [{"region": "us-ord", + "status": "available"}], "total_size": 1}' headers: Access-Control-Allow-Credentials: - "true" @@ -448,21 +559,21 @@ interactions: Akamai-Internal-Account: - '*' Cache-Control: - - private, max-age=0, s-maxage=0, no-cache, no-store - - private, max-age=60, s-maxage=60 + - max-age=0, no-cache, no-store Connection: - keep-alive Content-Length: - - "449" + - "467" Content-Security-Policy: - default-src 'none' Content-Type: - application/json - Server: - - nginx/1.14.2 + Expires: + - Fri, 20 Sep 2024 15:20:35 GMT + Pragma: + - no-cache Strict-Transport-Security: - max-age=31536000 - - max-age=31536000 Vary: - Authorization, X-Filter - Authorization, X-Filter @@ -479,14 +590,14 @@ interactions: longview:read_write nodebalancers:read_write object_storage:read_write stackscripts:read_write volumes:read_write vpc:read_write X-Ratelimit-Limit: - - "400" + - "800" X-Xss-Protection: - 1; mode=block status: 200 OK code: 200 duration: "" - request: - body: '{"regions":["us-east","eu-west"]}' + body: '{"regions":["us-iad","us-ord"]}' form: {} headers: Accept: @@ -495,16 +606,16 @@ interactions: - application/json User-Agent: - linodego/dev https://github.com/linode/linodego - url: https://api.linode.com/v4beta/images/private%2F26428975/regions + url: https://api.linode.com/v4beta/images/private%2F27384383/regions method: POST response: - body: '{"id": "private/26428975", "label": "linodego-image-replication", "description": + body: '{"id": "private/27384383", "label": "linodego-image-replication", "description": "An image that does stuff.", "created": "2018-01-02T03:04:05", "updated": "2018-01-02T03:04:05", "size": 1, "created_by": "ychen123", "type": "manual", "tags": [], "is_public": false, "deprecated": false, "vendor": null, "expiry": null, "eol": null, "status": - "available", "capabilities": [], "regions": [{"region": "us-east", "status": - "available"}, {"region": "eu-west", "status": "pending replication"}], "total_size": - 1}' + "available", "capabilities": ["distributed-sites"], "regions": [{"region": "us-ord", + "status": "available"}, {"region": "us-iad", "status": "pending replication"}], + "total_size": 1}' headers: Access-Control-Allow-Credentials: - "true" @@ -519,20 +630,21 @@ interactions: Akamai-Internal-Account: - '*' Cache-Control: - - private, max-age=60, s-maxage=60 + - max-age=0, no-cache, no-store Connection: - keep-alive Content-Length: - - "505" + - "522" Content-Security-Policy: - default-src 'none' Content-Type: - application/json - Server: - - nginx/1.14.2 + Expires: + - Fri, 20 Sep 2024 15:20:35 GMT + Pragma: + - no-cache Strict-Transport-Security: - max-age=31536000 - - max-age=31536000 Vary: - Authorization, X-Filter X-Accepted-Oauth-Scopes: @@ -548,7 +660,7 @@ interactions: longview:read_write nodebalancers:read_write object_storage:read_write stackscripts:read_write volumes:read_write vpc:read_write X-Ratelimit-Limit: - - "400" + - "800" X-Xss-Protection: - 1; mode=block status: 200 OK @@ -564,7 +676,7 @@ interactions: - application/json User-Agent: - linodego/dev https://github.com/linode/linodego - url: https://api.linode.com/v4beta/images/private%2F26428975 + url: https://api.linode.com/v4beta/images/private%2F27384383 method: DELETE response: body: '{}' @@ -582,7 +694,7 @@ interactions: Akamai-Internal-Account: - '*' Cache-Control: - - private, max-age=60, s-maxage=60 + - max-age=0, no-cache, no-store Connection: - keep-alive Content-Length: @@ -591,11 +703,12 @@ interactions: - default-src 'none' Content-Type: - application/json - Server: - - nginx/1.14.2 + Expires: + - Fri, 20 Sep 2024 15:20:35 GMT + Pragma: + - no-cache Strict-Transport-Security: - max-age=31536000 - - max-age=31536000 Vary: - Authorization, X-Filter X-Accepted-Oauth-Scopes: @@ -611,7 +724,7 @@ interactions: longview:read_write nodebalancers:read_write object_storage:read_write stackscripts:read_write volumes:read_write vpc:read_write X-Ratelimit-Limit: - - "400" + - "800" X-Xss-Protection: - 1; mode=block status: 200 OK diff --git a/test/integration/images_test.go b/test/integration/images_test.go index a0f85458..572fdd3d 100644 --- a/test/integration/images_test.go +++ b/test/integration/images_test.go @@ -178,14 +178,13 @@ func TestImage_CloudInit(t *testing.T) { } func TestImage_Replicate(t *testing.T) { - // TODO: use random regions with capabilities once it gets stable - availableRegions := []string{"us-east", "eu-west"} - client, teardown := createTestClient(t, "fixtures/TestImage_Replicate") defer teardown() + availableRegions := getRegionsWithCapsAndSiteType(t, client, []string{"Object Storage"}, "core") + image, uploadURL, err := client.CreateImageUpload(context.Background(), ImageCreateUploadOptions{ - Region: availableRegions[0], + Region: availableRegions[1], Label: "linodego-image-replication", Description: "An image that does stuff.", }) @@ -213,19 +212,19 @@ func TestImage_Replicate(t *testing.T) { } } - if _, err := client.WaitForImageStatus(context.Background(), image.ID, ImageStatusAvailable, 240); err != nil { + if _, err := client.WaitForImageStatus(context.Background(), image.ID, ImageStatusAvailable, 400); err != nil { t.Errorf("Failed to wait for image available upload status: %v", err) } - replicaRegions := availableRegions + replicaRegions := availableRegions[:2] image, err = client.ReplicateImage(context.Background(), image.ID, ImageReplicateOptions{ Regions: replicaRegions, }) require.NoError(t, err) - require.Len(t, image.Regions, len(availableRegions)) + require.Len(t, image.Regions, len(replicaRegions)) for _, region := range image.Regions { - assert.Contains(t, availableRegions, region.Region) + assert.Contains(t, replicaRegions, region.Region) } } diff --git a/test/integration/integration_suite_test.go b/test/integration/integration_suite_test.go index b55924c6..2bad132e 100644 --- a/test/integration/integration_suite_test.go +++ b/test/integration/integration_suite_test.go @@ -203,24 +203,8 @@ func getRegionsWithCaps(t *testing.T, client *linodego.Client, capabilities []st t.Fatal(err) } - regionHasCaps := func(r linodego.Region) bool { - capsMap := make(map[string]bool) - - for _, c := range r.Capabilities { - capsMap[strings.ToUpper(c)] = true - } - - for _, c := range capabilities { - if _, ok := capsMap[strings.ToUpper(c)]; !ok { - return false - } - } - - return true - } - for _, region := range regions { - if region.Status != "ok" || !regionHasCaps(region) { + if region.Status != "ok" || !regionHasCaps(region, capabilities) { continue } @@ -270,3 +254,39 @@ func getRegionsWithCapsAndPlans(t *testing.T, client *linodego.Client, capabilit return result } + +// getRegionsWithCapsAndSiteType returns a list of regions that meet the given capabilities and site type +func getRegionsWithCapsAndSiteType(t *testing.T, client *linodego.Client, capabilities []string, siteType string) []string { + result := make([]string, 0) + + regions, err := client.ListRegions(context.Background(), nil) + if err != nil { + t.Fatal(err) + } + + for _, region := range regions { + if region.Status != "ok" || region.SiteType != siteType || !regionHasCaps(region, capabilities) { + continue + } + + result = append(result, region.ID) + } + + return result +} + +func regionHasCaps(r linodego.Region, capabilities []string) bool { + capsMap := make(map[string]bool) + + for _, c := range r.Capabilities { + capsMap[strings.ToUpper(c)] = true + } + + for _, c := range capabilities { + if _, ok := capsMap[strings.ToUpper(c)]; !ok { + return false + } + } + + return true +} From ac81d65fb5d289c629c7b344eedf8e967dd90548 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Sep 2024 08:59:30 -0700 Subject: [PATCH 7/9] build(deps): bump golang.org/x/net from 0.28.0 to 0.29.0 (#578) * build(deps): bump golang.org/x/net from 0.28.0 to 0.29.0 Bumps [golang.org/x/net](https://github.com/golang/net) from 0.28.0 to 0.29.0. - [Commits](https://github.com/golang/net/compare/v0.28.0...v0.29.0) --- updated-dependencies: - dependency-name: golang.org/x/net dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Ran make tidy --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: ezilber-akamai Co-authored-by: Lena Garber <114949949+lgarber-akamai@users.noreply.github.com> Co-authored-by: Ye Chen <127243817+yec-akamai@users.noreply.github.com> Co-authored-by: Youjung Kim <126618609+ykim-1@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- go.work.sum | 9 ++++++--- k8s/go.mod | 6 +++--- k8s/go.sum | 12 ++++++------ test/go.mod | 6 +++--- test/go.sum | 12 ++++++------ 7 files changed, 27 insertions(+), 24 deletions(-) diff --git a/go.mod b/go.mod index 5d14b6bb..7d10cf44 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ require ( github.com/go-resty/resty/v2 v2.13.1 github.com/google/go-cmp v0.6.0 github.com/jarcoal/httpmock v1.3.1 - golang.org/x/net v0.28.0 + golang.org/x/net v0.29.0 golang.org/x/oauth2 v0.23.0 golang.org/x/text v0.18.0 gopkg.in/ini.v1 v1.66.6 diff --git a/go.sum b/go.sum index 34fdd1af..ef206efa 100644 --- a/go.sum +++ b/go.sum @@ -26,8 +26,8 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= -golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= -golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= +golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= +golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= diff --git a/go.work.sum b/go.work.sum index 5d491a18..8c284324 100644 --- a/go.work.sum +++ b/go.work.sum @@ -7,8 +7,6 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w= -github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= -github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= @@ -25,7 +23,6 @@ github.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw= github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5 h1:8Q0qkMVC/MmWkpIdlvZgcv2o2jrlF6zqVOh7W5YHdMA= -github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= @@ -41,12 +38,18 @@ golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= +golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= +golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM= +golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= 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/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= diff --git a/k8s/go.mod b/k8s/go.mod index 9675da00..c8cf226b 100644 --- a/k8s/go.mod +++ b/k8s/go.mod @@ -28,10 +28,10 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/spf13/pflag v1.0.5 // indirect - golang.org/x/net v0.28.0 // indirect + golang.org/x/net v0.29.0 // indirect golang.org/x/oauth2 v0.23.0 // indirect - golang.org/x/sys v0.23.0 // indirect - golang.org/x/term v0.23.0 // indirect + golang.org/x/sys v0.25.0 // indirect + golang.org/x/term v0.24.0 // indirect golang.org/x/text v0.18.0 // indirect golang.org/x/time v0.5.0 // indirect google.golang.org/protobuf v1.33.0 // indirect diff --git a/k8s/go.sum b/k8s/go.sum index b9158ed1..b295efe4 100644 --- a/k8s/go.sum +++ b/k8s/go.sum @@ -100,8 +100,8 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= -golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= -golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= +golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= +golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -120,16 +120,16 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= -golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= -golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= -golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= +golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM= +golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= diff --git a/test/go.mod b/test/go.mod index c89aa65a..a09f94ba 100644 --- a/test/go.mod +++ b/test/go.mod @@ -7,7 +7,7 @@ require ( github.com/linode/linodego v1.33.0 github.com/linode/linodego/k8s v0.0.0-00010101000000-000000000000 github.com/stretchr/testify v1.9.0 - golang.org/x/net v0.28.0 + golang.org/x/net v0.29.0 golang.org/x/oauth2 v0.23.0 k8s.io/client-go v0.29.4 ) @@ -34,8 +34,8 @@ require ( 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.23.0 // indirect - golang.org/x/term v0.23.0 // indirect + golang.org/x/sys v0.25.0 // indirect + golang.org/x/term v0.24.0 // indirect golang.org/x/text v0.18.0 // indirect golang.org/x/time v0.5.0 // indirect google.golang.org/protobuf v1.33.0 // indirect diff --git a/test/go.sum b/test/go.sum index 969ec019..905e845a 100644 --- a/test/go.sum +++ b/test/go.sum @@ -105,8 +105,8 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= -golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= -golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= +golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= +golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -125,16 +125,16 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= -golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= -golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= -golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= +golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM= +golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= From b20be2e986e039cd7f1e03b8fabfc858288b076d Mon Sep 17 00:00:00 2001 From: AniJ98 Date: Wed, 25 Sep 2024 13:30:15 -0400 Subject: [PATCH 8/9] Support for Adding Additional Reserved IP to Existing Linodes (#581) --- instance_ips.go | 16 + instances.go | 2 + .../TestInstance_AddReservedIPToInstance.yaml | 397 ++++++ ...tance_AddReservedIPToInstanceVariants.yaml | 1109 +++++++++++++++++ ...e_CreateWithAlreadyAssignedReservedIP.yaml | 303 +++++ ...TestInstance_CreateWithEmptyIPAddress.yaml | 180 +++ ...nstance_CreateWithMultipleIPAddresses.yaml | 304 +++++ ...nce_CreateWithNonOwnedReservedAddress.yaml | 48 + ...Instance_CreateWithNonReservedAddress.yaml | 48 + .../TestInstance_CreateWithNullIPAddress.yaml | 134 ++ ..._CreateWithOwnedNonAssignedReservedIP.yaml | 258 ++++ ...tInstance_CreateWithReservedIPAddress.yaml | 259 ++++ ...e_CreateWithReservedIPAddressVariants.yaml | 748 +++++++++++ .../TestInstance_CreateWithoutIPv4Field.yaml | 134 ++ .../integration/instance_reserved_ips_test.go | 456 +++++++ 15 files changed, 4396 insertions(+) create mode 100644 test/integration/fixtures/TestInstance_AddReservedIPToInstance.yaml create mode 100644 test/integration/fixtures/TestInstance_AddReservedIPToInstanceVariants.yaml create mode 100644 test/integration/fixtures/TestInstance_CreateWithAlreadyAssignedReservedIP.yaml create mode 100644 test/integration/fixtures/TestInstance_CreateWithEmptyIPAddress.yaml create mode 100644 test/integration/fixtures/TestInstance_CreateWithMultipleIPAddresses.yaml create mode 100644 test/integration/fixtures/TestInstance_CreateWithNonOwnedReservedAddress.yaml create mode 100644 test/integration/fixtures/TestInstance_CreateWithNonReservedAddress.yaml create mode 100644 test/integration/fixtures/TestInstance_CreateWithNullIPAddress.yaml create mode 100644 test/integration/fixtures/TestInstance_CreateWithOwnedNonAssignedReservedIP.yaml create mode 100644 test/integration/fixtures/TestInstance_CreateWithReservedIPAddress.yaml create mode 100644 test/integration/fixtures/TestInstance_CreateWithReservedIPAddressVariants.yaml create mode 100644 test/integration/fixtures/TestInstance_CreateWithoutIPv4Field.yaml create mode 100644 test/integration/instance_reserved_ips_test.go diff --git a/instance_ips.go b/instance_ips.go index 568be05e..7a5ad62c 100644 --- a/instance_ips.go +++ b/instance_ips.go @@ -79,6 +79,12 @@ type IPv6Range struct { Linodes []int `json:"linodes"` } +type InstanceReserveIPOptions struct { + Type string `json:"type"` + Public bool `json:"public"` + Address string `json:"address"` +} + // InstanceIPType constants start with IPType and include Linode Instance IP Types type InstanceIPType string @@ -144,3 +150,13 @@ func (c *Client) DeleteInstanceIPAddress(ctx context.Context, linodeID int, ipAd err := doDELETERequest(ctx, c, e) return err } + +// Function to add additional reserved IPV4 addresses to an existing linode +func (c *Client) AssignInstanceReservedIP(ctx context.Context, linodeID int, opts InstanceReserveIPOptions) (*InstanceIP, error) { + endpoint := formatAPIPath("linode/instances/%d/ips", linodeID) + response, err := doPOSTRequest[InstanceIP](ctx, c, endpoint, opts) + if err != nil { + return nil, err + } + return response, nil +} diff --git a/instances.go b/instances.go index 92eb6629..31876598 100644 --- a/instances.go +++ b/instances.go @@ -164,6 +164,8 @@ type InstanceCreateOptions struct { // Deprecated: group is a deprecated property denoting a group label for the Linode. Group string `json:"group,omitempty"` + + IPv4 []string `json:"ipv4,omitempty"` } // InstanceCreatePlacementGroupOptions represents the placement group diff --git a/test/integration/fixtures/TestInstance_AddReservedIPToInstance.yaml b/test/integration/fixtures/TestInstance_AddReservedIPToInstance.yaml new file mode 100644 index 00000000..8ff4312c --- /dev/null +++ b/test/integration/fixtures/TestInstance_AddReservedIPToInstance.yaml @@ -0,0 +1,397 @@ +--- +version: 1 +interactions: +- request: + body: '{"region":"us-east","type":"g6-nanode-1","label":"test-instance-for-ip-reservation","root_pass":"5vJy-=\\NV\u003c1w`6!2Yf~6.2zN4L-zz5w\\2nWk0lH6Zq/}BN8[3Ou#37shHE-C3|rV"}' + 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": 63837282, "label": "test-instance-for-ip-reservation", "group": + "", "status": "provisioning", "created": "2018-01-02T03:04:05", "updated": "2018-01-02T03:04:05", + "type": "g6-nanode-1", "ipv4": ["45.79.160.146"], "ipv6": "2600:3c03::f03c:95ff:fe46:25ac/128", + "image": null, "region": "us-east", "site_type": "core", "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": "aab21dc7e975cd72af77bb1dee30b501acd7d3b9", "has_user_data": + false, "placement_group": null, "disk_encryption": "disabled", "lke_cluster_id": + null, "capabilities": []}' + 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "858" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Thu, 12 Sep 2024 19:53:07 GMT + Pragma: + - no-cache + 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: '{"region":"us-east"}' + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - linodego/dev https://github.com/linode/linodego + url: https://api.linode.com/v4beta/networking/reserved/ips + method: POST + response: + body: '{"address": "45.79.150.200", "gateway": "45.79.150.1", "subnet_mask": "255.255.255.0", + "prefix": 24, "type": "ipv4", "public": true, "rdns": "45-79-150-200.ip.linodeusercontent.com", + "linode_id": null, "region": "us-east", "vpc_nat_1_1": null, "reserved": 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "261" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Thu, 12 Sep 2024 19:53:08 GMT + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - ips:read_write + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "800" + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: '{"type":"ipv4","public":true,"address":"45.79.150.200"}' + 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/63837282/ips + method: POST + response: + body: '{"address": "45.79.150.200", "gateway": "45.79.150.1", "subnet_mask": "255.255.255.0", + "prefix": 24, "type": "ipv4", "public": true, "rdns": "45-79-150-200.ip.linodeusercontent.com", + "linode_id": 63837282, "region": "us-east", "vpc_nat_1_1": null, "reserved": + 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "265" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Thu, 12 Sep 2024 19:53:08 GMT + Pragma: + - no-cache + 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: + - "800" + 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/63837282/ips + method: GET + response: + body: '{"ipv4": {"public": [{"address": "45.79.150.200", "gateway": "45.79.150.1", + "subnet_mask": "255.255.255.0", "prefix": 24, "type": "ipv4", "public": true, + "rdns": "45-79-150-200.ip.linodeusercontent.com", "linode_id": 63837282, "region": + "us-east", "vpc_nat_1_1": null, "reserved": true}, {"address": "45.79.160.146", + "gateway": "45.79.160.1", "subnet_mask": "255.255.255.0", "prefix": 24, "type": + "ipv4", "public": true, "rdns": "45-79-160-146.ip.linodeusercontent.com", "linode_id": + 63837282, "region": "us-east", "vpc_nat_1_1": null, "reserved": false}], "private": + [], "shared": [], "reserved": [], "vpc": []}, "ipv6": {"slaac": {"address": + "2600:3c03::f03c:95ff:fe46:25ac", "gateway": "fe80::1", "subnet_mask": "ffff:ffff:ffff:ffff::", + "prefix": 64, "type": "ipv6", "rdns": null, "linode_id": 63837282, "region": + "us-east", "public": true}, "link_local": {"address": "fe80::f03c:95ff:fe46:25ac", + "gateway": "fe80::1", "subnet_mask": "ffff:ffff:ffff:ffff::", "prefix": 64, + "type": "ipv6", "rdns": null, "linode_id": 63837282, "region": "us-east", "public": + false}, "global": []}}' + 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Thu, 12 Sep 2024 19:53:08 GMT + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + - Authorization, X-Filter + - Accept-Encoding + X-Accepted-Oauth-Scopes: + - linodes:read_only + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "800" + 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/networking/reserved/ips/45.79.150.200 + 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "2" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Thu, 12 Sep 2024 19:53:08 GMT + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - ips: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/63837282 + 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "2" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Thu, 12 Sep 2024 19:53:10 GMT + Pragma: + - no-cache + 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: + - "800" + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" diff --git a/test/integration/fixtures/TestInstance_AddReservedIPToInstanceVariants.yaml b/test/integration/fixtures/TestInstance_AddReservedIPToInstanceVariants.yaml new file mode 100644 index 00000000..6239225d --- /dev/null +++ b/test/integration/fixtures/TestInstance_AddReservedIPToInstanceVariants.yaml @@ -0,0 +1,1109 @@ +--- +version: 1 +interactions: +- request: + body: '{"region":"us-east","type":"g6-nanode-1","label":"test-instance-for-ip-reservation","root_pass":"G2iB;VR!85]g1LXU^sC9zW;f\u00268168Ee\u003ca6g*td{r16tGq\u003cm4.^Yd''p$7UH,5-6BM"}' + 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": 63837167, "label": "test-instance-for-ip-reservation", "group": + "", "status": "provisioning", "created": "2018-01-02T03:04:05", "updated": "2018-01-02T03:04:05", + "type": "g6-nanode-1", "ipv4": ["97.107.141.56"], "ipv6": "2600:3c03::f03c:95ff:fe46:d62c/128", + "image": null, "region": "us-east", "site_type": "core", "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": "aab21dc7e975cd72af77bb1dee30b501acd7d3b9", "has_user_data": + false, "placement_group": null, "disk_encryption": "disabled", "lke_cluster_id": + null, "capabilities": []}' + 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "858" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Thu, 12 Sep 2024 19:48:41 GMT + Pragma: + - no-cache + 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: '{"region":"us-east"}' + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - linodego/dev https://github.com/linode/linodego + url: https://api.linode.com/v4beta/networking/reserved/ips + method: POST + response: + body: '{"address": "23.92.21.220", "gateway": "23.92.21.1", "subnet_mask": "255.255.255.0", + "prefix": 24, "type": "ipv4", "public": true, "rdns": "23-92-21-220.ip.linodeusercontent.com", + "linode_id": null, "region": "us-east", "vpc_nat_1_1": null, "reserved": 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "258" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Thu, 12 Sep 2024 19:48:41 GMT + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - ips:read_write + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "800" + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: '{"type":"ipv4","public":true,"address":"23.92.21.220"}' + 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/63837167/ips + method: POST + response: + body: '{"address": "23.92.21.220", "gateway": "23.92.21.1", "subnet_mask": "255.255.255.0", + "prefix": 24, "type": "ipv4", "public": true, "rdns": "23-92-21-220.ip.linodeusercontent.com", + "linode_id": 63837167, "region": "us-east", "vpc_nat_1_1": null, "reserved": + 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "262" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Thu, 12 Sep 2024 19:48:41 GMT + Pragma: + - no-cache + 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: + - "800" + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: '{"type":"ipv4","public":false,"address":"23.92.21.220"}' + 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/63837167/ips + method: POST + response: + body: '{"errors": [{"reason": "Cannot reserve a private address.", "field": "address"}]}' + headers: + 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: + - '*' + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Content-Length: + - "81" + Content-Type: + - application/json + Expires: + - Thu, 12 Sep 2024 19:48:41 GMT + Pragma: + - no-cache + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Frame-Options: + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "800" + status: 400 Bad Request + code: 400 + duration: "" +- request: + body: '{"region":"us-east"}' + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - linodego/dev https://github.com/linode/linodego + url: https://api.linode.com/v4beta/networking/reserved/ips + method: POST + response: + body: '{"address": "45.79.150.200", "gateway": "45.79.150.1", "subnet_mask": "255.255.255.0", + "prefix": 24, "type": "ipv4", "public": true, "rdns": "45-79-150-200.ip.linodeusercontent.com", + "linode_id": null, "region": "us-east", "vpc_nat_1_1": null, "reserved": 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "261" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Thu, 12 Sep 2024 19:48:42 GMT + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - ips:read_write + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "800" + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: '{"type":"ipv4","public":true,"address":"45.79.150.200"}' + 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/63510870/ips + method: POST + response: + body: '{"errors": [{"reason": "Additional IPv4 addresses require technical justification. Please + contact support describing your requirement"}]}' + headers: + 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: + - '*' + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Content-Length: + - "138" + Content-Type: + - application/json + Expires: + - Thu, 12 Sep 2024 19:48:42 GMT + Pragma: + - no-cache + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Frame-Options: + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "800" + status: 400 Bad Request + code: 400 + 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/networking/reserved/ips/45.79.150.200 + 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "2" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Thu, 12 Sep 2024 19:48:42 GMT + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - ips: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: '{"type":"ipv4","public":true,"address":"23.92.21.220"}' + 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/888888/ips + method: POST + response: + body: '{"errors": [{"reason": "Not found"}]}' + headers: + 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: + - '*' + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Content-Length: + - "37" + Content-Type: + - application/json + Expires: + - Thu, 12 Sep 2024 19:48:42 GMT + Pragma: + - no-cache + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Frame-Options: + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "800" + status: 404 Not Found + code: 404 + duration: "" +- request: + body: '{"type":"ipv4","public":true,"address":"23.92.21.220"}' + 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/63837167/ips + method: POST + response: + body: '{"errors": [{"reason": "Address must be currently unassigned.", "field": + "address"}]}' + headers: + 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: + - '*' + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Content-Length: + - "85" + Content-Type: + - application/json + Expires: + - Thu, 12 Sep 2024 19:48:42 GMT + Pragma: + - no-cache + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Frame-Options: + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "800" + status: 400 Bad Request + code: 400 + duration: "" +- request: + body: '{"type":"ipv4","public":true,"address":"198.51.100.1"}' + 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/63837167/ips + method: POST + response: + body: '{"errors": [{"reason": "Address must be reserved and must be currently + unassigned.", "field": "address"}]}' + headers: + 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: + - '*' + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Content-Length: + - "106" + Content-Type: + - application/json + Expires: + - Thu, 12 Sep 2024 19:48:42 GMT + Pragma: + - no-cache + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Frame-Options: + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "800" + status: 400 Bad Request + code: 400 + duration: "" +- request: + body: '{"region":"ca-central"}' + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - linodego/dev https://github.com/linode/linodego + url: https://api.linode.com/v4beta/networking/reserved/ips + method: POST + response: + body: '{"address": "172.105.0.89", "gateway": "172.105.0.1", "subnet_mask": "255.255.255.0", + "prefix": 24, "type": "ipv4", "public": true, "rdns": "172-105-0-89.ip.linodeusercontent.com", + "linode_id": null, "region": "ca-central", "vpc_nat_1_1": null, "reserved": + 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "262" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Thu, 12 Sep 2024 19:48:43 GMT + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - ips:read_write + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "800" + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: '{"type":"ipv4","public":true,"address":"172.105.0.89"}' + 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/63837167/ips + method: POST + response: + body: '{"errors": [{"reason": "Address must belong to same region as linode.", + "field": "address"}]}' + headers: + 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: + - '*' + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Content-Length: + - "93" + Content-Type: + - application/json + Expires: + - Thu, 12 Sep 2024 19:48:43 GMT + Pragma: + - no-cache + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Frame-Options: + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "800" + status: 400 Bad Request + code: 400 + duration: "" +- request: + body: '{"type":"ipv6","public":true,"address":"23.92.21.220"}' + 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/63837167/ips + method: POST + response: + body: '{"errors": [{"reason": "Only addresses of type ipv4 are currently supported."}, + {"reason": "Address must be currently unassigned.", "field": "address"}]}' + headers: + 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: + - '*' + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Content-Length: + - "153" + Content-Type: + - application/json + Expires: + - Thu, 12 Sep 2024 19:48:43 GMT + Pragma: + - no-cache + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Frame-Options: + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "800" + status: 400 Bad Request + code: 400 + duration: "" +- request: + body: '{"type":"ipv4","public":false,"address":"23.92.21.220"}' + 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/63837167/ips + method: POST + response: + body: '{"errors": [{"reason": "Cannot reserve a private address.", "field": "address"}]}' + headers: + 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: + - '*' + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Content-Length: + - "81" + Content-Type: + - application/json + Expires: + - Thu, 12 Sep 2024 19:48:43 GMT + Pragma: + - no-cache + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Frame-Options: + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "800" + status: 400 Bad Request + code: 400 + duration: "" +- request: + body: '{"type":"ipv4","public":true,"address":"12345"}' + 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/63837167/ips + method: POST + response: + body: '{"errors": [{"reason": "Must provide a valid reserved address", "field": + "address"}]}' + headers: + 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: + - '*' + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Content-Length: + - "85" + Content-Type: + - application/json + Expires: + - Thu, 12 Sep 2024 19:48:43 GMT + Pragma: + - no-cache + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Frame-Options: + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "800" + status: 400 Bad Request + code: 400 + duration: "" +- request: + body: '{"type":"ipv4","public":true,"address":""}' + 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/63837167/ips + method: POST + response: + body: '{"errors": [{"reason": "Must provide a valid reserved address", "field": + "address"}]}' + headers: + 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: + - '*' + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Content-Length: + - "85" + Content-Type: + - application/json + Expires: + - Thu, 12 Sep 2024 19:48:43 GMT + Pragma: + - no-cache + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Frame-Options: + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "800" + status: 400 Bad Request + code: 400 + duration: "" +- request: + body: '{"type":"ipv4","public":true,"address":""}' + 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/63837167/ips + method: POST + response: + body: '{"errors": [{"reason": "Must provide a valid reserved address", "field": + "address"}]}' + headers: + 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: + - '*' + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Content-Length: + - "85" + Content-Type: + - application/json + Expires: + - Thu, 12 Sep 2024 19:48:44 GMT + Pragma: + - no-cache + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Frame-Options: + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "800" + status: 400 Bad Request + code: 400 + duration: "" +- request: + body: '{"type":"ipv4","public":true,"address":""}' + 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/63837167/ips + method: POST + response: + body: '{"errors": [{"reason": "Must provide a valid reserved address", "field": + "address"}]}' + headers: + 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: + - '*' + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Content-Length: + - "85" + Content-Type: + - application/json + Expires: + - Thu, 12 Sep 2024 19:48:44 GMT + Pragma: + - no-cache + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Frame-Options: + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "800" + status: 400 Bad Request + code: 400 + 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/networking/reserved/ips/172.105.0.89 + 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "2" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Thu, 12 Sep 2024 19:48:44 GMT + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - ips: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/networking/reserved/ips/23.92.21.220 + 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "2" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Thu, 12 Sep 2024 19:48:44 GMT + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - ips: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/63837167 + 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "2" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Thu, 12 Sep 2024 19:48:46 GMT + Pragma: + - no-cache + 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: + - "800" + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" diff --git a/test/integration/fixtures/TestInstance_CreateWithAlreadyAssignedReservedIP.yaml b/test/integration/fixtures/TestInstance_CreateWithAlreadyAssignedReservedIP.yaml new file mode 100644 index 00000000..7d995a2f --- /dev/null +++ b/test/integration/fixtures/TestInstance_CreateWithAlreadyAssignedReservedIP.yaml @@ -0,0 +1,303 @@ +--- +version: 1 +interactions: +- request: + body: '{"region":"us-east"}' + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - linodego/dev https://github.com/linode/linodego + url: https://api.linode.com/v4beta/networking/reserved/ips + method: POST + response: + body: '{"address": "172.104.28.100", "gateway": "172.104.28.1", "subnet_mask": + "255.255.255.0", "prefix": 24, "type": "ipv4", "public": true, "rdns": "172-104-28-100.ip.linodeusercontent.com", + "linode_id": null, "region": "us-east", "vpc_nat_1_1": null, "reserved": 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "264" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Thu, 12 Sep 2024 16:44:18 GMT + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - ips:read_write + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "800" + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: '{"region":"us-east","type":"g6-nanode-1","label":"go-test-ins-reserved-ip-5joh9oqb2908","root_pass":"?Mw;l]:[\u00262x^pK4819J9y[=623gC0qlLFj9?\u003e2ia6RSM!HHpc1Z;NG3r3Kz.=Mb]","image":"linode/alpine3.17","interfaces":[{"purpose":"public"}],"booted":false,"ipv4":["172.104.28.100"]}' + 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": 63830251, "label": "go-test-ins-reserved-ip-5joh9oqb2908", "group": + "", "status": "provisioning", "created": "2018-01-02T03:04:05", "updated": "2018-01-02T03:04:05", + "type": "g6-nanode-1", "ipv4": ["172.104.28.100"], "ipv6": "2600:3c03::f03c:95ff:fea5:b601/128", + "image": "linode/alpine3.17", "region": "us-east", "site_type": "core", "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": "e2b2194e60c6054585feb7014b294d65664c16a9", "has_user_data": + false, "placement_group": null, "disk_encryption": "disabled", "lke_cluster_id": + null, "capabilities": []}' + 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Thu, 12 Sep 2024 16:44:19 GMT + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + - Accept-Encoding + 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: '{"region":"us-east","type":"g6-nanode-1","label":"go-test-ins-reserved-ip-lm38753c0ooi","root_pass":"B8c03IyO8!+xfZt439xEpv#5n3H9HoJ^P\\^\u003c`2|XqgLZ9TDtXGq=04f\u003e4''$|.l}4","image":"linode/alpine3.17","interfaces":[{"purpose":"public"}],"booted":false,"ipv4":["172.104.28.100"]}' + 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: '{"errors": [{"reason": "Address must be currently unassigned.", "field": + "ipv4"}]}' + headers: + 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: + - '*' + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Content-Length: + - "82" + Content-Type: + - application/json + Expires: + - Thu, 12 Sep 2024 16:44:19 GMT + Pragma: + - no-cache + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Frame-Options: + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "10" + status: 400 Bad Request + code: 400 + 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/63830251 + 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "2" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Thu, 12 Sep 2024 16:44:21 GMT + Pragma: + - no-cache + 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: + - "800" + 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/networking/reserved/ips/172.104.28.100 + 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "2" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Thu, 12 Sep 2024 16:44:22 GMT + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - ips: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: "" diff --git a/test/integration/fixtures/TestInstance_CreateWithEmptyIPAddress.yaml b/test/integration/fixtures/TestInstance_CreateWithEmptyIPAddress.yaml new file mode 100644 index 00000000..135f1d7d --- /dev/null +++ b/test/integration/fixtures/TestInstance_CreateWithEmptyIPAddress.yaml @@ -0,0 +1,180 @@ +--- +version: 1 +interactions: +- request: + body: '{"region":"us-east","type":"g6-nanode-1","label":"go-test-ins-reserved-ip-2erk03yy2m36","root_pass":".H?9RM6V''ixIX),:X+?UP6[[tdg4wpQ5EnccaV2,@+l8FSw@2F58\u003ci3o16Cn68?6","image":"linode/alpine3.17","interfaces":[{"purpose":"public"}],"booted":false,"ipv4":[""]}' + 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: '{"errors": [{"reason": "Too many requests"}]}' + headers: + 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: + - '*' + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Content-Length: + - "45" + Content-Type: + - application/json + Expires: + - Thu, 12 Sep 2024 16:44:22 GMT + Pragma: + - no-cache + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Frame-Options: + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "5" + status: 429 Too Many Requests + code: 429 + duration: "" +- request: + body: '{"region":"us-east","type":"g6-nanode-1","label":"go-test-ins-reserved-ip-2erk03yy2m36","root_pass":".H?9RM6V''ixIX),:X+?UP6[[tdg4wpQ5EnccaV2,@+l8FSw@2F58\u003ci3o16Cn68?6","image":"linode/alpine3.17","interfaces":[{"purpose":"public"}],"booted":false,"ipv4":[""]}' + 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: '{"errors": [{"reason": "Too many requests"}]}' + headers: + 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: + - '*' + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Content-Length: + - "45" + Content-Type: + - application/json + Expires: + - Thu, 12 Sep 2024 16:44:25 GMT + Pragma: + - no-cache + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Frame-Options: + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "5" + status: 429 Too Many Requests + code: 429 + duration: "" +- request: + body: '{"region":"us-east","type":"g6-nanode-1","label":"go-test-ins-reserved-ip-2erk03yy2m36","root_pass":".H?9RM6V''ixIX),:X+?UP6[[tdg4wpQ5EnccaV2,@+l8FSw@2F58\u003ci3o16Cn68?6","image":"linode/alpine3.17","interfaces":[{"purpose":"public"}],"booted":false,"ipv4":[""]}' + 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: '{"errors": [{"reason": "Too many requests"}]}' + headers: + 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: + - '*' + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Content-Length: + - "45" + Content-Type: + - application/json + Expires: + - Thu, 12 Sep 2024 16:44:29 GMT + Pragma: + - no-cache + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Frame-Options: + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "5" + status: 429 Too Many Requests + code: 429 + duration: "" +- request: + body: '{"region":"us-east","type":"g6-nanode-1","label":"go-test-ins-reserved-ip-2erk03yy2m36","root_pass":".H?9RM6V''ixIX),:X+?UP6[[tdg4wpQ5EnccaV2,@+l8FSw@2F58\u003ci3o16Cn68?6","image":"linode/alpine3.17","interfaces":[{"purpose":"public"}],"booted":false,"ipv4":[""]}' + 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: '{"errors": [{"reason": "Must provide a single valid reserved ipv4 address", + "field": "ipv4"}]}' + headers: + 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: + - '*' + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Content-Length: + - "94" + Content-Type: + - application/json + Expires: + - Thu, 12 Sep 2024 16:44:32 GMT + Pragma: + - no-cache + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Frame-Options: + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "10" + status: 400 Bad Request + code: 400 + duration: "" diff --git a/test/integration/fixtures/TestInstance_CreateWithMultipleIPAddresses.yaml b/test/integration/fixtures/TestInstance_CreateWithMultipleIPAddresses.yaml new file mode 100644 index 00000000..bfd65fc0 --- /dev/null +++ b/test/integration/fixtures/TestInstance_CreateWithMultipleIPAddresses.yaml @@ -0,0 +1,304 @@ +--- +version: 1 +interactions: +- request: + body: '{"region":"us-east"}' + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - linodego/dev https://github.com/linode/linodego + url: https://api.linode.com/v4beta/networking/reserved/ips + method: POST + response: + body: '{"address": "66.228.42.57", "gateway": "66.228.42.1", "subnet_mask": "255.255.255.0", + "prefix": 24, "type": "ipv4", "public": true, "rdns": "66-228-42-57.ip.linodeusercontent.com", + "linode_id": null, "region": "us-east", "vpc_nat_1_1": null, "reserved": 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "259" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Thu, 12 Sep 2024 16:44:36 GMT + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - ips:read_write + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "800" + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: '{"region":"us-east","type":"g6-nanode-1","label":"go-test-ins-reserved-ip-4rc1sui21a14","root_pass":"E1dxAxLSB0}\u003c977C=n+5u1g@x4tOx/,5rav03~W''7!]7#lgOJRLO.0Zm$}52f-LT","image":"linode/alpine3.17","interfaces":[{"purpose":"public"}],"booted":false,"ipv4":["66.228.42.57","192.0.2.2"]}' + 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: '{"errors": [{"reason": "Too many requests"}]}' + headers: + 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: + - '*' + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Content-Length: + - "45" + Content-Type: + - application/json + Expires: + - Thu, 12 Sep 2024 16:44:36 GMT + Pragma: + - no-cache + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Frame-Options: + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "10" + status: 429 Too Many Requests + code: 429 + duration: "" +- request: + body: '{"region":"us-east","type":"g6-nanode-1","label":"go-test-ins-reserved-ip-4rc1sui21a14","root_pass":"E1dxAxLSB0}\u003c977C=n+5u1g@x4tOx/,5rav03~W''7!]7#lgOJRLO.0Zm$}52f-LT","image":"linode/alpine3.17","interfaces":[{"purpose":"public"}],"booted":false,"ipv4":["66.228.42.57","192.0.2.2"]}' + 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: '{"errors": [{"reason": "Too many requests"}]}' + headers: + 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: + - '*' + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Content-Length: + - "45" + Content-Type: + - application/json + Expires: + - Thu, 12 Sep 2024 16:44:39 GMT + Pragma: + - no-cache + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Frame-Options: + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "10" + status: 429 Too Many Requests + code: 429 + duration: "" +- request: + body: '{"region":"us-east","type":"g6-nanode-1","label":"go-test-ins-reserved-ip-4rc1sui21a14","root_pass":"E1dxAxLSB0}\u003c977C=n+5u1g@x4tOx/,5rav03~W''7!]7#lgOJRLO.0Zm$}52f-LT","image":"linode/alpine3.17","interfaces":[{"purpose":"public"}],"booted":false,"ipv4":["66.228.42.57","192.0.2.2"]}' + 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: '{"errors": [{"reason": "Too many requests"}]}' + headers: + 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: + - '*' + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Content-Length: + - "45" + Content-Type: + - application/json + Expires: + - Thu, 12 Sep 2024 16:44:43 GMT + Pragma: + - no-cache + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Frame-Options: + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "10" + status: 429 Too Many Requests + code: 429 + duration: "" +- request: + body: '{"region":"us-east","type":"g6-nanode-1","label":"go-test-ins-reserved-ip-4rc1sui21a14","root_pass":"E1dxAxLSB0}\u003c977C=n+5u1g@x4tOx/,5rav03~W''7!]7#lgOJRLO.0Zm$}52f-LT","image":"linode/alpine3.17","interfaces":[{"purpose":"public"}],"booted":false,"ipv4":["66.228.42.57","192.0.2.2"]}' + 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: '{"errors": [{"reason": "Must provide a single valid reserved ipv4 address", + "field": "ipv4"}]}' + headers: + 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: + - '*' + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Content-Length: + - "94" + Content-Type: + - application/json + Expires: + - Thu, 12 Sep 2024 16:44:46 GMT + Pragma: + - no-cache + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Frame-Options: + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "10" + status: 400 Bad Request + code: 400 + 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/networking/reserved/ips/66.228.42.57 + 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "2" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Thu, 12 Sep 2024 16:44:46 GMT + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - ips: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: "" diff --git a/test/integration/fixtures/TestInstance_CreateWithNonOwnedReservedAddress.yaml b/test/integration/fixtures/TestInstance_CreateWithNonOwnedReservedAddress.yaml new file mode 100644 index 00000000..31c14662 --- /dev/null +++ b/test/integration/fixtures/TestInstance_CreateWithNonOwnedReservedAddress.yaml @@ -0,0 +1,48 @@ +--- +version: 1 +interactions: +- request: + body: '{"region":"us-east","type":"g6-nanode-1","label":"go-test-ins-reserved-ip-x34lc083oko4","root_pass":"}VsdSi,{!omez2A1BMU7J7p`41z1ER6-rs=hD,151f2\u003e/81q\\SJNg].Rz7Q=`Z\u00262","image":"linode/alpine3.17","interfaces":[{"purpose":"public"}],"booted":false,"ipv4":["198.51.100.1"]}' + 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: '{"errors": [{"reason": "Must provide a single valid reserved ipv4 address", + "field": "ipv4"}]}' + headers: + 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: + - '*' + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Content-Length: + - "94" + Content-Type: + - application/json + Expires: + - Thu, 12 Sep 2024 16:44:22 GMT + Pragma: + - no-cache + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Frame-Options: + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "10" + status: 400 Bad Request + code: 400 + duration: "" diff --git a/test/integration/fixtures/TestInstance_CreateWithNonReservedAddress.yaml b/test/integration/fixtures/TestInstance_CreateWithNonReservedAddress.yaml new file mode 100644 index 00000000..bc8140ae --- /dev/null +++ b/test/integration/fixtures/TestInstance_CreateWithNonReservedAddress.yaml @@ -0,0 +1,48 @@ +--- +version: 1 +interactions: +- request: + body: '{"region":"us-east","type":"g6-nanode-1","label":"go-test-ins-reserved-ip-or7801td3le2","root_pass":"NJ361jSqj5#YLI;4I33S\u0026|C\\LlW74Bp!b9=g35b?[O0mU|7jnW''.ci*d)(0[9Pat","image":"linode/alpine3.17","interfaces":[{"purpose":"public"}],"booted":false,"ipv4":["192.0.2.1"]}' + 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: '{"errors": [{"reason": "Must provide a single valid reserved ipv4 address", + "field": "ipv4"}]}' + headers: + 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: + - '*' + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Content-Length: + - "94" + Content-Type: + - application/json + Expires: + - Thu, 12 Sep 2024 16:44:22 GMT + Pragma: + - no-cache + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Frame-Options: + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "10" + status: 400 Bad Request + code: 400 + duration: "" diff --git a/test/integration/fixtures/TestInstance_CreateWithNullIPAddress.yaml b/test/integration/fixtures/TestInstance_CreateWithNullIPAddress.yaml new file mode 100644 index 00000000..127653d0 --- /dev/null +++ b/test/integration/fixtures/TestInstance_CreateWithNullIPAddress.yaml @@ -0,0 +1,134 @@ +--- +version: 1 +interactions: +- request: + body: '{"region":"us-east","type":"g6-nanode-1","label":"go-test-ins-reserved-ip-vym5299ve91d","root_pass":"!86lC/O''5Q3\u0026(H3vb0LD4@Tu0JaM''Wo0N4ja13yj~)?qUA/f@.x/0=aM60o=4mHB","image":"linode/alpine3.17","interfaces":[{"purpose":"public"}],"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": 63830264, "label": "go-test-ins-reserved-ip-vym5299ve91d", "group": + "", "status": "provisioning", "created": "2018-01-02T03:04:05", "updated": "2018-01-02T03:04:05", + "type": "g6-nanode-1", "ipv4": ["45.56.104.17"], "ipv6": "2600:3c03::f03c:95ff:fea5:b690/128", + "image": "linode/alpine3.17", "region": "us-east", "site_type": "core", "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": "c6618489f09422003470c02e7f12a3e0b5303ddb", "has_user_data": + false, "placement_group": null, "disk_encryption": "disabled", "lke_cluster_id": + null, "capabilities": []}' + 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Thu, 12 Sep 2024 16:44:34 GMT + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + - Accept-Encoding + 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/63830264 + 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "2" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Thu, 12 Sep 2024 16:44:36 GMT + Pragma: + - no-cache + 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: + - "800" + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" diff --git a/test/integration/fixtures/TestInstance_CreateWithOwnedNonAssignedReservedIP.yaml b/test/integration/fixtures/TestInstance_CreateWithOwnedNonAssignedReservedIP.yaml new file mode 100644 index 00000000..7eeb83aa --- /dev/null +++ b/test/integration/fixtures/TestInstance_CreateWithOwnedNonAssignedReservedIP.yaml @@ -0,0 +1,258 @@ +--- +version: 1 +interactions: +- request: + body: '{"region":"us-east"}' + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - linodego/dev https://github.com/linode/linodego + url: https://api.linode.com/v4beta/networking/reserved/ips + method: POST + response: + body: '{"address": "172.104.28.70", "gateway": "172.104.28.1", "subnet_mask": + "255.255.255.0", "prefix": 24, "type": "ipv4", "public": true, "rdns": "172-104-28-70.ip.linodeusercontent.com", + "linode_id": null, "region": "us-east", "vpc_nat_1_1": null, "reserved": 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "262" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Thu, 12 Sep 2024 16:44:14 GMT + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - ips:read_write + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "800" + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: '{"region":"us-east","type":"g6-nanode-1","label":"go-test-ins-reserved-ip-vsr6v8p5t918","root_pass":"SO#sQ!0],LgsF3BJ0B(5\u003e}By6q2+\u0026c1fi{C\u0026f4=c?x2R!@Eiz+4iT742G7eb9JC7","image":"linode/alpine3.17","interfaces":[{"purpose":"public"}],"booted":false,"ipv4":["172.104.28.70"]}' + 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": 63830249, "label": "go-test-ins-reserved-ip-vsr6v8p5t918", "group": + "", "status": "provisioning", "created": "2018-01-02T03:04:05", "updated": "2018-01-02T03:04:05", + "type": "g6-nanode-1", "ipv4": ["172.104.28.70"], "ipv6": "2600:3c03::f03c:95ff:fea5:b656/128", + "image": "linode/alpine3.17", "region": "us-east", "site_type": "core", "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": "e2b2194e60c6054585feb7014b294d65664c16a9", "has_user_data": + false, "placement_group": null, "disk_encryption": "disabled", "lke_cluster_id": + null, "capabilities": []}' + 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Thu, 12 Sep 2024 16:44:15 GMT + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + - Accept-Encoding + 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/63830249 + 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "2" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Thu, 12 Sep 2024 16:44:17 GMT + Pragma: + - no-cache + 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: + - "800" + 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/networking/reserved/ips/172.104.28.70 + 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "2" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Thu, 12 Sep 2024 16:44:17 GMT + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - ips: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: "" diff --git a/test/integration/fixtures/TestInstance_CreateWithReservedIPAddress.yaml b/test/integration/fixtures/TestInstance_CreateWithReservedIPAddress.yaml new file mode 100644 index 00000000..6615c220 --- /dev/null +++ b/test/integration/fixtures/TestInstance_CreateWithReservedIPAddress.yaml @@ -0,0 +1,259 @@ +--- +version: 1 +interactions: +- request: + body: '{"region":"us-east"}' + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - linodego/dev https://github.com/linode/linodego + url: https://api.linode.com/v4beta/networking/reserved/ips + method: POST + response: + body: '{"address": "172.104.20.68", "gateway": "172.104.20.1", "subnet_mask": + "255.255.255.0", "prefix": 24, "type": "ipv4", "public": true, "rdns": "172-104-20-68.ip.linodeusercontent.com", + "linode_id": null, "region": "us-east", "vpc_nat_1_1": null, "reserved": 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "262" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Tue, 03 Sep 2024 19:13:05 GMT + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - ips: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":"us-east","type":"g6-nanode-1","label":"go-test-ins-reserved-ip-x0or7k0186hu","root_pass":"?6I~^OU95=viKV8$wb,Q=`dUCjq8x''8l^z0m4KD~8c6F\u003e-6\u003eW60I6Cf6Ln2#Gca$","image":"linode/alpine3.17","interfaces":[{"purpose":"public"}],"booted":false,"ipv4":["172.104.20.68"]}' + 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": 63432426, "label": "go-test-ins-reserved-ip-x0or7k0186hu", "group": + "", "status": "provisioning", "created": "2018-01-02T03:04:05", "updated": "2018-01-02T03:04:05", + "type": "g6-nanode-1", "ipv4": ["172.104.20.68"], "ipv6": "2600:3c03::f03c:95ff:fec2:4ccc/128", + "image": "linode/alpine3.17", "region": "us-east", "site_type": "core", "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": "d5c60a121fe8f306350b432af2263337c9e0495a", "has_user_data": + false, "placement_group": null, "disk_encryption": "disabled", "lke_cluster_id": + 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "857" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Tue, 03 Sep 2024 19:13:06 GMT + Pragma: + - no-cache + 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/63432426 + 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "2" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Tue, 03 Sep 2024 19:13:08 GMT + Pragma: + - no-cache + 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/networking/reserved/ips/172.104.20.68 + 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "2" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Tue, 03 Sep 2024 19:13:08 GMT + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - ips: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: "" diff --git a/test/integration/fixtures/TestInstance_CreateWithReservedIPAddressVariants.yaml b/test/integration/fixtures/TestInstance_CreateWithReservedIPAddressVariants.yaml new file mode 100644 index 00000000..d7c1fd9b --- /dev/null +++ b/test/integration/fixtures/TestInstance_CreateWithReservedIPAddressVariants.yaml @@ -0,0 +1,748 @@ +--- +version: 1 +interactions: +- request: + body: '{"region":"us-east"}' + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - linodego/dev https://github.com/linode/linodego + url: https://api.linode.com/v4beta/networking/reserved/ips + method: POST + response: + body: '{"address": "172.104.20.77", "gateway": "172.104.20.1", "subnet_mask": + "255.255.255.0", "prefix": 24, "type": "ipv4", "public": true, "rdns": "172-104-20-77.ip.linodeusercontent.com", + "linode_id": null, "region": "us-east", "vpc_nat_1_1": null, "reserved": 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "262" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Tue, 03 Sep 2024 19:13:08 GMT + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - ips: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":"us-east","type":"g6-nanode-1","label":"go-test-ins-reserved-ip-776ugys2x84t","root_pass":"9Nf1L;\u003e6ajieNPt\\X+2gP+8~rB`uJ22c;\u003e03C9Na40J}-}:)lQlj1[Y7qs-59UFV","image":"linode/alpine3.17","interfaces":[{"purpose":"public"}],"booted":false,"ipv4":["172.104.20.77"]}' + 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": 63432429, "label": "go-test-ins-reserved-ip-776ugys2x84t", "group": + "", "status": "provisioning", "created": "2018-01-02T03:04:05", "updated": "2018-01-02T03:04:05", + "type": "g6-nanode-1", "ipv4": ["172.104.20.77"], "ipv6": "2600:3c03::f03c:95ff:fec2:4c1b/128", + "image": "linode/alpine3.17", "region": "us-east", "site_type": "core", "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": "d5c60a121fe8f306350b432af2263337c9e0495a", "has_user_data": + false, "placement_group": null, "disk_encryption": "disabled", "lke_cluster_id": + 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "857" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Tue, 03 Sep 2024 19:13:09 GMT + Pragma: + - no-cache + 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: '{"region":"us-east","type":"g6-nanode-1","label":"go-test-ins-reserved-ip-k834ai1y8j2a","root_pass":"~um0O^Z`j5S=4tRxo(4pAn+;8eA4[2?zWOg5[8P3szYRfx;9X97|f4~8V:2QM=\u003eU","image":"linode/alpine3.17","interfaces":[{"purpose":"public"}],"booted":false,"ipv4":["172.104.20.77"]}' + 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: '{"errors": [{"reason": "Address must be currently unassigned.", "field": + "ipv4"}]}' + headers: + 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: + - '*' + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Content-Length: + - "82" + Content-Type: + - application/json + Expires: + - Tue, 03 Sep 2024 19:13:09 GMT + Pragma: + - no-cache + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Frame-Options: + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "10" + status: 400 Bad Request + code: 400 + duration: "" +- request: + body: '{"region":"us-east","type":"g6-nanode-1","label":"go-test-ins-reserved-ip-k13vw921yh5i","root_pass":"@g\\27J,2J$aX5xj$4v-\u003c3,Ny7nc5{WvY:''pDH7Vj1E45:9MjxP{=s14Kv$b-S5SD","image":"linode/alpine3.17","interfaces":[{"purpose":"public"}],"booted":false,"ipv4":["192.0.2.1"]}' + 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: '{"errors": [{"reason": "Must provide a single valid reserved ipv4 address", + "field": "ipv4"}]}' + headers: + 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: + - '*' + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Content-Length: + - "94" + Content-Type: + - application/json + Expires: + - Tue, 03 Sep 2024 19:13:09 GMT + Pragma: + - no-cache + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Frame-Options: + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "10" + status: 400 Bad Request + code: 400 + duration: "" +- request: + body: '{"region":"us-east","type":"g6-nanode-1","label":"go-test-ins-reserved-ip-k7zhi2807xk8","root_pass":"0BDN\\iia1C`\u0026O45tXS4[@7;0lF8)W+k[NRn6v3Y5ZtM/8e81xpwT[)i[f-\\-H1u4","image":"linode/alpine3.17","interfaces":[{"purpose":"public"}],"booted":false,"ipv4":["198.51.100.1"]}' + 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: '{"errors": [{"reason": "Must provide a single valid reserved ipv4 address", + "field": "ipv4"}]}' + headers: + 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: + - '*' + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Content-Length: + - "94" + Content-Type: + - application/json + Expires: + - Tue, 03 Sep 2024 19:13:09 GMT + Pragma: + - no-cache + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Frame-Options: + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "10" + status: 400 Bad Request + code: 400 + duration: "" +- request: + body: '{"region":"us-east","type":"g6-nanode-1","label":"go-test-ins-reserved-ip-n9ssc0141zh7","root_pass":":LD8t4cgg|164/p=L151I3\\WdMAkw]Vw3O5;+E)bAg,9\\b58Sc`u5`d)E\u003e3]GBZk","image":"linode/alpine3.17","interfaces":[{"purpose":"public"}],"booted":false,"ipv4":[""]}' + 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: '{"errors": [{"reason": "Must provide a single valid reserved ipv4 address", + "field": "ipv4"}]}' + headers: + 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: + - '*' + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Content-Length: + - "94" + Content-Type: + - application/json + Expires: + - Tue, 03 Sep 2024 19:13:22 GMT + Pragma: + - no-cache + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Frame-Options: + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "10" + status: 400 Bad Request + code: 400 + duration: "" +- request: + body: '{"region":"us-east","type":"g6-nanode-1","label":"go-test-ins-reserved-ip-e14gz6bc5p37","root_pass":"KjQ13TO2`g}huOSKKe3988}([j(o#[P]]e08tXUqd=?B3A87l12hOlU4I|\u003el9\u003eh/","image":"linode/alpine3.17","interfaces":[{"purpose":"public"}],"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": 63432443, "label": "go-test-ins-reserved-ip-e14gz6bc5p37", "group": + "", "status": "provisioning", "created": "2018-01-02T03:04:05", "updated": "2018-01-02T03:04:05", + "type": "g6-nanode-1", "ipv4": ["97.107.138.251"], "ipv6": "2600:3c03::f03c:95ff:fec2:4c10/128", + "image": "linode/alpine3.17", "region": "us-east", "site_type": "core", "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": "9c7219f8e3e33875047e6b169b3f167a43218198", "has_user_data": + false, "placement_group": null, "disk_encryption": "disabled", "lke_cluster_id": + 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "858" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Tue, 03 Sep 2024 19:13:38 GMT + Pragma: + - no-cache + 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: '{"region":"us-east","type":"g6-nanode-1","label":"go-test-ins-reserved-ip-3bly0ps6071m","root_pass":"H`X!T5x{D.4(J3k05dY,1IG=T/6e87DoN\\6DF@Bp8?4/.Nscw=qxn{4W4cluv91''","image":"linode/alpine3.17","interfaces":[{"purpose":"public"}],"booted":false,"ipv4":["172.104.20.77","192.0.2.2"]}' + 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: '{"errors": [{"reason": "Must provide a single valid reserved ipv4 address", + "field": "ipv4"}]}' + headers: + 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: + - '*' + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Content-Length: + - "94" + Content-Type: + - application/json + Expires: + - Tue, 03 Sep 2024 19:13:38 GMT + Pragma: + - no-cache + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Frame-Options: + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "10" + status: 400 Bad Request + code: 400 + duration: "" +- request: + body: '{"region":"us-east","type":"g6-nanode-1","label":"go-test-ins-reserved-ip-bw5b43pih670","root_pass":"wqx^Q)\u003ca\u0026))H`MV4n+ZT6geC53w3jV(n{F6JzG9G5h01jw97;/FxFi6HR?=:\\640","image":"linode/alpine3.17","interfaces":[{"purpose":"public"}],"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": 63432444, "label": "go-test-ins-reserved-ip-bw5b43pih670", "group": + "", "status": "provisioning", "created": "2018-01-02T03:04:05", "updated": "2018-01-02T03:04:05", + "type": "g6-nanode-1", "ipv4": ["45.33.68.112"], "ipv6": "2600:3c03::f03c:95ff:fec2:4c8b/128", + "image": "linode/alpine3.17", "region": "us-east", "site_type": "core", "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": "feeaaa559bcc85eaf49df4ff34238607aee5ad94", "has_user_data": + false, "placement_group": null, "disk_encryption": "disabled", "lke_cluster_id": + 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "856" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Tue, 03 Sep 2024 19:13:39 GMT + Pragma: + - no-cache + 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/63432444 + 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "2" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Tue, 03 Sep 2024 19:13:41 GMT + Pragma: + - no-cache + 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/63432443 + 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "2" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Tue, 03 Sep 2024 19:13:43 GMT + Pragma: + - no-cache + 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/63432429 + 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "2" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Tue, 03 Sep 2024 19:13:44 GMT + Pragma: + - no-cache + 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/networking/reserved/ips/172.104.20.77 + 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "2" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Tue, 03 Sep 2024 19:13:44 GMT + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - ips: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: "" diff --git a/test/integration/fixtures/TestInstance_CreateWithoutIPv4Field.yaml b/test/integration/fixtures/TestInstance_CreateWithoutIPv4Field.yaml new file mode 100644 index 00000000..9f8cd454 --- /dev/null +++ b/test/integration/fixtures/TestInstance_CreateWithoutIPv4Field.yaml @@ -0,0 +1,134 @@ +--- +version: 1 +interactions: +- request: + body: '{"region":"us-east","type":"g6-nanode-1","label":"go-test-ins-reserved-ip-le6w459su62x","root_pass":"j\\9[AV1,4@91t=V7nB2;QW8~dsmoWfK,b@A9g-K\u003cRr3xBn{11|i8TJzc\u0026:Q$H663","image":"linode/alpine3.17","interfaces":[{"purpose":"public"}],"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": 63830274, "label": "go-test-ins-reserved-ip-le6w459su62x", "group": + "", "status": "provisioning", "created": "2018-01-02T03:04:05", "updated": "2018-01-02T03:04:05", + "type": "g6-nanode-1", "ipv4": ["45.56.104.28"], "ipv6": "2600:3c03::f03c:95ff:fea5:92e5/128", + "image": "linode/alpine3.17", "region": "us-east", "site_type": "core", "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": "c6618489f09422003470c02e7f12a3e0b5303ddb", "has_user_data": + false, "placement_group": null, "disk_encryption": "disabled", "lke_cluster_id": + null, "capabilities": []}' + 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Thu, 12 Sep 2024 16:44:48 GMT + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + - Accept-Encoding + 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/63830274 + 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 + Akamai-Internal-Account: + - '*' + Cache-Control: + - max-age=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "2" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Expires: + - Thu, 12 Sep 2024 16:44:50 GMT + Pragma: + - no-cache + 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: + - "800" + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" diff --git a/test/integration/instance_reserved_ips_test.go b/test/integration/instance_reserved_ips_test.go new file mode 100644 index 00000000..e1f55af6 --- /dev/null +++ b/test/integration/instance_reserved_ips_test.go @@ -0,0 +1,456 @@ +package integration + +import ( + "context" + "testing" + + "github.com/linode/linodego" +) + +func TestInstance_CreateWithReservedIPAddress(t *testing.T) { + client, teardown := createTestClient(t, "fixtures/TestInstance_CreateWithReservedIPAddress") + defer teardown() + + // Reserve an IP for testing + reservedIP, err := client.ReserveIPAddress(context.Background(), linodego.ReserveIPOptions{Region: "us-east"}) + if err != nil { + t.Fatalf("Failed to reserve IP: %v", err) + } + defer func() { + err := client.DeleteReservedIPAddress(context.Background(), reservedIP.Address) + if err != nil { + t.Errorf("Failed to delete reserved IP: %v", err) + } + }() + + _, instanceTeardown, err := createInstanceWithReservedIP(t, client, reservedIP.Address) + defer instanceTeardown() + if err != nil { + t.Fatalf("Error creating instance with reserved IP: %s", err) + } + +} + +func createInstanceWithReservedIP( + t *testing.T, + client *linodego.Client, + reservedIP string, + modifiers ...instanceModifier, +) (*linodego.Instance, func(), error) { + t.Helper() + + createOpts := linodego.InstanceCreateOptions{ + Label: "go-test-ins-reserved-ip-" + randLabel(), + Region: "us-east", + Type: "g6-nanode-1", + Booted: linodego.Pointer(false), + Image: "linode/alpine3.17", + RootPass: randPassword(), + Interfaces: []linodego.InstanceConfigInterfaceCreateOptions{ + { + Purpose: linodego.InterfacePurposePublic, + Label: "", + IPAMAddress: "", + }, + }, + IPv4: []string{reservedIP}, + } + + for _, modifier := range modifiers { + modifier(client, &createOpts) + } + + instance, err := client.CreateInstance(context.Background(), createOpts) + if err != nil { + return nil, func() {}, err + } + + teardown := func() { + if terr := client.DeleteInstance(context.Background(), instance.ID); terr != nil { + t.Errorf("Error deleting test Instance: %s", terr) + } + } + + return instance, teardown, nil +} + +func TestInstance_CreateWithOwnedNonAssignedReservedIP(t *testing.T) { + client, teardown := createTestClient(t, "fixtures/TestInstance_CreateWithOwnedNonAssignedReservedIP") + defer teardown() + + reservedIP, err := client.ReserveIPAddress(context.Background(), linodego.ReserveIPOptions{Region: "us-east"}) + if err != nil { + t.Fatalf("Failed to reserve IP: %v", err) + } + defer func() { + err := client.DeleteReservedIPAddress(context.Background(), reservedIP.Address) + if err != nil { + t.Errorf("Failed to delete reserved IP: %v", err) + } + }() + + _, instanceTeardown, err := createInstanceWithReservedIP(t, client, reservedIP.Address) + defer instanceTeardown() + if err != nil { + t.Errorf("Unexpected error with owned non-assigned reserved IP: %v", err) + } +} + +func TestInstance_CreateWithAlreadyAssignedReservedIP(t *testing.T) { + client, teardown := createTestClient(t, "fixtures/TestInstance_CreateWithAlreadyAssignedReservedIP") + defer teardown() + + reservedIP, err := client.ReserveIPAddress(context.Background(), linodego.ReserveIPOptions{Region: "us-east"}) + if err != nil { + t.Fatalf("Failed to reserve IP: %v", err) + } + defer func() { + err := client.DeleteReservedIPAddress(context.Background(), reservedIP.Address) + if err != nil { + t.Errorf("Failed to delete reserved IP: %v", err) + } + }() + + // First, create an instance with the reserved IP + _, instanceTeardown, err := createInstanceWithReservedIP(t, client, reservedIP.Address) + defer instanceTeardown() + if err != nil { + t.Fatalf("Failed to create initial instance: %v", err) + } + + // Now try to create another instance with the same IP + _, secondInstanceTeardown, err := createInstanceWithReservedIP(t, client, reservedIP.Address) + defer secondInstanceTeardown() + if err == nil { + t.Errorf("Expected error with already assigned reserved IP, but got none") + } +} + +func TestInstance_CreateWithNonReservedAddress(t *testing.T) { + client, teardown := createTestClient(t, "fixtures/TestInstance_CreateWithNonReservedAddress") + defer teardown() + + _, instanceTeardown, err := createInstanceWithReservedIP(t, client, "192.0.2.1") + defer instanceTeardown() + if err == nil { + t.Errorf("Expected error with non-reserved address, but got none") + } +} + +func TestInstance_CreateWithNonOwnedReservedAddress(t *testing.T) { + client, teardown := createTestClient(t, "fixtures/TestInstance_CreateWithNonOwnedReservedAddress") + defer teardown() + + _, instanceTeardown, err := createInstanceWithReservedIP(t, client, "198.51.100.1") + defer instanceTeardown() + if err == nil { + t.Errorf("Expected error with non-owned reserved address, but got none") + } +} + +func TestInstance_CreateWithEmptyIPAddress(t *testing.T) { + client, teardown := createTestClient(t, "fixtures/TestInstance_CreateWithEmptyIPAddress") + defer teardown() + + _, instanceTeardown, err := createInstanceWithReservedIP(t, client, "") + defer instanceTeardown() + if err == nil { + t.Errorf("Expected error with empty IP address, but got none") + } +} + +func TestInstance_CreateWithNullIPAddress(t *testing.T) { + client, teardown := createTestClient(t, "fixtures/TestInstance_CreateWithNullIPAddress") + defer teardown() + + _, instanceTeardown, err := createInstanceWithReservedIP(t, client, "", func(client *linodego.Client, opts *linodego.InstanceCreateOptions) { + opts.IPv4 = nil + }) + defer instanceTeardown() + if err != nil { + t.Errorf("Unexpected error with null IP address: %v", err) + } +} + +func TestInstance_CreateWithMultipleIPAddresses(t *testing.T) { + client, teardown := createTestClient(t, "fixtures/TestInstance_CreateWithMultipleIPAddresses") + defer teardown() + + reservedIP, err := client.ReserveIPAddress(context.Background(), linodego.ReserveIPOptions{Region: "us-east"}) + if err != nil { + t.Fatalf("Failed to reserve IP: %v", err) + } + defer func() { + err := client.DeleteReservedIPAddress(context.Background(), reservedIP.Address) + if err != nil { + t.Errorf("Failed to delete reserved IP: %v", err) + } + }() + + _, instanceTeardown, err := createInstanceWithReservedIP(t, client, "", func(client *linodego.Client, opts *linodego.InstanceCreateOptions) { + opts.IPv4 = []string{reservedIP.Address, "192.0.2.2"} + }) + defer instanceTeardown() + if err == nil { + t.Errorf("Expected error with multiple IP addresses, but got none") + } +} + +func TestInstance_CreateWithoutIPv4Field(t *testing.T) { + client, teardown := createTestClient(t, "fixtures/TestInstance_CreateWithoutIPv4Field") + defer teardown() + + _, instanceTeardown, err := createInstanceWithReservedIP(t, client, "", func(client *linodego.Client, opts *linodego.InstanceCreateOptions) { + opts.IPv4 = nil + }) + defer instanceTeardown() + if err != nil { + t.Errorf("Unexpected error when omitting IPv4 field: %v", err) + } +} + +func TestInstance_AddReservedIPToInstance(t *testing.T) { + client, teardown := createTestClient(t, "fixtures/TestInstance_AddReservedIPToInstance") + defer teardown() + + // Create a test Linode instance + instance, err := client.CreateInstance(context.Background(), linodego.InstanceCreateOptions{ + Region: "us-east", + Type: "g6-nanode-1", + Label: "test-instance-for-ip-reservation", + RootPass: randPassword(), + }) + if err != nil { + t.Fatalf("Error creating test instance: %v", err) + } + defer func() { + if err := client.DeleteInstance(context.Background(), instance.ID); err != nil { + t.Errorf("Error deleting test instance: %v", err) + } + }() + + // Reserve an IP address + reservedIP, err := client.ReserveIPAddress(context.Background(), linodego.ReserveIPOptions{ + Region: "us-east", + }) + if err != nil { + t.Fatalf("Error reserving IP address: %v", err) + } + defer func() { + if err := client.DeleteReservedIPAddress(context.Background(), reservedIP.Address); err != nil { + t.Errorf("Error deleting reserved IP: %v", err) + } + }() + + // Add the reserved IP to the instance + opts := linodego.InstanceReserveIPOptions{ + Type: "ipv4", + Public: true, + Address: reservedIP.Address, + } + _, err = client.AssignInstanceReservedIP(context.Background(), instance.ID, opts) + if err != nil { + t.Fatalf("Error adding reserved IP to instance: %v", err) + } + + // Verify the IP was added to the instance + ips, err := client.GetInstanceIPAddresses(context.Background(), instance.ID) + if err != nil { + t.Fatalf("Error getting instance IP addresses: %v", err) + } + + found := false + for _, ip := range ips.IPv4.Public { + if ip.Address == reservedIP.Address { + found = true + break + } + } + + if !found { + t.Errorf("Reserved IP %s was not found in instance's IP addresses", reservedIP.Address) + } +} + +func TestInstance_AddReservedIPToInstanceVariants(t *testing.T) { + client, teardown := createTestClient(t, "fixtures/TestInstance_AddReservedIPToInstanceVariants") + defer teardown() + + // Create a test Linode instance + instance, err := client.CreateInstance(context.Background(), linodego.InstanceCreateOptions{ + Region: "us-east", + Type: "g6-nanode-1", + Label: "test-instance-for-ip-reservation", + RootPass: randPassword(), + }) + if err != nil { + t.Fatalf("Error creating test instance: %v", err) + } + defer func() { + if err := client.DeleteInstance(context.Background(), instance.ID); err != nil { + t.Errorf("Error deleting test instance: %v", err) + } + }() + + // Reserve an IP address + reservedIP, err := client.ReserveIPAddress(context.Background(), linodego.ReserveIPOptions{ + Region: "us-east", + }) + if err != nil { + t.Fatalf("Error reserving IP address: %v", err) + } + defer func() { + if err := client.DeleteReservedIPAddress(context.Background(), reservedIP.Address); err != nil { + t.Errorf("Error deleting reserved IP: %v", err) + } + }() + + // Test: Add reserved IP to instance with valid parameters + opts := linodego.InstanceReserveIPOptions{ + Type: "ipv4", + Public: true, + Address: reservedIP.Address, + } + _, err = client.AssignInstanceReservedIP(context.Background(), instance.ID, opts) + if err != nil { + t.Fatalf("Error adding reserved IP to instance: %v", err) + } + + // Test: Omit public field + omitPublicOpts := linodego.InstanceReserveIPOptions{ + Type: "ipv4", + Address: reservedIP.Address, + // Public field is omitted here + } + _, err = client.AssignInstanceReservedIP(context.Background(), instance.ID, omitPublicOpts) + if err == nil { + t.Fatalf("Expected error when adding reserved IP with omitted public field, but got none") + } + + // Assume we have a Linode that has been created without a reserved IP address and IPMAX set to 1 + linodeID := 63510870 + + // Reserve IP address + resIP, err := client.ReserveIPAddress(context.Background(), linodego.ReserveIPOptions{ + Region: "us-east", + }) + if err != nil { + t.Fatalf("Failed to reserve IP: %v", err) + } + + // Add IP address to the Linode + _, err = client.AssignInstanceReservedIP(context.Background(), linodeID, linodego.InstanceReserveIPOptions{ + Type: "ipv4", + Public: true, + Address: resIP.Address, + }) + if err == nil { + t.Errorf("Expected error when adding reserved IP to a Linode at its IPMAX limit, but got none") + } + + // Delete the reserved IP Address + + if err := client.DeleteReservedIPAddress(context.Background(), resIP.Address); err != nil { + t.Errorf("Failed to delete first reserved IP: %v", err) + } + + // Test: Non-owned Linode ID + nonOwnedInstanceID := 888888 // Replace with an actual non-owned Linode ID + _, err = client.AssignInstanceReservedIP(context.Background(), nonOwnedInstanceID, opts) + if err == nil { + t.Errorf("Expected error when adding reserved IP to non-owned Linode, but got none") + } + + // Test: Already assigned reserved IP + _, err = client.AssignInstanceReservedIP(context.Background(), instance.ID, opts) + if err == nil { + t.Errorf("Expected error when adding already assigned reserved IP, but got none") + } + + // Test: Non-owned reserved IP + _, err = client.AssignInstanceReservedIP(context.Background(), instance.ID, linodego.InstanceReserveIPOptions{ + Type: "ipv4", + Public: true, + Address: "198.51.100.1", // Assume this is a non-owned reserved IP + }) + if err == nil { + t.Errorf("Expected error when adding non-owned reserved IP, but got none") + } + + // Test: Reserved IP in different datacenter + // Reserve an IP address + diffDataCentreIP, err := client.ReserveIPAddress(context.Background(), linodego.ReserveIPOptions{ + Region: "ca-central", + }) + if err != nil { + t.Fatalf("Error reserving IP address: %v", err) + } + defer func() { + if err := client.DeleteReservedIPAddress(context.Background(), diffDataCentreIP.Address); err != nil { + t.Errorf("Error deleting reserved IP: %v", err) + } + }() + _, err = client.AssignInstanceReservedIP(context.Background(), instance.ID, linodego.InstanceReserveIPOptions{ + Type: "ipv4", + Public: true, + Address: diffDataCentreIP.Address, // Assume this IP is in a different datacenter + }) + if err == nil { + t.Errorf("Expected error when adding reserved IP in different datacenter, but got none") + } + + // Test: IPv6 type + _, err = client.AssignInstanceReservedIP(context.Background(), instance.ID, linodego.InstanceReserveIPOptions{ + Type: "ipv6", + Public: true, + Address: reservedIP.Address, + }) + if err == nil { + t.Errorf("Expected error when adding reserved IP with type ipv6, but got none") + } + + // Test: Public field set to false + opts.Public = false + _, err = client.AssignInstanceReservedIP(context.Background(), instance.ID, opts) + if err == nil { + t.Errorf("Expected error when adding reserved IP with public field set to false, but got none") + } + + // Test: Integer as address + _, err = client.AssignInstanceReservedIP(context.Background(), instance.ID, linodego.InstanceReserveIPOptions{ + Type: "ipv4", + Public: true, + Address: "12345", // Invalid IP format + }) + if err == nil { + t.Errorf("Expected error when adding reserved IP with integer as address, but got none") + } + + // Test: Empty address + _, err = client.AssignInstanceReservedIP(context.Background(), instance.ID, linodego.InstanceReserveIPOptions{ + Type: "ipv4", + Public: true, + Address: "", + }) + if err == nil { + t.Errorf("Expected error when adding reserved IP with empty address, but got none") + } + + // Test: Null address + _, err = client.AssignInstanceReservedIP(context.Background(), instance.ID, linodego.InstanceReserveIPOptions{ + Type: "ipv4", + Public: true, + }) + if err == nil { + t.Errorf("Expected error when adding reserved IP with null address, but got none") + } + + // Test: Omit address field + _, err = client.AssignInstanceReservedIP(context.Background(), instance.ID, linodego.InstanceReserveIPOptions{ + Type: "ipv4", + Public: true, + }) + if err == nil { + t.Errorf("Expected error when omitting address field, but got none") + } +} From 2b51d5c433e6cfed7e94e07a9dba00021474f55b Mon Sep 17 00:00:00 2001 From: Youjung Kim <126618609+ykim-1@users.noreply.github.com> Date: Fri, 27 Sep 2024 12:22:33 -0700 Subject: [PATCH 9/9] test: Add slack notifications to CI workflow (#585) * add slack notifications to ci.yml * fix syntax on build outcome * gha test 1 * gha test 2 --- .github/workflows/ci.yml | 68 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 41afc67c..83380bb3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -76,4 +76,70 @@ jobs: python3 e2e_scripts/tod_scripts/xml_to_obj_storage/scripts/xml_to_obj.py "$REPORT_FILENAME" env: LINODE_CLI_OBJ_ACCESS_KEY: ${{ secrets.LINODE_CLI_OBJ_ACCESS_KEY }} - LINODE_CLI_OBJ_SECRET_KEY: ${{ secrets.LINODE_CLI_OBJ_SECRET_KEY }} \ No newline at end of file + LINODE_CLI_OBJ_SECRET_KEY: ${{ secrets.LINODE_CLI_OBJ_SECRET_KEY }} + + notify-slack: + runs-on: ubuntu-latest + needs: [test] + if: always() && github.repository == 'linode/linodego' # Run even if integration tests fail and only on main repository + + steps: + - name: Notify Slack + uses: slackapi/slack-github-action@v1.27.0 + with: + channel-id: ${{ secrets.SLACK_CHANNEL_ID }} + payload: | + { + "blocks": [ + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": ":rocket: *${{ github.workflow }} Completed in: ${{ github.repository }}* :white_check_mark:" + } + }, + { + "type": "divider" + }, + { + "type": "section", + "fields": [ + { + "type": "mrkdwn", + "text": "*Build Result:*\n${{ needs.test.result == 'success' && ':large_green_circle: Build Passed' || ':red_circle: Build Failed' }}" + }, + { + "type": "mrkdwn", + "text": "*Branch:*\n`${{ github.ref_name }}`" + } + ] + }, + { + "type": "section", + "fields": [ + { + "type": "mrkdwn", + "text": "*Commit Hash:*\n<${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }}|${{ github.sha }}>" + }, + { + "type": "mrkdwn", + "text": "*Run URL:*\n<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|View Run Details>" + } + ] + }, + { + "type": "divider" + }, + { + "type": "context", + "elements": [ + { + "type": "mrkdwn", + "text": "Triggered by: :bust_in_silhouette: `${{ github.actor }}`" + } + ] + } + ] + } + env: + SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }} \ No newline at end of file