From c5d68c4aea8756ca545ab08ad6c97660971072d6 Mon Sep 17 00:00:00 2001 From: Bill Gale Date: Thu, 9 Nov 2023 16:31:18 +0000 Subject: [PATCH] chore: v6provider setup + ip resource and data source (#110) * chore: v6_provider setup with resource_ip and datasource_ip --- docs/index.md | 9 +- docs/resources/ip.md | 4 +- go.mod | 7 + go.sum | 18 +- .../data_source_file_storage_volume_test.go | 12 +- internal/provider/data_source_ip.go | 69 - .../data_source_virtual_machine_test.go | 16 +- internal/provider/provider.go | 97 +- .../resource_file_storage_volume_test.go | 16 +- internal/provider/resource_ip_test.go | 137 +- .../provider/resource_virtual_machine_test.go | 106 +- ...curityGroup_invalid_rules.cassette.rand_id | 2 +- internal/v6provider/data_source_ip.go | 162 +++ .../data_source_ip_test.go | 30 +- internal/v6provider/meta.go | 149 +++ internal/v6provider/meta_test.go | 110 ++ internal/v6provider/resource_ip.go | 347 +++++ internal/v6provider/resource_ip_test.go | 555 ++++++++ internal/v6provider/sweeper_test.go | 30 + .../DataSourceIP_by_address.cassette.yaml | 504 +++++++ .../testdata/DataSourceIP_by_id.cassette.yaml | 504 +++++++ .../v6provider/testdata/IP_ipv4.cassette.yaml | 377 ++++++ .../v6provider/testdata/IP_ipv6.cassette.yaml | 377 ++++++ .../testdata/IP_minimal.cassette.yaml | 377 ++++++ .../testdata/IP_update.cassette.yaml | 1174 +++++++++++++++++ .../testdata/IP_vip.cassette.rand_id | 1 + .../v6provider/testdata/IP_vip.cassette.yaml | 337 +++++ .../IP_vip_without_label.cassette.yaml | 88 ++ .../testdata/IP_with_network_id.cassette.yaml | 337 +++++ internal/v6provider/v6provider.go | 272 ++++ internal/v6provider/v6provider_test.go | 275 ++++ main.go | 6 + 32 files changed, 6229 insertions(+), 276 deletions(-) delete mode 100644 internal/provider/data_source_ip.go create mode 100644 internal/v6provider/data_source_ip.go rename internal/{provider => v6provider}/data_source_ip_test.go (84%) create mode 100644 internal/v6provider/meta.go create mode 100644 internal/v6provider/meta_test.go create mode 100644 internal/v6provider/resource_ip.go create mode 100644 internal/v6provider/resource_ip_test.go create mode 100644 internal/v6provider/sweeper_test.go create mode 100644 internal/v6provider/testdata/DataSourceIP_by_address.cassette.yaml create mode 100644 internal/v6provider/testdata/DataSourceIP_by_id.cassette.yaml create mode 100644 internal/v6provider/testdata/IP_ipv4.cassette.yaml create mode 100644 internal/v6provider/testdata/IP_ipv6.cassette.yaml create mode 100644 internal/v6provider/testdata/IP_minimal.cassette.yaml create mode 100644 internal/v6provider/testdata/IP_update.cassette.yaml create mode 100644 internal/v6provider/testdata/IP_vip.cassette.rand_id create mode 100644 internal/v6provider/testdata/IP_vip.cassette.yaml create mode 100644 internal/v6provider/testdata/IP_vip_without_label.cassette.yaml create mode 100644 internal/v6provider/testdata/IP_with_network_id.cassette.yaml create mode 100644 internal/v6provider/v6provider.go create mode 100644 internal/v6provider/v6provider_test.go diff --git a/docs/index.md b/docs/index.md index af77ecfb..86e21e79 100644 --- a/docs/index.md +++ b/docs/index.md @@ -31,15 +31,12 @@ provider "katapult" { ## Schema -### Required - -- `api_key` (String, Sensitive) API Key for Katapult Core API. Can be specified with the `KATAPULT_API_KEY` environment variable. -- `data_center` (String) Data center permalink. Can be specified with the `KATAPULT_DATA_CENTER` environment variable. -- `organization` (String) Organization sub-domain. Can be specified with the `KATAPULT_ORGANIZATION` environment variable. - ### Optional +- `api_key` (String, Sensitive) **REQUIRED** via config or environment variable. API Key for Katapult Core API. Can be specified with the `KATAPULT_API_KEY` environment variable. +- `data_center` (String) **REQUIRED** via config or environment variable. Data center permalink. Can be specified with the `KATAPULT_DATA_CENTER` environment variable. - `log_level` (String) Log level used by Katapult Terraform provider. Can be specified with the `KATAPULT_LOG_LEVEL` environment variable. Defaults to `info`. +- `organization` (String) **REQUIRED** via config or environment variable. Organization sub-domain. Can be specified with the `KATAPULT_ORGANIZATION` environment variable. - `skip_trash_object_purge` (Boolean) Skip purging deleted resources from Katapult's trash when they are destroyed by Terraform. Only relevant to some resources which are moved to the trash when they are deleted. Can be specified with the `KATAPULT_SKIP_TRASH_OBJECT_PURGE` environment variable. Defaults to `false`. diff --git a/docs/resources/ip.md b/docs/resources/ip.md index 5b36eb76..8f1610af 100644 --- a/docs/resources/ip.md +++ b/docs/resources/ip.md @@ -35,8 +35,8 @@ resource "katapult_ip" "primary-db" { - `label` (String) VIP label. Required when **vip** is `true`. - `network_id` (String) -- `version` (Number) IPv4 or IPv6. Defaults to `4`. -- `vip` (Boolean) Defaults to `false`. +- `version` (Number) IPv4 or IPv6. Default is `4`. +- `vip` (Boolean) Default is `false`. ### Read-Only diff --git a/go.mod b/go.mod index 5afe987b..d45c88cb 100644 --- a/go.mod +++ b/go.mod @@ -7,9 +7,12 @@ require ( github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 github.com/hashicorp/go-hclog v1.5.0 github.com/hashicorp/go-retryablehttp v0.7.4 + github.com/hashicorp/terraform-plugin-framework v1.4.2 + github.com/hashicorp/terraform-plugin-framework-validators v0.12.0 github.com/hashicorp/terraform-plugin-go v0.19.0 github.com/hashicorp/terraform-plugin-mux v0.12.0 github.com/hashicorp/terraform-plugin-sdk/v2 v2.29.0 + github.com/hashicorp/terraform-plugin-testing v1.5.1 github.com/jimeh/rands v0.3.0 github.com/jimeh/undent v1.1.1 github.com/krystal/go-katapult v0.2.1 @@ -43,6 +46,8 @@ require ( github.com/hashicorp/terraform-registry-address v0.2.2 // indirect github.com/hashicorp/terraform-svchost v0.1.1 // indirect github.com/hashicorp/yamux v0.1.1 // indirect + github.com/kr/pretty v0.2.1 // indirect + github.com/kr/text v0.2.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect @@ -58,6 +63,7 @@ require ( github.com/zclconf/go-cty v1.14.1 // indirect go.mongodb.org/mongo-driver v1.12.1 // indirect golang.org/x/crypto v0.14.0 // indirect + golang.org/x/exp v0.0.0-20230809150735-7b3493d9a819 // indirect golang.org/x/mod v0.13.0 // indirect golang.org/x/net v0.17.0 // indirect golang.org/x/sys v0.13.0 // indirect @@ -66,6 +72,7 @@ require ( google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b // indirect google.golang.org/grpc v1.59.0 // indirect google.golang.org/protobuf v1.31.0 // indirect + gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 1600f34d..4644ad8a 100644 --- a/go.sum +++ b/go.sum @@ -15,6 +15,7 @@ github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7N github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= github.com/cloudflare/circl v1.3.6 h1:/xbKIqSHbZXHwkhbrhrt2YOHIwYJlXH94E3tI/gDlUg= github.com/cloudflare/circl v1.3.6/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -77,6 +78,10 @@ github.com/hashicorp/terraform-exec v0.19.0 h1:FpqZ6n50Tk95mItTSS9BjeOVUb4eg81Sp github.com/hashicorp/terraform-exec v0.19.0/go.mod h1:tbxUpe3JKruE9Cuf65mycSIT8KiNPZ0FkuTE3H4urQg= github.com/hashicorp/terraform-json v0.17.1 h1:eMfvh/uWggKmY7Pmb3T85u86E2EQg6EQHgyRwf3RkyA= github.com/hashicorp/terraform-json v0.17.1/go.mod h1:Huy6zt6euxaY9knPAFKjUITn8QxUFIe9VuSzb4zn/0o= +github.com/hashicorp/terraform-plugin-framework v1.4.2 h1:P7a7VP1GZbjc4rv921Xy5OckzhoiO3ig6SGxwelD2sI= +github.com/hashicorp/terraform-plugin-framework v1.4.2/go.mod h1:GWl3InPFZi2wVQmdVnINPKys09s9mLmTZr95/ngLnbY= +github.com/hashicorp/terraform-plugin-framework-validators v0.12.0 h1:HOjBuMbOEzl7snOdOoUfE2Jgeto6JOjLVQ39Ls2nksc= +github.com/hashicorp/terraform-plugin-framework-validators v0.12.0/go.mod h1:jfHGE/gzjxYz6XoUwi/aYiiKrJDeutQNUtGQXkaHklg= github.com/hashicorp/terraform-plugin-go v0.19.0 h1:BuZx/6Cp+lkmiG0cOBk6Zps0Cb2tmqQpDM3iAtnhDQU= github.com/hashicorp/terraform-plugin-go v0.19.0/go.mod h1:EhRSkEPNoylLQntYsk5KrDHTZJh9HQoumZXbOGOXmec= github.com/hashicorp/terraform-plugin-log v0.9.0 h1:i7hOA+vdAItN1/7UrfBqBwvYPQ9TFvymaRGZED3FCV0= @@ -85,6 +90,8 @@ github.com/hashicorp/terraform-plugin-mux v0.12.0 h1:TJlmeslQ11WlQtIFAfth0vXx+gS github.com/hashicorp/terraform-plugin-mux v0.12.0/go.mod h1:8MR0AgmV+Q03DIjyrAKxXyYlq2EUnYBQP8gxAAA0zeM= github.com/hashicorp/terraform-plugin-sdk/v2 v2.29.0 h1:wcOKYwPI9IorAJEBLzgclh3xVolO7ZorYd6U1vnok14= github.com/hashicorp/terraform-plugin-sdk/v2 v2.29.0/go.mod h1:qH/34G25Ugdj5FcM95cSoXzUgIbgfhVLXCcEcYaMwq8= +github.com/hashicorp/terraform-plugin-testing v1.5.1 h1:T4aQh9JAhmWo4+t1A7x+rnxAJHCDIYW9kXyo4sVO92c= +github.com/hashicorp/terraform-plugin-testing v1.5.1/go.mod h1:dg8clO6K59rZ8w9EshBmDp1CxTIPu3yA4iaDpX1h5u0= github.com/hashicorp/terraform-registry-address v0.2.2 h1:lPQBg403El8PPicg/qONZJDC6YlgCVbWDtNmmZKtBno= github.com/hashicorp/terraform-registry-address v0.2.2/go.mod h1:LtwNbCihUoUZ3RYriyS2wF/lGPB6gF9ICLRtuDk7hSo= github.com/hashicorp/terraform-svchost v0.1.1 h1:EZZimZ1GxdqFRinZ1tpJwVxxt49xc/S52uzrw4x0jKQ= @@ -100,11 +107,13 @@ github.com/jimeh/undent v1.1.1 h1:ZAzvd2DDx7gxQvOMGkQjfeRx9gRPIXe2cq+8ZNiGKaM= github.com/jimeh/undent v1.1.1/go.mod h1:oxYCIzdbyQNy8GXnCnjRJ2NS6Uq4p4yWoeawiGFqoHI= github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/krystal/go-katapult v0.2.1 h1:UltHtVShIrqX/6jx7PHLKEJBH7KAsme2veHku7O5TBg= github.com/krystal/go-katapult v0.2.1/go.mod h1:yTy0Lx0qpwK8RwhOHqmsGJhMcDlcg00AswfJWh1yw3w= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= @@ -173,6 +182,8 @@ golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2Uz golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/exp v0.0.0-20230809150735-7b3493d9a819 h1:EDuYyU/MkFXllv9QF9819VlI9a4tzGuCbhG0ExK9o1U= +golang.org/x/exp v0.0.0-20230809150735-7b3493d9a819/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= @@ -245,8 +256,9 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= diff --git a/internal/provider/data_source_file_storage_volume_test.go b/internal/provider/data_source_file_storage_volume_test.go index 0edfbd55..f126dffa 100644 --- a/internal/provider/data_source_file_storage_volume_test.go +++ b/internal/provider/data_source_file_storage_volume_test.go @@ -70,7 +70,7 @@ func TestAccKatapultDataSourceFileStorageVolume_associations(t *testing.T) { Steps: []resource.TestStep{ { Config: undent.Stringf(` - resource "katapult_ip" "web" {} + resource "katapult_legacy_ip" "web" {} resource "katapult_virtual_machine" "web" { hostname = "%s-web" package = "rock-3" @@ -78,7 +78,7 @@ func TestAccKatapultDataSourceFileStorageVolume_associations(t *testing.T) { disk_template_options = { install_agent = true } - ip_address_ids = [katapult_ip.web.id] + ip_address_ids = [katapult_legacy_ip.web.id] } resource "katapult_file_storage_volume" "my_vol" { @@ -117,7 +117,7 @@ func TestAccKatapultDataSourceFileStorageVolume_associations(t *testing.T) { }, { Config: undent.Stringf(` - resource "katapult_ip" "web" {} + resource "katapult_legacy_ip" "web" {} resource "katapult_virtual_machine" "web" { hostname = "%s-web" package = "rock-3" @@ -125,10 +125,10 @@ func TestAccKatapultDataSourceFileStorageVolume_associations(t *testing.T) { disk_template_options = { install_agent = true } - ip_address_ids = [katapult_ip.web.id] + ip_address_ids = [katapult_legacy_ip.web.id] } - resource "katapult_ip" "db" {} + resource "katapult_legacy_ip" "db" {} resource "katapult_virtual_machine" "db" { hostname = "%s-db" package = "rock-3" @@ -136,7 +136,7 @@ func TestAccKatapultDataSourceFileStorageVolume_associations(t *testing.T) { disk_template_options = { install_agent = true } - ip_address_ids = [katapult_ip.db.id] + ip_address_ids = [katapult_legacy_ip.db.id] } resource "katapult_file_storage_volume" "my_vol" { diff --git a/internal/provider/data_source_ip.go b/internal/provider/data_source_ip.go deleted file mode 100644 index 9670a49c..00000000 --- a/internal/provider/data_source_ip.go +++ /dev/null @@ -1,69 +0,0 @@ -package provider - -import ( - "context" - - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/krystal/go-katapult/core" -) - -func dataSourceIP() *schema.Resource { - ds := dataSourceSchemaFromResourceSchema(resourceIP().Schema) - - ds["id"] = &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Description: "The ID of this resource.", - AtLeastOneOf: []string{"id", "address"}, - } - - ds["address"].Optional = true - ds["label"].Description = "VIP label." - - return &schema.Resource{ - ReadContext: dataSourceIPRead, - Schema: ds, - } -} - -func dataSourceIPRead( - ctx context.Context, - d *schema.ResourceData, - meta interface{}, -) diag.Diagnostics { - m := meta.(*Meta) - var diags diag.Diagnostics - - id := d.Get("id").(string) - address := d.Get("address").(string) - - var ip *core.IPAddress - var err error - - switch { - case id != "": - ip, _, err = m.Core.IPAddresses.GetByID(ctx, id) - default: - ip, _, err = m.Core.IPAddresses.GetByAddress(ctx, address) - } - if err != nil { - return diag.FromErr(err) - } - - if ip.Network != nil { - _ = d.Set("network_id", ip.Network.ID) - } - _ = d.Set("address", ip.Address) - _ = d.Set("address_with_mask", ip.AddressWithMask) - _ = d.Set("reverse_dns", ip.ReverseDNS) - _ = d.Set("version", flattenIPVersion(ip.Address)) - _ = d.Set("vip", ip.VIP) - _ = d.Set("label", ip.Label) - _ = d.Set("allocation_type", ip.AllocationType) - _ = d.Set("allocation_id", ip.AllocationID) - - d.SetId(ip.ID) - - return diags -} diff --git a/internal/provider/data_source_virtual_machine_test.go b/internal/provider/data_source_virtual_machine_test.go index 872f8407..2e3fd677 100644 --- a/internal/provider/data_source_virtual_machine_test.go +++ b/internal/provider/data_source_virtual_machine_test.go @@ -23,7 +23,7 @@ func TestAccKatapultDataSourceVirtualMachine_by_id(t *testing.T) { Steps: []resource.TestStep{ { Config: undent.Stringf(` - resource "katapult_ip" "web" {} + resource "katapult_legacy_ip" "web" {} resource "katapult_virtual_machine_group" "web" { name = "%s" @@ -38,7 +38,7 @@ func TestAccKatapultDataSourceVirtualMachine_by_id(t *testing.T) { disk_template_options = { install_agent = true } - ip_address_ids = [katapult_ip.web.id] + ip_address_ids = [katapult_legacy_ip.web.id] group_id = katapult_virtual_machine_group.web.id tags = ["web", "public"] network_speed_profile = "1gbps" @@ -78,11 +78,11 @@ func TestAccKatapultDataSourceVirtualMachine_by_id(t *testing.T) { ), resource.TestCheckTypeSetElemAttrPair( "data.katapult_virtual_machine.src", "ip_address_ids.*", - "katapult_ip.web", "id", + "katapult_legacy_ip.web", "id", ), resource.TestCheckTypeSetElemAttrPair( "data.katapult_virtual_machine.src", "ip_addresses.*", - "katapult_ip.web", "address", + "katapult_legacy_ip.web", "address", ), resource.TestCheckTypeSetElemAttrPair( "data.katapult_virtual_machine.src", "group_id", @@ -123,7 +123,7 @@ func TestAccKatapultDataSourceVirtualMachine_by_fqdn(t *testing.T) { Steps: []resource.TestStep{ { Config: undent.Stringf(` - resource "katapult_ip" "web" {} + resource "katapult_legacy_ip" "web" {} resource "katapult_virtual_machine_group" "web" { name = "%s" @@ -138,7 +138,7 @@ func TestAccKatapultDataSourceVirtualMachine_by_fqdn(t *testing.T) { disk_template_options = { install_agent = true } - ip_address_ids = [katapult_ip.web.id] + ip_address_ids = [katapult_legacy_ip.web.id] group_id = katapult_virtual_machine_group.web.id tags = ["web", "public"] network_speed_profile = "1gbps" @@ -178,11 +178,11 @@ func TestAccKatapultDataSourceVirtualMachine_by_fqdn(t *testing.T) { ), resource.TestCheckTypeSetElemAttrPair( "data.katapult_virtual_machine.src", "ip_address_ids.*", - "katapult_ip.web", "id", + "katapult_legacy_ip.web", "id", ), resource.TestCheckTypeSetElemAttrPair( "data.katapult_virtual_machine.src", "ip_addresses.*", - "katapult_ip.web", "address", + "katapult_legacy_ip.web", "address", ), resource.TestCheckTypeSetElemAttrPair( "data.katapult_virtual_machine.src", "group_id", diff --git a/internal/provider/provider.go b/internal/provider/provider.go index fb2e4ede..e13ff964 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -55,40 +55,38 @@ func New(c *Config) func() *schema.Provider { //nolint:funlen p := &schema.Provider{ Schema: map[string]*schema.Schema{ "api_key": { - Type: schema.TypeString, - Required: true, - Sensitive: true, - DefaultFunc: schema.EnvDefaultFunc("KATAPULT_API_KEY", nil), - Description: "API Key for Katapult Core API. Can be " + + Type: schema.TypeString, + Optional: true, + Sensitive: true, + Description: "**REQUIRED** via config or " + + "environment variable. " + + "API Key for Katapult Core API. Can be " + "specified with the `KATAPULT_API_KEY` environment " + "variable.", }, "organization": { Type: schema.TypeString, - Required: true, - DefaultFunc: schema.EnvDefaultFunc( - "KATAPULT_ORGANIZATION", nil, - ), - Description: "Organization sub-domain. Can be " + + Optional: true, + + Description: "**REQUIRED** via config or " + + "environment variable. " + + "Organization sub-domain. Can be " + "specified with the `KATAPULT_ORGANIZATION` " + "environment variable.", }, "data_center": { Type: schema.TypeString, - Required: true, - DefaultFunc: schema.EnvDefaultFunc( - "KATAPULT_DATA_CENTER", nil, - ), - Description: "Data center permalink. Can be " + + Optional: true, + + Description: "**REQUIRED** via config or " + + "environment variable. " + + "Data center permalink. Can be " + "specified with the `KATAPULT_DATA_CENTER` " + "environment variable.", }, "skip_trash_object_purge": { Type: schema.TypeBool, Optional: true, - DefaultFunc: schema.EnvDefaultFunc( - "KATAPULT_SKIP_TRASH_OBJECT_PURGE", false, - ), //nolint:lll Description: strings.TrimSpace(` @@ -122,7 +120,6 @@ Skip purging deleted resources from Katapult's trash when they are destroyed by }, }, ResourcesMap: map[string]*schema.Resource{ - "katapult_ip": resourceIP(), "katapult_file_storage_volume": resourceFileStorageVolume(), "katapult_security_group": resourceSecurityGroup(), "katapult_security_group_rule": resourceSecurityGroupRule(), @@ -136,7 +133,6 @@ Skip purging deleted resources from Katapult's trash when they are destroyed by "katapult_disk_templates": dataSourceDiskTemplates(), "katapult_file_storage_volume": dataSourceFileStorageVolume(), "katapult_file_storage_volumes": dataSourceFileStorageVolumes(), - "katapult_ip": dataSourceIP(), "katapult_network_speed_profile": dataSourceNetworkSpeedProfile(), "katapult_network_speed_profiles": dataSourceNetworkSpeedProfiles(), "katapult_security_group": dataSourceSecurityGroup(), @@ -151,12 +147,37 @@ Skip purging deleted resources from Katapult's trash when they are destroyed by }, } + if os.Getenv("TF_ACC") == "1" { + p.ResourcesMap["katapult_legacy_ip"] = resourceIP() + } + p.ConfigureContextFunc = configure(c, p) return p } } +func stringOrEnv(in string, env string) string { + if in != "" { + return in + } + + return os.Getenv(env) +} + +func boolOrEnv(in bool, env string) bool { + if in { + return true + } + + switch strings.ToLower(os.Getenv(env)) { + case "true", "1", "yes", "on", "y", "t": + return true + } + + return false +} + func configure( conf *Config, p *schema.Provider, @@ -165,17 +186,37 @@ func configure( _ context.Context, d *schema.ResourceData, ) (interface{}, diag.Diagnostics) { + logLevel := stringOrEnv( + d.Get("log_level").(string), + "KATAPULT_LOG_LEVEL", + ) + if logLevel == "" { + logLevel = "info" + } + m := &Meta{ Logger: hclog.New(&hclog.LoggerOptions{ Name: "katapult", - Level: hclog.LevelFromString(d.Get("log_level").(string)), + Level: hclog.LevelFromString(logLevel), TimeFormat: "2006/01/02 15:04:05", }), - confAPIKey: d.Get("api_key").(string), - confDataCenter: d.Get("data_center").(string), - confOrganization: d.Get("organization").(string), - SkipTrashObjectPurge: d.Get("skip_trash_object_purge").(bool), - GeneratedNamePrefix: conf.GeneratedNamePrefix, + confAPIKey: stringOrEnv( + d.Get("api_key").(string), + "KATAPULT_API_KEY", + ), + confDataCenter: stringOrEnv( + d.Get("data_center").(string), + "KATAPULT_DATA_CENTER", + ), + confOrganization: stringOrEnv( + d.Get("organization").(string), + "KATAPULT_ORGANIZATION", + ), + SkipTrashObjectPurge: boolOrEnv( + d.Get("skip_trash_object_purge").(bool), + "KATAPULT_SKIP_TRASH_OBJECT_PURGE", + ), + GeneratedNamePrefix: conf.GeneratedNamePrefix, } if m.GeneratedNamePrefix == "" { @@ -220,10 +261,10 @@ func configure( m.Core = core.New(m.Client) m.OrganizationRef = core.OrganizationRef{ - SubDomain: d.Get("organization").(string), + SubDomain: m.confOrganization, } m.DataCenterRef = core.DataCenterRef{ - Permalink: d.Get("data_center").(string), + Permalink: m.confDataCenter, } return m, nil diff --git a/internal/provider/resource_file_storage_volume_test.go b/internal/provider/resource_file_storage_volume_test.go index f77d37bf..1dfbb7ab 100644 --- a/internal/provider/resource_file_storage_volume_test.go +++ b/internal/provider/resource_file_storage_volume_test.go @@ -216,7 +216,7 @@ func TestAccKatapultFileStorageVolume_associations(t *testing.T) { }, { Config: undent.Stringf(` - resource "katapult_ip" "web" {} + resource "katapult_legacy_ip" "web" {} resource "katapult_virtual_machine" "web" { hostname = "%s-web" @@ -225,7 +225,7 @@ func TestAccKatapultFileStorageVolume_associations(t *testing.T) { disk_template_options = { install_agent = true } - ip_address_ids = [katapult_ip.web.id] + ip_address_ids = [katapult_legacy_ip.web.id] } resource "katapult_file_storage_volume" "data" { @@ -254,7 +254,7 @@ func TestAccKatapultFileStorageVolume_associations(t *testing.T) { }, { Config: undent.Stringf(` - resource "katapult_ip" "web" {} + resource "katapult_legacy_ip" "web" {} resource "katapult_virtual_machine" "web" { hostname = "%s-web" package = "rock-3" @@ -262,10 +262,10 @@ func TestAccKatapultFileStorageVolume_associations(t *testing.T) { disk_template_options = { install_agent = true } - ip_address_ids = [katapult_ip.web.id] + ip_address_ids = [katapult_legacy_ip.web.id] } - resource "katapult_ip" "db" {} + resource "katapult_legacy_ip" "db" {} resource "katapult_virtual_machine" "db" { hostname = "%s-db" package = "rock-3" @@ -273,7 +273,7 @@ func TestAccKatapultFileStorageVolume_associations(t *testing.T) { disk_template_options = { install_agent = true } - ip_address_ids = [katapult_ip.db.id] + ip_address_ids = [katapult_legacy_ip.db.id] } resource "katapult_file_storage_volume" "data" { @@ -302,7 +302,7 @@ func TestAccKatapultFileStorageVolume_associations(t *testing.T) { }, { Config: undent.Stringf(` - resource "katapult_ip" "web" {} + resource "katapult_legacy_ip" "web" {} resource "katapult_virtual_machine" "web" { hostname = "%s-web" package = "rock-3" @@ -310,7 +310,7 @@ func TestAccKatapultFileStorageVolume_associations(t *testing.T) { disk_template_options = { install_agent = true } - ip_address_ids = [katapult_ip.web.id] + ip_address_ids = [katapult_legacy_ip.web.id] } resource "katapult_file_storage_volume" "data" { diff --git a/internal/provider/resource_ip_test.go b/internal/provider/resource_ip_test.go index e32fd3fd..bc2e9f97 100644 --- a/internal/provider/resource_ip_test.go +++ b/internal/provider/resource_ip_test.go @@ -15,8 +15,8 @@ import ( ) func init() { //nolint:gochecknoinits - resource.AddTestSweepers("katapult_ip", &resource.Sweeper{ - Name: "katapult_ip", + resource.AddTestSweepers("katapult_legacy_ip", &resource.Sweeper{ + Name: "katapult_legacy_ip", F: testSweepIPs, Dependencies: []string{"katapult_virtual_machine"}, }) @@ -78,31 +78,31 @@ func TestAccKatapultIP_minimal(t *testing.T) { CheckDestroy: testAccCheckKatapultIPDestroy(tt), Steps: []resource.TestStep{ { - Config: `resource "katapult_ip" "web" {}`, + Config: `resource "katapult_legacy_ip" "web" {}`, Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckKatapultIPAttrs(tt, "katapult_ip.web"), + testAccCheckKatapultIPAttrs(tt, "katapult_legacy_ip.web"), resource.TestCheckResourceAttr( - "katapult_ip.web", "network_id", network.ID, + "katapult_legacy_ip.web", "network_id", network.ID, ), resource.TestMatchResourceAttr( - "katapult_ip.web", + "katapult_legacy_ip.web", "address", regexp.MustCompile( `^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$`, ), ), resource.TestCheckResourceAttr( - "katapult_ip.web", "version", "4", + "katapult_legacy_ip.web", "version", "4", ), resource.TestCheckResourceAttr( - "katapult_ip.web", "vip", "false", + "katapult_legacy_ip.web", "vip", "false", ), resource.TestCheckResourceAttr( - "katapult_ip.web", "label", "", + "katapult_legacy_ip.web", "label", "", ), ), }, { - ResourceName: "katapult_ip.web", + ResourceName: "katapult_legacy_ip.web", ImportState: true, ImportStateVerify: true, }, @@ -125,34 +125,34 @@ func TestAccKatapultIP_ipv4(t *testing.T) { Steps: []resource.TestStep{ { Config: undent.String(` - resource "katapult_ip" "web" { + resource "katapult_legacy_ip" "web" { version = 4 }`, ), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckKatapultIPAttrs(tt, "katapult_ip.web"), + testAccCheckKatapultIPAttrs(tt, "katapult_legacy_ip.web"), resource.TestCheckResourceAttr( - "katapult_ip.web", "network_id", network.ID, + "katapult_legacy_ip.web", "network_id", network.ID, ), resource.TestMatchResourceAttr( - "katapult_ip.web", + "katapult_legacy_ip.web", "address", regexp.MustCompile( `^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$`, ), ), resource.TestCheckResourceAttr( - "katapult_ip.web", "version", "4", + "katapult_legacy_ip.web", "version", "4", ), resource.TestCheckResourceAttr( - "katapult_ip.web", "vip", "false", + "katapult_legacy_ip.web", "vip", "false", ), resource.TestCheckResourceAttr( - "katapult_ip.web", "label", "", + "katapult_legacy_ip.web", "label", "", ), ), }, { - ResourceName: "katapult_ip.web", + ResourceName: "katapult_legacy_ip.web", ImportState: true, ImportStateVerify: true, }, @@ -175,32 +175,32 @@ func TestAccKatapultIP_ipv6(t *testing.T) { Steps: []resource.TestStep{ { Config: undent.String(` - resource "katapult_ip" "web" { + resource "katapult_legacy_ip" "web" { version = 6 }`, ), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckKatapultIPAttrs(tt, "katapult_ip.web"), + testAccCheckKatapultIPAttrs(tt, "katapult_legacy_ip.web"), resource.TestCheckResourceAttr( - "katapult_ip.web", "network_id", network.ID, + "katapult_legacy_ip.web", "network_id", network.ID, ), resource.TestMatchResourceAttr( - "katapult_ip.web", + "katapult_legacy_ip.web", "address", regexp.MustCompile(`:.*:`), ), resource.TestCheckResourceAttr( - "katapult_ip.web", "version", "6", + "katapult_legacy_ip.web", "version", "6", ), resource.TestCheckResourceAttr( - "katapult_ip.web", "vip", "false", + "katapult_legacy_ip.web", "vip", "false", ), resource.TestCheckResourceAttr( - "katapult_ip.web", "label", "", + "katapult_legacy_ip.web", "label", "", ), ), }, { - ResourceName: "katapult_ip.web", + ResourceName: "katapult_legacy_ip.web", ImportState: true, ImportStateVerify: true, }, @@ -218,7 +218,7 @@ func TestAccKatapultIP_ipv5(t *testing.T) { Steps: []resource.TestStep{ { Config: undent.String(` - resource "katapult_ip" "web" { + resource "katapult_legacy_ip" "web" { version = 5 }`, ), @@ -244,24 +244,24 @@ func TestAccKatapultIP_vip(t *testing.T) { Steps: []resource.TestStep{ { Config: undent.Stringf(` - resource "katapult_ip" "vip" { + resource "katapult_legacy_ip" "vip" { vip = true label = "%s" }`, name, ), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckKatapultIPAttrs(tt, "katapult_ip.vip"), + testAccCheckKatapultIPAttrs(tt, "katapult_legacy_ip.vip"), resource.TestCheckResourceAttr( - "katapult_ip.vip", "vip", "true", + "katapult_legacy_ip.vip", "vip", "true", ), resource.TestCheckResourceAttr( - "katapult_ip.vip", "label", name, + "katapult_legacy_ip.vip", "label", name, ), ), }, { - ResourceName: "katapult_ip.vip", + ResourceName: "katapult_legacy_ip.vip", ImportState: true, ImportStateVerify: true, }, @@ -279,7 +279,7 @@ func TestAccKatapultIP_vip_empty_label(t *testing.T) { Steps: []resource.TestStep{ { Config: undent.String(` - resource "katapult_ip" "vip" { + resource "katapult_legacy_ip" "vip" { vip = true label = "" }`, @@ -304,7 +304,7 @@ func TestAccKatapultIP_vip_without_label(t *testing.T) { Steps: []resource.TestStep{ { Config: undent.String(` - resource "katapult_ip" "vip" { + resource "katapult_legacy_ip" "vip" { vip = true }`, ), @@ -326,7 +326,7 @@ func TestAccKatapultIP_label_without_vip(t *testing.T) { Steps: []resource.TestStep{ { Config: undent.String(` - resource "katapult_ip" "vip" { + resource "katapult_legacy_ip" "vip" { label = "hello" }`, ), @@ -353,20 +353,20 @@ func TestAccKatapultIP_with_network_id(t *testing.T) { Steps: []resource.TestStep{ { Config: undent.Stringf(` - resource "katapult_ip" "net" { + resource "katapult_legacy_ip" "net" { network_id = "%s" }`, network.ID, ), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckKatapultIPAttrs(tt, "katapult_ip.net"), + testAccCheckKatapultIPAttrs(tt, "katapult_legacy_ip.net"), resource.TestCheckResourceAttr( - "katapult_ip.net", "network_id", network.ID, + "katapult_legacy_ip.net", "network_id", network.ID, ), ), }, { - ResourceName: "katapult_ip.net", + ResourceName: "katapult_legacy_ip.net", ImportState: true, ImportStateVerify: true, }, @@ -383,64 +383,68 @@ func TestAccKatapultIP_update(t *testing.T) { CheckDestroy: testAccCheckKatapultIPDestroy(tt), Steps: []resource.TestStep{ { - Config: `resource "katapult_ip" "update" {}`, + Config: `resource "katapult_legacy_ip" "update" {}`, Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckKatapultIPAttrs(tt, "katapult_ip.update"), + testAccCheckKatapultIPAttrs(tt, + "katapult_legacy_ip.update"), resource.TestCheckResourceAttr( - "katapult_ip.update", "vip", "false", + "katapult_legacy_ip.update", "vip", "false", ), resource.TestCheckResourceAttr( - "katapult_ip.update", "label", "", + "katapult_legacy_ip.update", "label", "", ), ), }, { Config: undent.String(` - resource "katapult_ip" "update" { + resource "katapult_legacy_ip" "update" { vip = true label = "vip-yes" }`, ), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckKatapultIPAttrs(tt, "katapult_ip.update"), + testAccCheckKatapultIPAttrs(tt, + "katapult_legacy_ip.update"), resource.TestCheckResourceAttr( - "katapult_ip.update", "vip", "true", + "katapult_legacy_ip.update", "vip", "true", ), resource.TestCheckResourceAttr( - "katapult_ip.update", "label", "vip-yes", + "katapult_legacy_ip.update", "label", "vip-yes", ), ), }, { Config: undent.String(` - resource "katapult_ip" "update" { + resource "katapult_legacy_ip" "update" { vip = true label = "vip-oh-yes" }`, ), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckKatapultIPAttrs(tt, "katapult_ip.update"), + testAccCheckKatapultIPAttrs(tt, + "katapult_legacy_ip.update"), resource.TestCheckResourceAttr( - "katapult_ip.update", "vip", "true", + "katapult_legacy_ip.update", "vip", "true", ), resource.TestCheckResourceAttr( - "katapult_ip.update", "label", "vip-oh-yes", + "katapult_legacy_ip.update", "label", "vip-oh-yes", ), ), }, { Config: undent.String(` - resource "katapult_ip" "update" { + resource "katapult_legacy_ip" "update" { vip = false }`, ), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckKatapultIPAttrs(tt, "katapult_ip.update"), + testAccCheckKatapultIPAttrs(tt, + "katapult_legacy_ip.update"), resource.TestCheckResourceAttr( - "katapult_ip.update", "vip", "false", + "katapult_legacy_ip.update", "vip", "false", ), resource.TestCheckResourceAttr( - "katapult_ip.update", "label", "", + "katapult_legacy_ip.update", "label", "", ), ), }, @@ -452,27 +456,6 @@ func TestAccKatapultIP_update(t *testing.T) { // Helpers // -func testAccCheckKatapultIPExists( - tt *testTools, - res string, -) resource.TestCheckFunc { - m := tt.Meta - - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[res] - if !ok { - return fmt.Errorf("resource not found: %s", res) - } - - ip, _, err := m.Core.IPAddresses.GetByID(tt.Ctx, rs.Primary.ID) - if err != nil { - return err - } - - return resource.TestCheckResourceAttr(res, "id", ip.ID)(s) - } -} - func testAccCheckKatapultIPAttrs( tt *testTools, res string, @@ -529,7 +512,7 @@ func testAccCheckKatapultIPDestroy( return func(s *terraform.State) error { for _, rs := range s.RootModule().Resources { - if rs.Type != "katapult_ip" { + if rs.Type != "katapult_legacy_ip" { continue } diff --git a/internal/provider/resource_virtual_machine_test.go b/internal/provider/resource_virtual_machine_test.go index 5e926fad..a7653d1f 100644 --- a/internal/provider/resource_virtual_machine_test.go +++ b/internal/provider/resource_virtual_machine_test.go @@ -164,7 +164,7 @@ func TestAccKatapultVirtualMachine_minimal(t *testing.T) { Steps: []resource.TestStep{ { Config: undent.String(` - resource "katapult_ip" "web" {} + resource "katapult_legacy_ip" "web" {} resource "katapult_virtual_machine" "base" { package = "rock-3" @@ -172,7 +172,7 @@ func TestAccKatapultVirtualMachine_minimal(t *testing.T) { disk_template_options = { install_agent = true } - ip_address_ids = [katapult_ip.web.id] + ip_address_ids = [katapult_legacy_ip.web.id] }`, ), Check: resource.ComposeAggregateTestCheckFunc( @@ -208,11 +208,11 @@ func TestAccKatapultVirtualMachine_minimal(t *testing.T) { ), resource.TestCheckTypeSetElemAttrPair( "katapult_virtual_machine.base", "ip_address_ids.*", - "katapult_ip.web", "id", + "katapult_legacy_ip.web", "id", ), resource.TestCheckTypeSetElemAttrPair( "katapult_virtual_machine.base", "ip_addresses.*", - "katapult_ip.web", "address", + "katapult_legacy_ip.web", "address", ), resource.TestCheckResourceAttr( "katapult_virtual_machine.base", @@ -239,8 +239,8 @@ func TestAccKatapultVirtualMachine_basic(t *testing.T) { Steps: []resource.TestStep{ { Config: undent.Stringf(` - resource "katapult_ip" "web" {} - resource "katapult_ip" "internal" {} + resource "katapult_legacy_ip" "web" {} + resource "katapult_legacy_ip" "internal" {} resource "katapult_virtual_machine_group" "web" { name = "%s" @@ -257,8 +257,8 @@ func TestAccKatapultVirtualMachine_basic(t *testing.T) { } group_id = katapult_virtual_machine_group.web.id ip_address_ids = [ - katapult_ip.web.id, - katapult_ip.internal.id + katapult_legacy_ip.web.id, + katapult_legacy_ip.internal.id ] tags = ["web", "public"] network_speed_profile = "1gbps" @@ -312,11 +312,11 @@ func TestAccKatapultVirtualMachine_basic(t *testing.T) { ), resource.TestCheckTypeSetElemAttrPair( "katapult_virtual_machine.base", "ip_address_ids.*", - "katapult_ip.web", "id", + "katapult_legacy_ip.web", "id", ), resource.TestCheckTypeSetElemAttrPair( "katapult_virtual_machine.base", "ip_address_ids.*", - "katapult_ip.internal", "id", + "katapult_legacy_ip.internal", "id", ), resource.TestCheckResourceAttr( "katapult_virtual_machine.base", @@ -324,11 +324,11 @@ func TestAccKatapultVirtualMachine_basic(t *testing.T) { ), resource.TestCheckTypeSetElemAttrPair( "katapult_virtual_machine.base", "ip_addresses.*", - "katapult_ip.web", "address", + "katapult_legacy_ip.web", "address", ), resource.TestCheckTypeSetElemAttrPair( "katapult_virtual_machine.base", "ip_addresses.*", - "katapult_ip.internal", "address", + "katapult_legacy_ip.internal", "address", ), resource.TestCheckResourceAttr( "katapult_virtual_machine.base", @@ -368,8 +368,8 @@ func TestAccKatapultVirtualMachine_custom_disks(t *testing.T) { Steps: []resource.TestStep{ { Config: undent.Stringf(` - resource "katapult_ip" "web" {} - resource "katapult_ip" "internal" {} + resource "katapult_legacy_ip" "web" {} + resource "katapult_legacy_ip" "internal" {} resource "katapult_virtual_machine_group" "web" { name = "%s" @@ -386,8 +386,8 @@ func TestAccKatapultVirtualMachine_custom_disks(t *testing.T) { } group_id = katapult_virtual_machine_group.web.id ip_address_ids = [ - katapult_ip.web.id, - katapult_ip.internal.id + katapult_legacy_ip.web.id, + katapult_legacy_ip.internal.id ] tags = ["web", "public"] network_speed_profile = "1gbps" @@ -452,11 +452,11 @@ func TestAccKatapultVirtualMachine_custom_disks(t *testing.T) { ), resource.TestCheckTypeSetElemAttrPair( "katapult_virtual_machine.base", "ip_address_ids.*", - "katapult_ip.web", "id", + "katapult_legacy_ip.web", "id", ), resource.TestCheckTypeSetElemAttrPair( "katapult_virtual_machine.base", "ip_address_ids.*", - "katapult_ip.internal", "id", + "katapult_legacy_ip.internal", "id", ), resource.TestCheckResourceAttr( "katapult_virtual_machine.base", @@ -464,11 +464,11 @@ func TestAccKatapultVirtualMachine_custom_disks(t *testing.T) { ), resource.TestCheckTypeSetElemAttrPair( "katapult_virtual_machine.base", "ip_addresses.*", - "katapult_ip.web", "address", + "katapult_legacy_ip.web", "address", ), resource.TestCheckTypeSetElemAttrPair( "katapult_virtual_machine.base", "ip_addresses.*", - "katapult_ip.internal", "address", + "katapult_legacy_ip.internal", "address", ), resource.TestCheckResourceAttr( "katapult_virtual_machine.base", @@ -505,7 +505,7 @@ func TestAccKatapultVirtualMachine_update(t *testing.T) { Steps: []resource.TestStep{ { Config: undent.Stringf(` - resource "katapult_ip" "web" {} + resource "katapult_legacy_ip" "web" {} resource "katapult_virtual_machine" "base" { name = "%s" @@ -516,7 +516,7 @@ func TestAccKatapultVirtualMachine_update(t *testing.T) { disk_template_options = { install_agent = true } - ip_address_ids = [katapult_ip.web.id] + ip_address_ids = [katapult_legacy_ip.web.id] tags = ["web", "public"] network_speed_profile = "1gbps" }`, @@ -564,7 +564,7 @@ func TestAccKatapultVirtualMachine_update(t *testing.T) { }, { Config: undent.Stringf(` - resource "katapult_ip" "web" {} + resource "katapult_legacy_ip" "web" {} resource "katapult_virtual_machine" "base" { name = "%s" hostname = "%s" @@ -574,7 +574,7 @@ func TestAccKatapultVirtualMachine_update(t *testing.T) { disk_template_options = { install_agent = true } - ip_address_ids = [katapult_ip.web.id] + ip_address_ids = [katapult_legacy_ip.web.id] tags = ["web", "app", "lb"] network_speed_profile = "10gbps" }`, @@ -640,7 +640,7 @@ func TestAccKatapultVirtualMachine_update_ips(t *testing.T) { Steps: []resource.TestStep{ { Config: undent.String(` - resource "katapult_ip" "web" {} + resource "katapult_legacy_ip" "web" {} resource "katapult_virtual_machine" "base" { package = "rock-3" @@ -649,7 +649,7 @@ func TestAccKatapultVirtualMachine_update_ips(t *testing.T) { install_agent = true } ip_address_ids = [ - katapult_ip.web.id, + katapult_legacy_ip.web.id, ] }`, ), @@ -663,7 +663,7 @@ func TestAccKatapultVirtualMachine_update_ips(t *testing.T) { ), resource.TestCheckTypeSetElemAttrPair( "katapult_virtual_machine.base", "ip_address_ids.*", - "katapult_ip.web", "id", + "katapult_legacy_ip.web", "id", ), resource.TestCheckResourceAttr( "katapult_virtual_machine.base", @@ -671,14 +671,14 @@ func TestAccKatapultVirtualMachine_update_ips(t *testing.T) { ), resource.TestCheckTypeSetElemAttrPair( "katapult_virtual_machine.base", "ip_addresses.*", - "katapult_ip.web", "address", + "katapult_legacy_ip.web", "address", ), ), }, { Config: undent.String(` - resource "katapult_ip" "web" {} - resource "katapult_ip" "office" {} + resource "katapult_legacy_ip" "web" {} + resource "katapult_legacy_ip" "office" {} resource "katapult_virtual_machine" "base" { package = "rock-3" @@ -687,8 +687,8 @@ func TestAccKatapultVirtualMachine_update_ips(t *testing.T) { install_agent = true } ip_address_ids = [ - katapult_ip.web.id, - katapult_ip.office.id, + katapult_legacy_ip.web.id, + katapult_legacy_ip.office.id, ] }`, ), @@ -702,11 +702,11 @@ func TestAccKatapultVirtualMachine_update_ips(t *testing.T) { ), resource.TestCheckTypeSetElemAttrPair( "katapult_virtual_machine.base", "ip_address_ids.*", - "katapult_ip.web", "id", + "katapult_legacy_ip.web", "id", ), resource.TestCheckTypeSetElemAttrPair( "katapult_virtual_machine.base", "ip_address_ids.*", - "katapult_ip.office", "id", + "katapult_legacy_ip.office", "id", ), resource.TestCheckResourceAttr( "katapult_virtual_machine.base", @@ -714,18 +714,18 @@ func TestAccKatapultVirtualMachine_update_ips(t *testing.T) { ), resource.TestCheckTypeSetElemAttrPair( "katapult_virtual_machine.base", "ip_addresses.*", - "katapult_ip.web", "address", + "katapult_legacy_ip.web", "address", ), resource.TestCheckTypeSetElemAttrPair( "katapult_virtual_machine.base", "ip_addresses.*", - "katapult_ip.office", "address", + "katapult_legacy_ip.office", "address", ), ), }, { Config: undent.String(` - resource "katapult_ip" "web" {} - resource "katapult_ip" "office" {} + resource "katapult_legacy_ip" "web" {} + resource "katapult_legacy_ip" "office" {} resource "katapult_virtual_machine" "base" { package = "rock-3" @@ -734,7 +734,7 @@ func TestAccKatapultVirtualMachine_update_ips(t *testing.T) { install_agent = true } ip_address_ids = [ - katapult_ip.web.id + katapult_legacy_ip.web.id ] tags = ["web", "app", "lb"] }`, @@ -749,7 +749,7 @@ func TestAccKatapultVirtualMachine_update_ips(t *testing.T) { ), resource.TestCheckTypeSetElemAttrPair( "katapult_virtual_machine.base", "ip_address_ids.*", - "katapult_ip.web", "id", + "katapult_legacy_ip.web", "id", ), resource.TestCheckResourceAttr( "katapult_virtual_machine.base", @@ -757,7 +757,7 @@ func TestAccKatapultVirtualMachine_update_ips(t *testing.T) { ), resource.TestCheckTypeSetElemAttrPair( "katapult_virtual_machine.base", "ip_addresses.*", - "katapult_ip.web", "address", + "katapult_legacy_ip.web", "address", ), ), }, @@ -780,7 +780,7 @@ func TestAccKatapultVirtualMachine_update_group(t *testing.T) { Steps: []resource.TestStep{ { Config: undent.Stringf(` - resource "katapult_ip" "web" {} + resource "katapult_legacy_ip" "web" {} resource "katapult_virtual_machine_group" "web" { name = "%s" @@ -793,7 +793,7 @@ func TestAccKatapultVirtualMachine_update_group(t *testing.T) { install_agent = true } ip_address_ids = [ - katapult_ip.web.id, + katapult_legacy_ip.web.id, ] }`, name, ), @@ -809,7 +809,7 @@ func TestAccKatapultVirtualMachine_update_group(t *testing.T) { }, { Config: undent.Stringf(` - resource "katapult_ip" "web" {} + resource "katapult_legacy_ip" "web" {} resource "katapult_virtual_machine_group" "web" { name = "%s" @@ -822,7 +822,7 @@ func TestAccKatapultVirtualMachine_update_group(t *testing.T) { install_agent = true } ip_address_ids = [ - katapult_ip.web.id, + katapult_legacy_ip.web.id, ] group_id = katapult_virtual_machine_group.web.id }`, name, @@ -839,7 +839,7 @@ func TestAccKatapultVirtualMachine_update_group(t *testing.T) { }, { Config: undent.String(` - resource "katapult_ip" "web" {} + resource "katapult_legacy_ip" "web" {} resource "katapult_virtual_machine" "base" { package = "rock-3" @@ -848,7 +848,7 @@ func TestAccKatapultVirtualMachine_update_group(t *testing.T) { install_agent = true } ip_address_ids = [ - katapult_ip.web.id, + katapult_legacy_ip.web.id, ] }`, ), @@ -881,7 +881,7 @@ func TestAccKatapultVirtualMachine_update_network_speed_profile(t *testing.T) { Steps: []resource.TestStep{ { Config: undent.Stringf(` - resource "katapult_ip" "web" {} + resource "katapult_legacy_ip" "web" {} resource "katapult_virtual_machine" "base" { name = "%s" @@ -891,7 +891,7 @@ func TestAccKatapultVirtualMachine_update_network_speed_profile(t *testing.T) { install_agent = true } ip_address_ids = [ - katapult_ip.web.id, + katapult_legacy_ip.web.id, ] }`, name, ), @@ -907,7 +907,7 @@ func TestAccKatapultVirtualMachine_update_network_speed_profile(t *testing.T) { }, { Config: undent.Stringf(` - resource "katapult_ip" "web" {} + resource "katapult_legacy_ip" "web" {} resource "katapult_virtual_machine" "base" { name = "%s" @@ -917,7 +917,7 @@ func TestAccKatapultVirtualMachine_update_network_speed_profile(t *testing.T) { install_agent = true } ip_address_ids = [ - katapult_ip.web.id, + katapult_legacy_ip.web.id, ] network_speed_profile = "10gbps" }`, name, @@ -934,7 +934,7 @@ func TestAccKatapultVirtualMachine_update_network_speed_profile(t *testing.T) { }, { Config: undent.Stringf(` - resource "katapult_ip" "web" {} + resource "katapult_legacy_ip" "web" {} resource "katapult_virtual_machine" "base" { name = "%s" @@ -944,7 +944,7 @@ func TestAccKatapultVirtualMachine_update_network_speed_profile(t *testing.T) { install_agent = true } ip_address_ids = [ - katapult_ip.web.id, + katapult_legacy_ip.web.id, ] network_speed_profile = "1gbps" }`, name, diff --git a/internal/provider/testdata/SecurityGroup_invalid_rules.cassette.rand_id b/internal/provider/testdata/SecurityGroup_invalid_rules.cassette.rand_id index 698ebf38..f673d468 100644 --- a/internal/provider/testdata/SecurityGroup_invalid_rules.cassette.rand_id +++ b/internal/provider/testdata/SecurityGroup_invalid_rules.cassette.rand_id @@ -1 +1 @@ -ego102f3ucns \ No newline at end of file +h2o9cslvuk1q \ No newline at end of file diff --git a/internal/v6provider/data_source_ip.go b/internal/v6provider/data_source_ip.go new file mode 100644 index 00000000..f6170a3c --- /dev/null +++ b/internal/v6provider/data_source_ip.go @@ -0,0 +1,162 @@ +package v6provider + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/krystal/go-katapult/core" +) + +type ( + IPDataSource struct { + M *Meta + } + + IPDataSourceModel struct { + ID types.String `tfsdk:"id"` + NetworkID types.String `tfsdk:"network_id"` + Version types.Int64 `tfsdk:"version"` + Address types.String `tfsdk:"address"` + AddressWithMask types.String `tfsdk:"address_with_mask"` + ReverseDNS types.String `tfsdk:"reverse_dns"` + VIP types.Bool `tfsdk:"vip"` + Label types.String `tfsdk:"label"` + AllocationType types.String `tfsdk:"allocation_type"` + AllocationID types.String `tfsdk:"allocation_id"` + } +) + +func (r IPDataSource) Metadata( + _ context.Context, + req datasource.MetadataRequest, + resp *datasource.MetadataResponse, +) { + resp.TypeName = req.ProviderTypeName + "_ip" +} + +func (r *IPDataSource) Configure( + _ context.Context, + req datasource.ConfigureRequest, + resp *datasource.ConfigureResponse, +) { + if req.ProviderData == nil { + return + } + + meta, ok := req.ProviderData.(*Meta) + if !ok { + resp.Diagnostics.AddError( + "Meta Error", + "meta is not of type *Meta", + ) + return + } + + r.M = meta +} + +func (r IPDataSource) Schema( + _ context.Context, + _ datasource.SchemaRequest, + resp *datasource.SchemaResponse, +) { + resp.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Computed: true, + Optional: true, + Description: "The ID of this resource.", + Validators: []validator.String{ + stringvalidator.AtLeastOneOf( + path.MatchRoot("id"), + path.MatchRoot("address"), + ), + }, + }, + "network_id": schema.StringAttribute{ + Computed: true, + }, + "version": schema.Int64Attribute{ + Description: "IPv4 or IPv6.", + Computed: true, + }, + "address": schema.StringAttribute{ + Optional: true, + Computed: true, + }, + "address_with_mask": schema.StringAttribute{ + Computed: true, + }, + "reverse_dns": schema.StringAttribute{ + Computed: true, + }, + "vip": schema.BoolAttribute{ + Computed: true, + }, + "label": schema.StringAttribute{ + Description: "VIP label.", + MarkdownDescription: "VIP label.", + Computed: true, + }, + "allocation_type": schema.StringAttribute{ + Computed: true, + }, + "allocation_id": schema.StringAttribute{ + Computed: true, + }, + }, + } +} + +func (r *IPDataSource) Read( + ctx context.Context, + req datasource.ReadRequest, + resp *datasource.ReadResponse, +) { + var data IPDataSourceModel + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + var ip *core.IPAddress + var err error + + switch { + case data.ID.ValueString() != "": + ip, _, err = r.M.Core.IPAddresses.GetByID(ctx, data.ID.ValueString()) + default: + ip, _, err = r.M.Core.IPAddresses.GetByAddress(ctx, + data.Address.ValueString()) + } + + if err != nil { + resp.Diagnostics.AddError( + "IP Error", + err.Error(), + ) + return + } + + if ip.Network != nil { + data.NetworkID = types.StringValue(ip.Network.ID) + } + + data.ID = types.StringValue(ip.ID) + data.Address = types.StringValue(ip.Address) + data.AddressWithMask = types.StringValue(ip.AddressWithMask) + data.ReverseDNS = types.StringValue(ip.ReverseDNS) + data.Version = types.Int64Value(flattenIPVersion(ip.Address)) + data.VIP = types.BoolValue(ip.VIP) + data.Label = types.StringValue(ip.Label) + data.AllocationType = types.StringValue(ip.AllocationType) + data.AllocationID = types.StringValue(ip.AllocationID) + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} diff --git a/internal/provider/data_source_ip_test.go b/internal/v6provider/data_source_ip_test.go similarity index 84% rename from internal/provider/data_source_ip_test.go rename to internal/v6provider/data_source_ip_test.go index f58d91d3..83a4e307 100644 --- a/internal/provider/data_source_ip_test.go +++ b/internal/v6provider/data_source_ip_test.go @@ -1,10 +1,11 @@ -package provider +package v6provider import ( "regexp" "testing" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/jimeh/undent" ) @@ -12,9 +13,9 @@ func TestAccKatapultDataSourceIP_by_id(t *testing.T) { tt := newTestTools(t) resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ProviderFactories: tt.ProviderFactories, - CheckDestroy: testAccCheckKatapultIPDestroy(tt), + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: tt.ProviderFactories, + CheckDestroy: testAccCheckKatapultIPDestroy(tt), Steps: []resource.TestStep{ { Config: undent.String(` @@ -73,9 +74,9 @@ func TestAccKatapultDataSourceIP_by_address(t *testing.T) { tt := newTestTools(t) resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ProviderFactories: tt.ProviderFactories, - CheckDestroy: testAccCheckKatapultIPDestroy(tt), + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: tt.ProviderFactories, + CheckDestroy: testAccCheckKatapultIPDestroy(tt), Steps: []resource.TestStep{ { Config: undent.String(` @@ -134,19 +135,18 @@ func TestAccKatapultDataSourceIP_invalid(t *testing.T) { tt := newTestTools(t) resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ProviderFactories: tt.ProviderFactories, + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: tt.ProviderFactories, Steps: []resource.TestStep{ { Config: `data "katapult_ip" "src" {}`, ExpectError: regexp.MustCompile( - regexp.QuoteMeta("one of `address,id` must be specified"), + regexp.QuoteMeta( + "At least one attribute out of " + + "[id,address] must be specified", + ), ), }, }, }) } - -// -// Helpers -// diff --git a/internal/v6provider/meta.go b/internal/v6provider/meta.go new file mode 100644 index 00000000..a9601a6a --- /dev/null +++ b/internal/v6provider/meta.go @@ -0,0 +1,149 @@ +package v6provider + +import ( + "net/http" + "net/url" + "os" + "time" + + "github.com/hashicorp/go-hclog" + + "github.com/krystal/go-katapult" + "github.com/krystal/go-katapult/core" + "github.com/krystal/go-katapult/namegenerator" +) + +type Meta struct { + Client *katapult.Client + Core *core.Client + Logger hclog.Logger + + GeneratedNamePrefix string + SkipTrashObjectPurge bool + + // Raw provider attribute string values + confAPIKey string + confDataCenter string + confOrganization string + + // Internal cache of shallow lookup reference objects + DataCenterRef core.DataCenterRef + OrganizationRef core.OrganizationRef +} + +func (m *Meta) UseOrGenerateName(name string) string { + switch { + case name != "": + return name + case m.GeneratedNamePrefix == "": + return namegenerator.RandomName() + default: + return namegenerator.RandomName(m.GeneratedNamePrefix) + } +} + +func (m *Meta) UseOrGenerateHostname(hostname string) string { + switch { + case hostname != "": + return hostname + case m.GeneratedNamePrefix == "": + return namegenerator.RandomHostname() + default: + return m.GeneratedNamePrefix + "-" + namegenerator.RandomHostname() + } +} + +func NewMeta( + apiKey string, + datacenter string, + org string, + skipTrashObjectPurge *bool, + logLevel string, + generatedNamePrefix string, + httpClient *http.Client, + version string, + terraformVersion string, +) (*Meta, error) { + logLevel = stringOrEnv( + logLevel, + "KATAPULT_LOG_LEVEL", + ) + if logLevel == "" { + logLevel = "info" + } + + m := &Meta{ + Logger: hclog.New(&hclog.LoggerOptions{ + Name: "katapult", + Level: hclog.LevelFromString(logLevel), + TimeFormat: "2006/01/02 15:04:05", + }), + confAPIKey: stringOrEnv( + apiKey, + "KATAPULT_API_KEY", + ), + confDataCenter: stringOrEnv( + datacenter, + "KATAPULT_DATA_CENTER", + ), + confOrganization: stringOrEnv( + org, + "KATAPULT_ORGANIZATION", + ), + SkipTrashObjectPurge: boolOrEnv( + skipTrashObjectPurge, + "KATAPULT_SKIP_TRASH_OBJECT_PURGE", + ), + GeneratedNamePrefix: generatedNamePrefix, + } + + if m.GeneratedNamePrefix == "" { + m.GeneratedNamePrefix = defaultGeneratedNamePrefix + } + + opts := []katapult.Option{ + katapult.WithAPIKey(m.confAPIKey), + katapult.WithUserAgent( + userAgent( + "terraform-provider-katapult", + terraformVersion, + version, + ), + ), + } + if httpClient == nil { + httpClient = &http.Client{Timeout: 60 * time.Second} + } + + opts = append(opts, katapult.WithHTTPClient(httpClient)) + + // Debug override of API URL for internal testing purposes. + if apiURL := os.Getenv("KATAPULT_TF_DEBUG_API_URL"); apiURL != "" { + u, err := url.Parse(apiURL) + if err != nil { + return nil, err + } + + opts = append(opts, katapult.WithBaseURL(u)) + } + + c, err := katapult.New(opts...) + if err != nil { + return nil, err + } + + rhc := newRetryableHTTPClient(httpClient, m.Logger) + c.HTTPClient = rhc.StandardClient() + + m.Client = c + m.Core = core.New(m.Client) + + m.OrganizationRef = core.OrganizationRef{ + SubDomain: m.confOrganization, + } + m.DataCenterRef = core.DataCenterRef{ + Permalink: m.confDataCenter, + } + + return m, nil +} diff --git a/internal/v6provider/meta_test.go b/internal/v6provider/meta_test.go new file mode 100644 index 00000000..71d3cdd3 --- /dev/null +++ b/internal/v6provider/meta_test.go @@ -0,0 +1,110 @@ +package v6provider + +import ( + "regexp" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestMeta_UseOrGenerateName(t *testing.T) { + type fields struct { + GeneratedNamePrefix string + } + type args struct { + name string + } + tests := []struct { + name string + fields fields + args args + want *regexp.Regexp + }{ + { + name: "no prefix and empty string", + fields: fields{}, + args: args{name: ""}, + want: regexp.MustCompile("^[^-]+-[^-]+$"), + }, + { + name: "no prefix and non-empty string", + fields: fields{}, + args: args{name: "dope-groovy-narwhal-flower"}, + want: regexp.MustCompile("^dope-groovy-narwhal-flower$"), + }, + { + name: "prefix and empty string", + fields: fields{GeneratedNamePrefix: "tf-unit-test"}, + args: args{name: ""}, + want: regexp.MustCompile("^tf-unit-test-[^-]+-[^-]+$"), + }, + { + name: "prefix and non-empty string", + fields: fields{GeneratedNamePrefix: "tf-unit-test"}, + args: args{name: "dope-groovy-narwhal-flower"}, + want: regexp.MustCompile("^dope-groovy-narwhal-flower$"), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := &Meta{ + GeneratedNamePrefix: tt.fields.GeneratedNamePrefix, + } + + got := m.UseOrGenerateName(tt.args.name) + + assert.Regexp(t, tt.want, got) + }) + } +} + +func TestMeta_UseOrGenerateHostname(t *testing.T) { + type fields struct { + GeneratedNamePrefix string + } + type args struct { + name string + } + tests := []struct { + name string + fields fields + args args + want *regexp.Regexp + }{ + { + name: "no prefix and empty string", + fields: fields{}, + args: args{name: ""}, + want: regexp.MustCompile("^[^-]+-[^-]+-[^-]+$"), + }, + { + name: "no prefix and non-empty string", + fields: fields{}, + args: args{name: "dope-groovy-narwhal-flower"}, + want: regexp.MustCompile("^dope-groovy-narwhal-flower$"), + }, + { + name: "prefix and empty string", + fields: fields{GeneratedNamePrefix: "tf-unit-test"}, + args: args{name: ""}, + want: regexp.MustCompile("^tf-unit-test-[^-]+-[^-]+-[^-]+$"), + }, + { + name: "prefix and non-empty string", + fields: fields{GeneratedNamePrefix: "tf-unit-test"}, + args: args{name: "dope-groovy-narwhal-flower"}, + want: regexp.MustCompile("^dope-groovy-narwhal-flower$"), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := &Meta{ + GeneratedNamePrefix: tt.fields.GeneratedNamePrefix, + } + + got := m.UseOrGenerateHostname(tt.args.name) + + assert.Regexp(t, tt.want, got) + }) + } +} diff --git a/internal/v6provider/resource_ip.go b/internal/v6provider/resource_ip.go new file mode 100644 index 00000000..8bb3a31e --- /dev/null +++ b/internal/v6provider/resource_ip.go @@ -0,0 +1,347 @@ +package v6provider + +import ( + "context" + "errors" + "strings" + + "github.com/hashicorp/terraform-plugin-framework-validators/int64validator" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/tfsdk" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/krystal/go-katapult" + "github.com/krystal/go-katapult/core" +) + +type ( + IPResource struct { + M *Meta + } + + IPResourceModel struct { + ID types.String `tfsdk:"id"` + NetworkID types.String `tfsdk:"network_id"` + Version types.Int64 `tfsdk:"version"` + Address types.String `tfsdk:"address"` + AddressWithMask types.String `tfsdk:"address_with_mask"` + ReverseDNS types.String `tfsdk:"reverse_dns"` + VIP types.Bool `tfsdk:"vip"` + Label types.String `tfsdk:"label"` + AllocationType types.String `tfsdk:"allocation_type"` + AllocationID types.String `tfsdk:"allocation_id"` + } +) + +func (r IPResource) Metadata( + _ context.Context, + req resource.MetadataRequest, + resp *resource.MetadataResponse, +) { + resp.TypeName = req.ProviderTypeName + "_ip" +} + +func (r *IPResource) Configure( + _ context.Context, + req resource.ConfigureRequest, + resp *resource.ConfigureResponse, +) { + if req.ProviderData == nil { + return + } + + meta, ok := req.ProviderData.(*Meta) + if !ok { + resp.Diagnostics.AddError( + "Meta Error", + "meta is not of type *Meta", + ) + return + } + + r.M = meta +} + +func (r IPResource) Schema( + _ context.Context, + _ resource.SchemaRequest, + resp *resource.SchemaResponse, +) { + resp.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Computed: true, + }, + "network_id": schema.StringAttribute{ + Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + "version": schema.Int64Attribute{ + Description: "IPv4 or IPv6. Default is `4`.", + MarkdownDescription: "IPv4 or IPv6. " + + "Default is `4`.", + Optional: true, + Computed: true, + Default: int64default.StaticInt64(4), + PlanModifiers: []planmodifier.Int64{ + int64planmodifier.RequiresReplace(), + }, + Validators: []validator.Int64{ + int64validator.OneOf(4, 6), + }, + }, + "address": schema.StringAttribute{ + Computed: true, + }, + "address_with_mask": schema.StringAttribute{ + Computed: true, + }, + "reverse_dns": schema.StringAttribute{ + Computed: true, + }, + "vip": schema.BoolAttribute{ + Description: "Default is `false`.", + MarkdownDescription: "Default is `false`.", + Optional: true, + Computed: true, + Default: booldefault.StaticBool(false), + }, + "label": schema.StringAttribute{ + Description: "VIP label. Required when vip is true.", + MarkdownDescription: "VIP label. " + + "Required when **vip** is `true`.", + Optional: true, + Computed: true, + Validators: []validator.String{ + stringvalidator.AlsoRequires( + path.MatchRoot("vip")), + stringvalidator.LengthAtLeast(1), + }, + }, + "allocation_type": schema.StringAttribute{ + Computed: true, + }, + "allocation_id": schema.StringAttribute{ + Computed: true, + }, + }, + } +} + +func (r *IPResource) Create( + ctx context.Context, + req resource.CreateRequest, + resp *resource.CreateResponse, +) { + var plan IPResourceModel + + diags := req.Plan.Get(ctx, &plan) + resp.Diagnostics.Append(diags...) + + if resp.Diagnostics.HasError() { + return + } + + var network *core.Network + + if netID := plan.NetworkID.ValueString(); netID != "" { + network = &core.Network{ID: netID} + } else { + var err error + network, _, err = r.M.Core.DataCenters.DefaultNetwork( + ctx, r.M.DataCenterRef, + ) + + if err != nil { + resp.Diagnostics.AddError( + "Default Network Error", + err.Error(), + ) + return + } + } + + args := &core.IPAddressCreateArguments{ + Network: network.Ref(), + Version: unflattenIPVersion(plan.Version.ValueInt64()), + } + + if vip := plan.VIP.ValueBool(); vip { + args.VIP = &vip + args.Label = plan.Label.ValueString() + } + + ip, _, err := r.M.Core.IPAddresses.Create(ctx, r.M.OrganizationRef, args) + if err != nil { + resp.Diagnostics.AddError("IP Address Create Error", err.Error()) + return + } + + plan.ID = types.StringValue(ip.ID) + + diags = resp.State.Set(ctx, plan) + resp.Diagnostics.Append(diags...) + + if err := r.IPRead(ctx, &plan, &resp.State); err != nil { + resp.Diagnostics.AddError("IP Address Read Error", err.Error()) + return + } + + diags = resp.State.Set(ctx, plan) + resp.Diagnostics.Append(diags...) +} + +func (r *IPResource) Read( + ctx context.Context, + req resource.ReadRequest, + resp *resource.ReadResponse, +) { + state := &IPResourceModel{} + diags := req.State.Get(ctx, &state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + if err := r.IPRead(ctx, state, &resp.State); err != nil { + resp.Diagnostics.AddError("IP Address Read Error", err.Error()) + return + } + + diags = resp.State.Set(ctx, state) + resp.Diagnostics.Append(diags...) +} + +func (r *IPResource) Update( + ctx context.Context, + req resource.UpdateRequest, + resp *resource.UpdateResponse, +) { + var plan IPResourceModel + + diags := req.Plan.Get(ctx, &plan) + resp.Diagnostics.Append(diags...) + + if resp.Diagnostics.HasError() { + return + } + + var state IPResourceModel + diags = req.State.Get(ctx, &state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + ipRef := core.IPAddressRef{ID: plan.ID.String()} + args := &core.IPAddressUpdateArguments{} + + if !plan.VIP.Equal(state.VIP) { + vip := plan.VIP.ValueBool() + args.VIP = &vip + } + + if !plan.Label.Equal(state.Label) { + args.Label = plan.Label.ValueString() + } + + _, _, err := r.M.Core.IPAddresses.Update(ctx, ipRef, args) + if err != nil { + resp.Diagnostics.AddError("IP Address Update Error", err.Error()) + return + } + + if err := r.IPRead(ctx, &plan, &resp.State); err != nil { + resp.Diagnostics.AddError("IP Address Read Error", err.Error()) + return + } + + diags = resp.State.Set(ctx, plan) + resp.Diagnostics.Append(diags...) +} + +func (r *IPResource) Delete( + ctx context.Context, + req resource.DeleteRequest, + resp *resource.DeleteResponse, +) { + state := &IPResourceModel{} + diags := req.State.Get(ctx, &state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + ipRef := core.IPAddressRef{ID: state.ID.ValueString()} + _, err := r.M.Core.IPAddresses.Delete(ctx, ipRef) + if err != nil { + resp.Diagnostics.AddError("IP Address Delete Error", err.Error()) + } +} + +func (r *IPResource) IPRead( + ctx context.Context, + model *IPResourceModel, + state *tfsdk.State, +) error { + ip, _, err := r.M.Core.IPAddresses.GetByID(ctx, model.ID.ValueString()) + if err != nil { + if errors.Is(err, katapult.ErrNotFound) { + state.RemoveResource(ctx) + return nil + } + + return err + } + + if ip.Network != nil { + model.NetworkID = types.StringValue(ip.Network.ID) + } + + model.Address = types.StringValue(ip.Address) + model.AddressWithMask = types.StringValue(ip.AddressWithMask) + model.ReverseDNS = types.StringValue(ip.ReverseDNS) + model.Version = types.Int64Value(flattenIPVersion(ip.Address)) + model.VIP = types.BoolValue(ip.VIP) + model.Label = types.StringValue(ip.Label) + model.AllocationType = types.StringValue(ip.AllocationType) + model.AllocationID = types.StringValue(ip.AllocationID) + + return nil +} + +func (r *IPResource) ImportState( + ctx context.Context, + req resource.ImportStateRequest, + resp *resource.ImportStateResponse, +) { + resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) +} + +func unflattenIPVersion(ver int64) core.IPVersion { + switch ver { + case 6: + return core.IPv6 + default: + return core.IPv4 + } +} + +func flattenIPVersion(address string) int64 { + if strings.Count(address, ":") < 2 { + return 4 + } + + return 6 +} diff --git a/internal/v6provider/resource_ip_test.go b/internal/v6provider/resource_ip_test.go new file mode 100644 index 00000000..d809a3e5 --- /dev/null +++ b/internal/v6provider/resource_ip_test.go @@ -0,0 +1,555 @@ +package v6provider + +import ( + "context" + "fmt" + "regexp" + "strconv" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/terraform" + "github.com/jimeh/undent" + "github.com/krystal/go-katapult/core" + "github.com/stretchr/testify/require" +) + +func init() { //nolint:gochecknoinits + resource.AddTestSweepers("katapult_ip", &resource.Sweeper{ + Name: "katapult_ip", + F: testSweepIPs, + Dependencies: []string{"katapult_virtual_machine"}, + }) +} + +func testSweepIPs(_ string) error { + m := sweepMeta() + ctx := context.TODO() + + var ips []*core.IPAddress + totalPages := 2 + for pageNum := 1; pageNum <= totalPages; pageNum++ { + pageResult, resp, err := m.Core.IPAddresses.List( + ctx, m.OrganizationRef, + &core.ListOptions{Page: pageNum}, + ) + if err != nil { + return err + } + + totalPages = resp.Pagination.TotalPages + ips = append(ips, pageResult...) + } + + for _, ip := range ips { + if ip.AllocationID != "" { + m.Logger.Info( + "skipping IP address: has allocation", + "id", ip.ID, + "address", ip.Address, + "allocation_id", ip.AllocationID, + "allocation_type", ip.AllocationType, + ) + + continue + } + + m.Logger.Info("deleting IP address", "id", ip.ID, "address", ip.Address) + _, err := m.Core.IPAddresses.Delete(ctx, ip.Ref()) + if err != nil { + return err + } + } + + return nil +} + +func TestAccKatapultIP_minimal(t *testing.T) { + tt := newTestTools(t) + + network, _, err := tt.Meta.Core.DataCenters.DefaultNetwork( + tt.Ctx, tt.Meta.DataCenterRef, + ) + + require.NoError(t, err) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: tt.ProviderFactories, + + CheckDestroy: testAccCheckKatapultIPDestroy(tt), + Steps: []resource.TestStep{ + { + Config: `resource "katapult_ip" "web" {}`, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckKatapultIPAttrs(tt, "katapult_ip.web"), + resource.TestCheckResourceAttr( + "katapult_ip.web", "network_id", network.ID, + ), + resource.TestMatchResourceAttr( + "katapult_ip.web", + "address", regexp.MustCompile( + `^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$`, + ), + ), + resource.TestCheckResourceAttr( + "katapult_ip.web", "version", "4", + ), + resource.TestCheckResourceAttr( + "katapult_ip.web", "vip", "false", + ), + resource.TestCheckResourceAttr( + "katapult_ip.web", "label", "", + ), + ), + }, + { + ResourceName: "katapult_ip.web", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccKatapultIP_ipv4(t *testing.T) { + tt := newTestTools(t) + + network, _, err := tt.Meta.Core.DataCenters.DefaultNetwork( + tt.Ctx, tt.Meta.DataCenterRef, + ) + require.NoError(t, err) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: tt.ProviderFactories, + CheckDestroy: testAccCheckKatapultIPDestroy(tt), + Steps: []resource.TestStep{ + { + Config: undent.String(` + resource "katapult_ip" "web" { + version = 4 + }`, + ), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckKatapultIPAttrs(tt, "katapult_ip.web"), + resource.TestCheckResourceAttr( + "katapult_ip.web", "network_id", network.ID, + ), + resource.TestMatchResourceAttr( + "katapult_ip.web", + "address", regexp.MustCompile( + `^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$`, + ), + ), + resource.TestCheckResourceAttr( + "katapult_ip.web", "version", "4", + ), + resource.TestCheckResourceAttr( + "katapult_ip.web", "vip", "false", + ), + resource.TestCheckResourceAttr( + "katapult_ip.web", "label", "", + ), + ), + }, + { + ResourceName: "katapult_ip.web", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccKatapultIP_ipv6(t *testing.T) { + tt := newTestTools(t) + + network, _, err := tt.Meta.Core.DataCenters.DefaultNetwork( + tt.Ctx, tt.Meta.DataCenterRef, + ) + require.NoError(t, err) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: tt.ProviderFactories, + CheckDestroy: testAccCheckKatapultIPDestroy(tt), + Steps: []resource.TestStep{ + { + Config: undent.String(` + resource "katapult_ip" "web" { + version = 6 + }`, + ), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckKatapultIPAttrs(tt, "katapult_ip.web"), + resource.TestCheckResourceAttr( + "katapult_ip.web", "network_id", network.ID, + ), + resource.TestMatchResourceAttr( + "katapult_ip.web", + "address", regexp.MustCompile(`:.*:`), + ), + resource.TestCheckResourceAttr( + "katapult_ip.web", "version", "6", + ), + resource.TestCheckResourceAttr( + "katapult_ip.web", "vip", "false", + ), + resource.TestCheckResourceAttr( + "katapult_ip.web", "label", "", + ), + ), + }, + { + ResourceName: "katapult_ip.web", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccKatapultIP_ipv5(t *testing.T) { + tt := newTestTools(t) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: tt.ProviderFactories, + CheckDestroy: testAccCheckKatapultIPDestroy(tt), + Steps: []resource.TestStep{ + { + Config: undent.String(` + resource "katapult_ip" "web" { + version = 5 + }`, + ), + ExpectError: regexp.MustCompile( + regexp.QuoteMeta( + `Attribute version value must be one ` + + `of: ["4" "6"], got: 5`, + ), + ), + }, + }, + }) +} + +func TestAccKatapultIP_vip(t *testing.T) { + tt := newTestTools(t) + + name := tt.ResourceName() + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: tt.ProviderFactories, + CheckDestroy: testAccCheckKatapultIPDestroy(tt), + Steps: []resource.TestStep{ + { + Config: undent.Stringf(` + resource "katapult_ip" "vip" { + vip = true + label = "%s" + }`, + name, + ), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckKatapultIPAttrs(tt, "katapult_ip.vip"), + resource.TestCheckResourceAttr( + "katapult_ip.vip", "vip", "true", + ), + resource.TestCheckResourceAttr( + "katapult_ip.vip", "label", name, + ), + ), + }, + { + ResourceName: "katapult_ip.vip", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccKatapultIP_vip_empty_label(t *testing.T) { + tt := newTestTools(t) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: tt.ProviderFactories, + CheckDestroy: testAccCheckKatapultIPDestroy(tt), + Steps: []resource.TestStep{ + { + Config: undent.String(` + resource "katapult_ip" "vip" { + vip = true + label = "" + }`, + ), + ExpectError: regexp.MustCompile( + regexp.QuoteMeta( + `Attribute label string length must be at least 1,` + + ` got: 0`, + ), + ), + }, + }, + }) +} + +func TestAccKatapultIP_vip_without_label(t *testing.T) { + tt := newTestTools(t) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: tt.ProviderFactories, + CheckDestroy: testAccCheckKatapultIPDestroy(tt), + Steps: []resource.TestStep{ + { + Config: undent.String(` + resource "katapult_ip" "vip" { + vip = true + }`, + ), + ExpectError: regexp.MustCompile( + `(?s).*validation_error.+Label can't be blank.*`, + ), + }, + }, + }) +} + +func TestAccKatapultIP_label_without_vip(t *testing.T) { + tt := newTestTools(t) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: tt.ProviderFactories, + CheckDestroy: testAccCheckKatapultIPDestroy(tt), + Steps: []resource.TestStep{ + { + Config: undent.String(` + resource "katapult_ip" "vip" { + label = "hello" + }`, + ), + ExpectError: regexp.MustCompile( + regexp.QuoteMeta( + `Attribute "vip" must be specified when ` + + `"label" is specified`, + ), + ), + }, + }, + }) +} + +func TestAccKatapultIP_with_network_id(t *testing.T) { + tt := newTestTools(t) + + network, _, err := tt.Meta.Core.DataCenters.DefaultNetwork( + tt.Ctx, tt.Meta.DataCenterRef, + ) + require.NoError(t, err) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: tt.ProviderFactories, + CheckDestroy: testAccCheckKatapultIPDestroy(tt), + Steps: []resource.TestStep{ + { + Config: undent.Stringf(` + resource "katapult_ip" "net" { + network_id = "%s" + }`, + network.ID, + ), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckKatapultIPAttrs(tt, "katapult_ip.net"), + resource.TestCheckResourceAttr( + "katapult_ip.net", "network_id", network.ID, + ), + ), + }, + { + ResourceName: "katapult_ip.net", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccKatapultIP_update(t *testing.T) { + tt := newTestTools(t) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: tt.ProviderFactories, + CheckDestroy: testAccCheckKatapultIPDestroy(tt), + Steps: []resource.TestStep{ + { + Config: `resource "katapult_ip" "update" {}`, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckKatapultIPAttrs(tt, "katapult_ip.update"), + resource.TestCheckResourceAttr( + "katapult_ip.update", "vip", "false", + ), + resource.TestCheckResourceAttr( + "katapult_ip.update", "label", "", + ), + ), + }, + { + Config: undent.String(` + resource "katapult_ip" "update" { + vip = true + label = "vip-yes" + }`, + ), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckKatapultIPAttrs(tt, "katapult_ip.update"), + resource.TestCheckResourceAttr( + "katapult_ip.update", "vip", "true", + ), + resource.TestCheckResourceAttr( + "katapult_ip.update", "label", "vip-yes", + ), + ), + }, + { + Config: undent.String(` + resource "katapult_ip" "update" { + vip = true + label = "vip-oh-yes" + }`, + ), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckKatapultIPAttrs(tt, "katapult_ip.update"), + resource.TestCheckResourceAttr( + "katapult_ip.update", "vip", "true", + ), + resource.TestCheckResourceAttr( + "katapult_ip.update", "label", "vip-oh-yes", + ), + ), + }, + { + Config: undent.String(` + resource "katapult_ip" "update" { + vip = false + }`, + ), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckKatapultIPAttrs(tt, "katapult_ip.update"), + resource.TestCheckResourceAttr( + "katapult_ip.update", "vip", "false", + ), + resource.TestCheckResourceAttr( + "katapult_ip.update", "label", "", + ), + ), + }, + }, + }) +} + +// +// Helpers +// + +func testAccCheckKatapultIPExists( + tt *testTools, + res string, +) resource.TestCheckFunc { + m := tt.Meta + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[res] + if !ok { + return fmt.Errorf("resource not found: %s", res) + } + + ip, _, err := m.Core.IPAddresses.GetByID(tt.Ctx, rs.Primary.ID) + if err != nil { + return err + } + + return resource.TestCheckResourceAttr(res, "id", ip.ID)(s) + } +} + +func testAccCheckKatapultIPAttrs( + tt *testTools, + res string, +) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[res] + if !ok { + return fmt.Errorf("resource not found: %s", res) + } + + var err error + ip, _, err := tt.Meta.Core.IPAddresses.GetByID( + tt.Ctx, rs.Primary.ID, + ) + if err != nil { + return err + } + + tfs := []resource.TestCheckFunc{ + resource.TestCheckResourceAttr(res, "id", ip.ID), + resource.TestCheckResourceAttr(res, "address", ip.Address), + resource.TestCheckResourceAttr( + res, "address_with_mask", ip.AddressWithMask, + ), + resource.TestCheckResourceAttr(res, "reverse_dns", ip.ReverseDNS), + resource.TestCheckResourceAttr( + res, + "version", + strconv.FormatInt(flattenIPVersion(ip.Address), 10), + ), + resource.TestCheckResourceAttr( + res, "vip", fmt.Sprintf("%t", ip.VIP), + ), + resource.TestCheckResourceAttr( + res, "allocation_type", ip.AllocationType, + ), + resource.TestCheckResourceAttr( + res, "allocation_id", ip.AllocationID, + ), + } + + if ip.Network != nil { + tfs = append(tfs, resource.TestCheckResourceAttr( + res, "network_id", ip.Network.ID, + )) + } + + return resource.ComposeAggregateTestCheckFunc(tfs...)(s) + } +} + +func testAccCheckKatapultIPDestroy( + tt *testTools, +) resource.TestCheckFunc { + m := tt.Meta + + return func(s *terraform.State) error { + for _, rs := range s.RootModule().Resources { + if rs.Type != "katapult_ip" { + continue + } + + ip, _, err := m.Core.IPAddresses.GetByID(tt.Ctx, rs.Primary.ID) + if err == nil && ip != nil { + return fmt.Errorf( + "katapult_ip %s (%s) was not destroyed", + rs.Primary.ID, ip.Address) + } + } + + return nil + } +} diff --git a/internal/v6provider/sweeper_test.go b/internal/v6provider/sweeper_test.go new file mode 100644 index 00000000..c80cf775 --- /dev/null +++ b/internal/v6provider/sweeper_test.go @@ -0,0 +1,30 @@ +package v6provider + +import ( + "context" + "log" + "testing" + + "github.com/hashicorp/terraform-plugin-framework/provider" + "github.com/hashicorp/terraform-plugin-framework/tfsdk" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +func TestMain(m *testing.M) { + resource.TestMain(m) +} + +func sweepMeta() *Meta { + k := &KatapultProvider{Version: testAccProviderVersion} + resp := &provider.ConfigureResponse{} + k.Configure( + context.TODO(), + provider.ConfigureRequest{Config: tfsdk.Config{}}, + resp, + ) + if resp.Diagnostics.HasError() { + log.Fatalf("failed to configure client: %+v", resp.Diagnostics) + } + + return k.m +} diff --git a/internal/v6provider/testdata/DataSourceIP_by_address.cassette.yaml b/internal/v6provider/testdata/DataSourceIP_by_address.cassette.yaml new file mode 100644 index 00000000..4b1463d6 --- /dev/null +++ b/internal/v6provider/testdata/DataSourceIP_by_address.cassette.yaml @@ -0,0 +1,504 @@ +--- +version: 1 +interactions: +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/data_centers/_/default_network?data_center%5Bpermalink%5D=uk-lon-01 + method: GET + response: + body: '{"network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01"}}}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "181" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 13:38:43 GMT + Etag: + - W/"d60d47b2ba0b179327bb89a97b1c0e77" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "199" + X-Request-Id: + - ff140d5f-0115-4f89-84af-ea9fb5a103c0 + status: 200 OK + code: 200 + duration: "" +- request: + body: | + {"organization":{"sub_domain":"terraform-acc-test"},"network":{"id":"netw_gVRkZdSKczfNg34P"},"version":"ipv4"} + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/organizations/_/ip_addresses + method: POST + response: + body: '{"ip_address":{"id":"ip_EppNXhWKM7pWlcrW","address":"185.199.222.89","reverse_dns":"185-199-222-89.rdns.katapult.cloud","vip":false,"label":null,"address_with_mask":"185.199.222.89/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null}}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "549" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 13:38:43 GMT + Etag: + - W/"e47caecc91f78c8b5ad1f1e48bb77507" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "197" + X-Request-Id: + - 61cefe36-49b5-4373-afbb-828b9d48d6ac + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_EppNXhWKM7pWlcrW + method: GET + response: + body: '{"ip_address":{"id":"ip_EppNXhWKM7pWlcrW","address":"185.199.222.89","reverse_dns":"185-199-222-89.rdns.katapult.cloud","vip":false,"label":null,"address_with_mask":"185.199.222.89/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null},"allocation":null}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "567" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 13:38:43 GMT + Etag: + - W/"ce62a882b60e2eff3b6406c19450a229" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "195" + X-Request-Id: + - f0ea74d5-3c56-43d1-9f38-8ad283faecc0 + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Baddress%5D=185.199.222.89 + method: GET + response: + body: '{"ip_address":{"id":"ip_EppNXhWKM7pWlcrW","address":"185.199.222.89","reverse_dns":"185-199-222-89.rdns.katapult.cloud","vip":false,"label":null,"address_with_mask":"185.199.222.89/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null},"allocation":null}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "567" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 13:38:43 GMT + Etag: + - W/"ce62a882b60e2eff3b6406c19450a229" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "194" + X-Request-Id: + - 8c95c030-bb5d-4dab-a07d-fee9d81e3824 + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_EppNXhWKM7pWlcrW + method: GET + response: + body: '{"ip_address":{"id":"ip_EppNXhWKM7pWlcrW","address":"185.199.222.89","reverse_dns":"185-199-222-89.rdns.katapult.cloud","vip":false,"label":null,"address_with_mask":"185.199.222.89/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null},"allocation":null}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "567" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 13:38:43 GMT + Etag: + - W/"ce62a882b60e2eff3b6406c19450a229" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "193" + X-Request-Id: + - fbe0b6ef-ac50-4373-8914-6593deca50ae + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Baddress%5D=185.199.222.89 + method: GET + response: + body: '{"ip_address":{"id":"ip_EppNXhWKM7pWlcrW","address":"185.199.222.89","reverse_dns":"185-199-222-89.rdns.katapult.cloud","vip":false,"label":null,"address_with_mask":"185.199.222.89/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null},"allocation":null}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "567" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 13:38:43 GMT + Etag: + - W/"ce62a882b60e2eff3b6406c19450a229" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "190" + X-Request-Id: + - 65a0a710-4355-415a-9a21-d1982c9abbdf + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_EppNXhWKM7pWlcrW + method: GET + response: + body: '{"ip_address":{"id":"ip_EppNXhWKM7pWlcrW","address":"185.199.222.89","reverse_dns":"185-199-222-89.rdns.katapult.cloud","vip":false,"label":null,"address_with_mask":"185.199.222.89/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null},"allocation":null}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "567" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 13:38:43 GMT + Etag: + - W/"ce62a882b60e2eff3b6406c19450a229" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "188" + X-Request-Id: + - 91acd932-16bb-4825-a3a3-6124967fbaad + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Baddress%5D=185.199.222.89 + method: GET + response: + body: '{"ip_address":{"id":"ip_EppNXhWKM7pWlcrW","address":"185.199.222.89","reverse_dns":"185-199-222-89.rdns.katapult.cloud","vip":false,"label":null,"address_with_mask":"185.199.222.89/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null},"allocation":null}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "567" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 13:38:43 GMT + Etag: + - W/"ce62a882b60e2eff3b6406c19450a229" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "186" + X-Request-Id: + - 6fcabcf0-a021-4022-bf30-6ad451062997 + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Baddress%5D=185.199.222.89 + method: GET + response: + body: '{"ip_address":{"id":"ip_EppNXhWKM7pWlcrW","address":"185.199.222.89","reverse_dns":"185-199-222-89.rdns.katapult.cloud","vip":false,"label":null,"address_with_mask":"185.199.222.89/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null},"allocation":null}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "567" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 13:38:43 GMT + Etag: + - W/"ce62a882b60e2eff3b6406c19450a229" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "184" + X-Request-Id: + - 13cac141-babf-475f-a0b5-8d414cbef57e + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_EppNXhWKM7pWlcrW + method: DELETE + response: + body: '{}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "2" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 13:38:43 GMT + Etag: + - W/"44136fa355b3678a1146ad16f7e8649e" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "181" + X-Request-Id: + - 39ca6faa-eca7-4e19-8271-0b9f62ea79b4 + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_EppNXhWKM7pWlcrW + method: GET + response: + body: '{"error":{"code":"ip_address_not_found","description":"No IP addresses + were found matching any of the criteria provided in the arguments","detail":{}}}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - no-cache + Content-Length: + - "151" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 13:38:43 GMT + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Api-Schema: + - json-error + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "179" + X-Request-Id: + - ae1a2899-df63-40af-bcc2-eca383eadb0f + status: 404 Not Found + code: 404 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_EppNXhWKM7pWlcrW + method: GET + response: + body: '{"error":{"code":"ip_address_not_found","description":"No IP addresses + were found matching any of the criteria provided in the arguments","detail":{}}}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - no-cache + Content-Length: + - "151" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 13:38:43 GMT + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Api-Schema: + - json-error + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "178" + X-Request-Id: + - d9898a76-846d-4a77-b481-9861b1306639 + status: 404 Not Found + code: 404 + duration: "" diff --git a/internal/v6provider/testdata/DataSourceIP_by_id.cassette.yaml b/internal/v6provider/testdata/DataSourceIP_by_id.cassette.yaml new file mode 100644 index 00000000..eb992daf --- /dev/null +++ b/internal/v6provider/testdata/DataSourceIP_by_id.cassette.yaml @@ -0,0 +1,504 @@ +--- +version: 1 +interactions: +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/data_centers/_/default_network?data_center%5Bpermalink%5D=uk-lon-01 + method: GET + response: + body: '{"network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01"}}}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "181" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 13:38:43 GMT + Etag: + - W/"d60d47b2ba0b179327bb89a97b1c0e77" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "198" + X-Request-Id: + - af82d0d1-be07-4256-89c5-b0b066c4a1ff + status: 200 OK + code: 200 + duration: "" +- request: + body: | + {"organization":{"sub_domain":"terraform-acc-test"},"network":{"id":"netw_gVRkZdSKczfNg34P"},"version":"ipv4"} + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/organizations/_/ip_addresses + method: POST + response: + body: '{"ip_address":{"id":"ip_AcSzjZJFamxNtScE","address":"185.199.222.45","reverse_dns":"185-199-222-45.rdns.katapult.cloud","vip":false,"label":null,"address_with_mask":"185.199.222.45/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null}}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "549" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 13:38:43 GMT + Etag: + - W/"da6e501e679e64075c688d63392b2251" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "196" + X-Request-Id: + - f2c8256c-9927-4a8f-95fb-16ab4dda31c1 + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_AcSzjZJFamxNtScE + method: GET + response: + body: '{"ip_address":{"id":"ip_AcSzjZJFamxNtScE","address":"185.199.222.45","reverse_dns":"185-199-222-45.rdns.katapult.cloud","vip":false,"label":null,"address_with_mask":"185.199.222.45/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null},"allocation":null}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "567" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 13:38:43 GMT + Etag: + - W/"d267285e34915427200cc05d039e8071" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "192" + X-Request-Id: + - 7dac4cd0-88da-48c1-81a8-4c25eec8172d + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_AcSzjZJFamxNtScE + method: GET + response: + body: '{"ip_address":{"id":"ip_AcSzjZJFamxNtScE","address":"185.199.222.45","reverse_dns":"185-199-222-45.rdns.katapult.cloud","vip":false,"label":null,"address_with_mask":"185.199.222.45/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null},"allocation":null}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "567" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 13:38:43 GMT + Etag: + - W/"d267285e34915427200cc05d039e8071" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "191" + X-Request-Id: + - 12936275-530d-4b43-b531-294883e2d87b + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_AcSzjZJFamxNtScE + method: GET + response: + body: '{"ip_address":{"id":"ip_AcSzjZJFamxNtScE","address":"185.199.222.45","reverse_dns":"185-199-222-45.rdns.katapult.cloud","vip":false,"label":null,"address_with_mask":"185.199.222.45/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null},"allocation":null}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "567" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 13:38:43 GMT + Etag: + - W/"d267285e34915427200cc05d039e8071" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "189" + X-Request-Id: + - 967bce25-c8b2-4fba-b951-975071e4eec8 + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_AcSzjZJFamxNtScE + method: GET + response: + body: '{"ip_address":{"id":"ip_AcSzjZJFamxNtScE","address":"185.199.222.45","reverse_dns":"185-199-222-45.rdns.katapult.cloud","vip":false,"label":null,"address_with_mask":"185.199.222.45/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null},"allocation":null}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "567" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 13:38:43 GMT + Etag: + - W/"d267285e34915427200cc05d039e8071" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "187" + X-Request-Id: + - 544eff98-35ae-46f8-af79-76bdf1641beb + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_AcSzjZJFamxNtScE + method: GET + response: + body: '{"ip_address":{"id":"ip_AcSzjZJFamxNtScE","address":"185.199.222.45","reverse_dns":"185-199-222-45.rdns.katapult.cloud","vip":false,"label":null,"address_with_mask":"185.199.222.45/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null},"allocation":null}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "567" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 13:38:43 GMT + Etag: + - W/"d267285e34915427200cc05d039e8071" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "185" + X-Request-Id: + - cae53258-d695-44ae-8442-54ad479cdf79 + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_AcSzjZJFamxNtScE + method: GET + response: + body: '{"ip_address":{"id":"ip_AcSzjZJFamxNtScE","address":"185.199.222.45","reverse_dns":"185-199-222-45.rdns.katapult.cloud","vip":false,"label":null,"address_with_mask":"185.199.222.45/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null},"allocation":null}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "567" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 13:38:43 GMT + Etag: + - W/"d267285e34915427200cc05d039e8071" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "183" + X-Request-Id: + - c4cd387d-77a0-4227-a2e0-efb27e6b1d5f + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_AcSzjZJFamxNtScE + method: GET + response: + body: '{"ip_address":{"id":"ip_AcSzjZJFamxNtScE","address":"185.199.222.45","reverse_dns":"185-199-222-45.rdns.katapult.cloud","vip":false,"label":null,"address_with_mask":"185.199.222.45/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null},"allocation":null}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "567" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 13:38:43 GMT + Etag: + - W/"d267285e34915427200cc05d039e8071" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "182" + X-Request-Id: + - 0c137ee2-94e4-43db-a3b7-a723c2358958 + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_AcSzjZJFamxNtScE + method: DELETE + response: + body: '{}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "2" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 13:38:43 GMT + Etag: + - W/"44136fa355b3678a1146ad16f7e8649e" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "180" + X-Request-Id: + - 430a2ca3-9ccf-42c5-8b4b-bc3a4ba6df0d + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_AcSzjZJFamxNtScE + method: GET + response: + body: '{"error":{"code":"ip_address_not_found","description":"No IP addresses + were found matching any of the criteria provided in the arguments","detail":{}}}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - no-cache + Content-Length: + - "151" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 13:38:44 GMT + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Api-Schema: + - json-error + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "177" + X-Request-Id: + - 2cafd858-b910-4dfc-b38b-fb7494a5a210 + status: 404 Not Found + code: 404 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_AcSzjZJFamxNtScE + method: GET + response: + body: '{"error":{"code":"ip_address_not_found","description":"No IP addresses + were found matching any of the criteria provided in the arguments","detail":{}}}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - no-cache + Content-Length: + - "151" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 13:38:44 GMT + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Api-Schema: + - json-error + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "176" + X-Request-Id: + - 6f7ad3e7-5ae4-4ed7-a1cf-22fe75656c61 + status: 404 Not Found + code: 404 + duration: "" diff --git a/internal/v6provider/testdata/IP_ipv4.cassette.yaml b/internal/v6provider/testdata/IP_ipv4.cassette.yaml new file mode 100644 index 00000000..c579020b --- /dev/null +++ b/internal/v6provider/testdata/IP_ipv4.cassette.yaml @@ -0,0 +1,377 @@ +--- +version: 1 +interactions: +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/data_centers/_/default_network?data_center%5Bpermalink%5D=uk-lon-01 + method: GET + response: + body: '{"network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01"}}}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "181" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 12:53:29 GMT + Etag: + - W/"d60d47b2ba0b179327bb89a97b1c0e77" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "198" + X-Request-Id: + - 714bec50-2f72-4aa0-8016-7be67bf4b867 + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/data_centers/_/default_network?data_center%5Bpermalink%5D=uk-lon-01 + method: GET + response: + body: '{"network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01"}}}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "181" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 12:53:30 GMT + Etag: + - W/"d60d47b2ba0b179327bb89a97b1c0e77" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "194" + X-Request-Id: + - cb156507-4706-48e8-b4d0-4dbadabc7cb8 + status: 200 OK + code: 200 + duration: "" +- request: + body: | + {"organization":{"sub_domain":"terraform-acc-test"},"network":{"id":"netw_gVRkZdSKczfNg34P"},"version":"ipv4"} + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/organizations/_/ip_addresses + method: POST + response: + body: '{"ip_address":{"id":"ip_AcSzjZJFamxNtScE","address":"185.199.222.45","reverse_dns":"185-199-222-45.rdns.katapult.cloud","vip":false,"label":null,"address_with_mask":"185.199.222.45/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null}}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "549" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 12:53:30 GMT + Etag: + - W/"da6e501e679e64075c688d63392b2251" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "187" + X-Request-Id: + - 65fa4f17-4f7b-48c1-847a-ce922f99871c + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_AcSzjZJFamxNtScE + method: GET + response: + body: '{"ip_address":{"id":"ip_AcSzjZJFamxNtScE","address":"185.199.222.45","reverse_dns":"185-199-222-45.rdns.katapult.cloud","vip":false,"label":null,"address_with_mask":"185.199.222.45/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null},"allocation":null}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "567" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 12:53:30 GMT + Etag: + - W/"d267285e34915427200cc05d039e8071" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "177" + X-Request-Id: + - a8099edf-81d2-4ea4-9f53-1cf22382daf9 + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_AcSzjZJFamxNtScE + method: GET + response: + body: '{"ip_address":{"id":"ip_AcSzjZJFamxNtScE","address":"185.199.222.45","reverse_dns":"185-199-222-45.rdns.katapult.cloud","vip":false,"label":null,"address_with_mask":"185.199.222.45/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null},"allocation":null}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "567" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 12:53:30 GMT + Etag: + - W/"d267285e34915427200cc05d039e8071" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "176" + X-Request-Id: + - 6e9fc084-2e5e-4365-8daf-1ce45d011b23 + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_AcSzjZJFamxNtScE + method: GET + response: + body: '{"ip_address":{"id":"ip_AcSzjZJFamxNtScE","address":"185.199.222.45","reverse_dns":"185-199-222-45.rdns.katapult.cloud","vip":false,"label":null,"address_with_mask":"185.199.222.45/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null},"allocation":null}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "567" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 12:53:30 GMT + Etag: + - W/"d267285e34915427200cc05d039e8071" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "173" + X-Request-Id: + - 6cc0e239-9103-44d9-8b4a-2997c4f2a2ec + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_AcSzjZJFamxNtScE + method: GET + response: + body: '{"ip_address":{"id":"ip_AcSzjZJFamxNtScE","address":"185.199.222.45","reverse_dns":"185-199-222-45.rdns.katapult.cloud","vip":false,"label":null,"address_with_mask":"185.199.222.45/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null},"allocation":null}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "567" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 12:53:31 GMT + Etag: + - W/"d267285e34915427200cc05d039e8071" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "167" + X-Request-Id: + - 22ec6cdc-3428-4435-a3c4-0d51a01ec701 + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_AcSzjZJFamxNtScE + method: DELETE + response: + body: '{}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "2" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 12:53:31 GMT + Etag: + - W/"44136fa355b3678a1146ad16f7e8649e" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "161" + X-Request-Id: + - 63084424-53de-4f8d-b171-60edc52a0fb5 + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_AcSzjZJFamxNtScE + method: GET + response: + body: '{"error":{"code":"ip_address_not_found","description":"No IP addresses + were found matching any of the criteria provided in the arguments","detail":{}}}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - no-cache + Content-Length: + - "151" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 12:53:31 GMT + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Api-Schema: + - json-error + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "159" + X-Request-Id: + - 43bbee3b-d977-455b-a47e-b448cd197439 + status: 404 Not Found + code: 404 + duration: "" diff --git a/internal/v6provider/testdata/IP_ipv6.cassette.yaml b/internal/v6provider/testdata/IP_ipv6.cassette.yaml new file mode 100644 index 00000000..f41a9d94 --- /dev/null +++ b/internal/v6provider/testdata/IP_ipv6.cassette.yaml @@ -0,0 +1,377 @@ +--- +version: 1 +interactions: +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/data_centers/_/default_network?data_center%5Bpermalink%5D=uk-lon-01 + method: GET + response: + body: '{"network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01"}}}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "181" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 12:53:29 GMT + Etag: + - W/"d60d47b2ba0b179327bb89a97b1c0e77" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "197" + X-Request-Id: + - a9184162-3a1e-4c9a-b5c5-2dc6b90e08b6 + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/data_centers/_/default_network?data_center%5Bpermalink%5D=uk-lon-01 + method: GET + response: + body: '{"network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01"}}}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "181" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 12:53:30 GMT + Etag: + - W/"d60d47b2ba0b179327bb89a97b1c0e77" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "189" + X-Request-Id: + - a1c36b75-4711-44fb-9f93-ee16f70a7abf + status: 200 OK + code: 200 + duration: "" +- request: + body: | + {"organization":{"sub_domain":"terraform-acc-test"},"network":{"id":"netw_gVRkZdSKczfNg34P"},"version":"ipv6"} + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/organizations/_/ip_addresses + method: POST + response: + body: '{"ip_address":{"id":"ip_139MxwIsMfApqiYz","address":"2a03:2800:500::3c5","reverse_dns":"2a03-2800-500--3c5.rdns.k.io","vip":false,"label":null,"address_with_mask":"2a03:2800:500::3c5/48","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null}}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "551" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 12:53:30 GMT + Etag: + - W/"430c01f636fa09094310f39047c392e3" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "184" + X-Request-Id: + - a5a8509c-f71f-4c5c-838a-6807bad09222 + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_139MxwIsMfApqiYz + method: GET + response: + body: '{"ip_address":{"id":"ip_139MxwIsMfApqiYz","address":"2a03:2800:500::3c5","reverse_dns":"2a03-2800-500--3c5.rdns.k.io","vip":false,"label":null,"address_with_mask":"2a03:2800:500::3c5/48","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null},"allocation":null}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "569" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 12:53:30 GMT + Etag: + - W/"034d7dc9f61b6e2fe67301bfcb09ded3" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "180" + X-Request-Id: + - 74aeb5d2-295d-4197-aa7a-7571c0b3d516 + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_139MxwIsMfApqiYz + method: GET + response: + body: '{"ip_address":{"id":"ip_139MxwIsMfApqiYz","address":"2a03:2800:500::3c5","reverse_dns":"2a03-2800-500--3c5.rdns.k.io","vip":false,"label":null,"address_with_mask":"2a03:2800:500::3c5/48","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null},"allocation":null}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "569" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 12:53:30 GMT + Etag: + - W/"034d7dc9f61b6e2fe67301bfcb09ded3" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "178" + X-Request-Id: + - 6518b6a0-034e-48e7-a351-bae1bb9e05c4 + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_139MxwIsMfApqiYz + method: GET + response: + body: '{"ip_address":{"id":"ip_139MxwIsMfApqiYz","address":"2a03:2800:500::3c5","reverse_dns":"2a03-2800-500--3c5.rdns.k.io","vip":false,"label":null,"address_with_mask":"2a03:2800:500::3c5/48","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null},"allocation":null}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "569" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 12:53:30 GMT + Etag: + - W/"034d7dc9f61b6e2fe67301bfcb09ded3" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "175" + X-Request-Id: + - 470a2c17-1655-43e8-8381-9507825460fd + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_139MxwIsMfApqiYz + method: GET + response: + body: '{"ip_address":{"id":"ip_139MxwIsMfApqiYz","address":"2a03:2800:500::3c5","reverse_dns":"2a03-2800-500--3c5.rdns.k.io","vip":false,"label":null,"address_with_mask":"2a03:2800:500::3c5/48","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null},"allocation":null}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "569" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 12:53:30 GMT + Etag: + - W/"034d7dc9f61b6e2fe67301bfcb09ded3" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "170" + X-Request-Id: + - ca735fcc-7307-48e7-a44b-4c9af7df17d5 + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_139MxwIsMfApqiYz + method: DELETE + response: + body: '{}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "2" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 12:53:31 GMT + Etag: + - W/"44136fa355b3678a1146ad16f7e8649e" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "164" + X-Request-Id: + - b6d02d19-9ff8-47b1-a390-2994c5e23727 + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_139MxwIsMfApqiYz + method: GET + response: + body: '{"error":{"code":"ip_address_not_found","description":"No IP addresses + were found matching any of the criteria provided in the arguments","detail":{}}}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - no-cache + Content-Length: + - "151" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 12:53:31 GMT + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Api-Schema: + - json-error + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "162" + X-Request-Id: + - bfaeb43e-5a79-4952-a28b-d083362887e9 + status: 404 Not Found + code: 404 + duration: "" diff --git a/internal/v6provider/testdata/IP_minimal.cassette.yaml b/internal/v6provider/testdata/IP_minimal.cassette.yaml new file mode 100644 index 00000000..af06bc9d --- /dev/null +++ b/internal/v6provider/testdata/IP_minimal.cassette.yaml @@ -0,0 +1,377 @@ +--- +version: 1 +interactions: +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/data_centers/_/default_network?data_center%5Bpermalink%5D=uk-lon-01 + method: GET + response: + body: '{"network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01"}}}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "181" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 12:53:29 GMT + Etag: + - W/"d60d47b2ba0b179327bb89a97b1c0e77" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "199" + X-Request-Id: + - 575a5f38-1ba7-464a-98c4-21a0448cbd24 + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/data_centers/_/default_network?data_center%5Bpermalink%5D=uk-lon-01 + method: GET + response: + body: '{"network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01"}}}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "181" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 12:53:30 GMT + Etag: + - W/"d60d47b2ba0b179327bb89a97b1c0e77" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "192" + X-Request-Id: + - af2630cd-3bf5-4e57-9525-bd1d216c1411 + status: 200 OK + code: 200 + duration: "" +- request: + body: | + {"organization":{"sub_domain":"terraform-acc-test"},"network":{"id":"netw_gVRkZdSKczfNg34P"},"version":"ipv4"} + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/organizations/_/ip_addresses + method: POST + response: + body: '{"ip_address":{"id":"ip_KXmqJnl1mLikzNjD","address":"185.199.222.189","reverse_dns":"185-199-222-189.rdns.katapult.cloud","vip":false,"label":null,"address_with_mask":"185.199.222.189/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null}}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "552" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 12:53:30 GMT + Etag: + - W/"cb0dfe2cc7fbf5fd6b92212d22b5517a" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "185" + X-Request-Id: + - 237ba4bf-0014-4a30-9808-9d3cb013a082 + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_KXmqJnl1mLikzNjD + method: GET + response: + body: '{"ip_address":{"id":"ip_KXmqJnl1mLikzNjD","address":"185.199.222.189","reverse_dns":"185-199-222-189.rdns.katapult.cloud","vip":false,"label":null,"address_with_mask":"185.199.222.189/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null},"allocation":null}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "570" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 12:53:30 GMT + Etag: + - W/"6892b29793fda99aee73f676d21e7078" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "172" + X-Request-Id: + - a5fe2ccb-4932-4141-8d77-11c1237cd018 + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_KXmqJnl1mLikzNjD + method: GET + response: + body: '{"ip_address":{"id":"ip_KXmqJnl1mLikzNjD","address":"185.199.222.189","reverse_dns":"185-199-222-189.rdns.katapult.cloud","vip":false,"label":null,"address_with_mask":"185.199.222.189/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null},"allocation":null}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "570" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 12:53:30 GMT + Etag: + - W/"6892b29793fda99aee73f676d21e7078" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "169" + X-Request-Id: + - 0ea5d51b-3f3c-4a78-baa6-cb4e016e781f + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_KXmqJnl1mLikzNjD + method: GET + response: + body: '{"ip_address":{"id":"ip_KXmqJnl1mLikzNjD","address":"185.199.222.189","reverse_dns":"185-199-222-189.rdns.katapult.cloud","vip":false,"label":null,"address_with_mask":"185.199.222.189/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null},"allocation":null}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "570" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 12:53:31 GMT + Etag: + - W/"6892b29793fda99aee73f676d21e7078" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "165" + X-Request-Id: + - 887b0772-95e7-45ce-b855-3a84d4e6f180 + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_KXmqJnl1mLikzNjD + method: GET + response: + body: '{"ip_address":{"id":"ip_KXmqJnl1mLikzNjD","address":"185.199.222.189","reverse_dns":"185-199-222-189.rdns.katapult.cloud","vip":false,"label":null,"address_with_mask":"185.199.222.189/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null},"allocation":null}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "570" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 12:53:31 GMT + Etag: + - W/"6892b29793fda99aee73f676d21e7078" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "158" + X-Request-Id: + - 5ea547cf-c670-4c72-b53e-65514c7fd541 + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_KXmqJnl1mLikzNjD + method: DELETE + response: + body: '{}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "2" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 12:53:31 GMT + Etag: + - W/"44136fa355b3678a1146ad16f7e8649e" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "157" + X-Request-Id: + - d4f013e9-c1ec-4be4-b438-23c1d5331d40 + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_KXmqJnl1mLikzNjD + method: GET + response: + body: '{"error":{"code":"ip_address_not_found","description":"No IP addresses + were found matching any of the criteria provided in the arguments","detail":{}}}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - no-cache + Content-Length: + - "151" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 12:53:31 GMT + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Api-Schema: + - json-error + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "155" + X-Request-Id: + - c62da17e-ea7c-4d39-bc7d-e6665c53f54a + status: 404 Not Found + code: 404 + duration: "" diff --git a/internal/v6provider/testdata/IP_update.cassette.yaml b/internal/v6provider/testdata/IP_update.cassette.yaml new file mode 100644 index 00000000..b4881ee8 --- /dev/null +++ b/internal/v6provider/testdata/IP_update.cassette.yaml @@ -0,0 +1,1174 @@ +--- +version: 1 +interactions: +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/data_centers/_/default_network?data_center%5Bpermalink%5D=uk-lon-01 + method: GET + response: + body: '{"network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01"}}}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "181" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 13:48:23 GMT + Etag: + - W/"d60d47b2ba0b179327bb89a97b1c0e77" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "199" + X-Request-Id: + - 2dc7d19b-e307-47b6-8830-d8fbdfdc62ce + status: 200 OK + code: 200 + duration: "" +- request: + body: | + {"organization":{"sub_domain":"terraform-acc-test"},"network":{"id":"netw_gVRkZdSKczfNg34P"},"version":"ipv4"} + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/organizations/_/ip_addresses + method: POST + response: + body: '{"ip_address":{"id":"ip_KXmqJnl1mLikzNjD","address":"185.199.222.189","reverse_dns":"185-199-222-189.rdns.katapult.cloud","vip":false,"label":null,"address_with_mask":"185.199.222.189/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null}}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "552" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 13:48:23 GMT + Etag: + - W/"cb0dfe2cc7fbf5fd6b92212d22b5517a" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "198" + X-Request-Id: + - 72fb4bcd-22fc-4368-bba5-c0859e9668f9 + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_KXmqJnl1mLikzNjD + method: GET + response: + body: '{"ip_address":{"id":"ip_KXmqJnl1mLikzNjD","address":"185.199.222.189","reverse_dns":"185-199-222-189.rdns.katapult.cloud","vip":false,"label":null,"address_with_mask":"185.199.222.189/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null},"allocation":null}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "570" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 13:48:23 GMT + Etag: + - W/"6892b29793fda99aee73f676d21e7078" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "197" + X-Request-Id: + - e8d943be-0e75-42de-994c-03a41053e61f + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_KXmqJnl1mLikzNjD + method: GET + response: + body: '{"ip_address":{"id":"ip_KXmqJnl1mLikzNjD","address":"185.199.222.189","reverse_dns":"185-199-222-189.rdns.katapult.cloud","vip":false,"label":null,"address_with_mask":"185.199.222.189/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null},"allocation":null}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "570" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 13:48:23 GMT + Etag: + - W/"6892b29793fda99aee73f676d21e7078" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "196" + X-Request-Id: + - 18219121-194c-4465-8295-d21f978325af + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_KXmqJnl1mLikzNjD + method: GET + response: + body: '{"ip_address":{"id":"ip_KXmqJnl1mLikzNjD","address":"185.199.222.189","reverse_dns":"185-199-222-189.rdns.katapult.cloud","vip":false,"label":null,"address_with_mask":"185.199.222.189/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null},"allocation":null}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "570" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 13:48:23 GMT + Etag: + - W/"6892b29793fda99aee73f676d21e7078" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "195" + X-Request-Id: + - fc269fd1-e340-403b-bb6a-75fd886f74ce + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_KXmqJnl1mLikzNjD + method: GET + response: + body: '{"ip_address":{"id":"ip_KXmqJnl1mLikzNjD","address":"185.199.222.189","reverse_dns":"185-199-222-189.rdns.katapult.cloud","vip":false,"label":null,"address_with_mask":"185.199.222.189/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null},"allocation":null}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "570" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 13:48:23 GMT + Etag: + - W/"6892b29793fda99aee73f676d21e7078" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "194" + X-Request-Id: + - c05fdb14-042b-4c7b-8819-a63038e7bfb3 + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_KXmqJnl1mLikzNjD + method: DELETE + response: + body: '{}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "2" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 13:48:24 GMT + Etag: + - W/"44136fa355b3678a1146ad16f7e8649e" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "193" + X-Request-Id: + - 1762ad4d-830b-44f9-80d5-a96075afee44 + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/data_centers/_/default_network?data_center%5Bpermalink%5D=uk-lon-01 + method: GET + response: + body: '{"network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01"}}}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "181" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 13:48:24 GMT + Etag: + - W/"d60d47b2ba0b179327bb89a97b1c0e77" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "192" + X-Request-Id: + - 63245773-388e-4fc5-8070-735bbae26339 + status: 200 OK + code: 200 + duration: "" +- request: + body: | + {"organization":{"sub_domain":"terraform-acc-test"},"network":{"id":"netw_gVRkZdSKczfNg34P"},"version":"ipv4","vip":true,"label":"vip-yes"} + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/organizations/_/ip_addresses + method: POST + response: + body: '{"ip_address":{"id":"ip_AcSzjZJFamxNtScE","address":"185.199.222.45","reverse_dns":"185-199-222-45.rdns.katapult.cloud","vip":true,"label":"vip-yes","address_with_mask":"185.199.222.45/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null}}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "553" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 13:48:24 GMT + Etag: + - W/"65fa74103c4821784c6089f3a85b0e67" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "191" + X-Request-Id: + - 6f2016b5-3446-4d7a-9b3c-4130f9a5ec83 + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_AcSzjZJFamxNtScE + method: GET + response: + body: '{"ip_address":{"id":"ip_AcSzjZJFamxNtScE","address":"185.199.222.45","reverse_dns":"185-199-222-45.rdns.katapult.cloud","vip":true,"label":"vip-yes","address_with_mask":"185.199.222.45/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null},"allocation":null}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "571" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 13:48:24 GMT + Etag: + - W/"f34d9cb0bf40a174bb523d96409c9272" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "190" + X-Request-Id: + - 91cfe870-bcca-45a6-852c-3cf0f7d51498 + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_AcSzjZJFamxNtScE + method: GET + response: + body: '{"ip_address":{"id":"ip_AcSzjZJFamxNtScE","address":"185.199.222.45","reverse_dns":"185-199-222-45.rdns.katapult.cloud","vip":true,"label":"vip-yes","address_with_mask":"185.199.222.45/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null},"allocation":null}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "571" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 13:48:24 GMT + Etag: + - W/"f34d9cb0bf40a174bb523d96409c9272" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "189" + X-Request-Id: + - 9bf495be-1a9b-499d-955d-57d6017d1594 + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_AcSzjZJFamxNtScE + method: GET + response: + body: '{"ip_address":{"id":"ip_AcSzjZJFamxNtScE","address":"185.199.222.45","reverse_dns":"185-199-222-45.rdns.katapult.cloud","vip":true,"label":"vip-yes","address_with_mask":"185.199.222.45/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null},"allocation":null}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "571" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 13:48:24 GMT + Etag: + - W/"f34d9cb0bf40a174bb523d96409c9272" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "188" + X-Request-Id: + - 380b5aec-7576-4c0d-bb23-4daa592c6691 + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_AcSzjZJFamxNtScE + method: GET + response: + body: '{"ip_address":{"id":"ip_AcSzjZJFamxNtScE","address":"185.199.222.45","reverse_dns":"185-199-222-45.rdns.katapult.cloud","vip":true,"label":"vip-yes","address_with_mask":"185.199.222.45/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null},"allocation":null}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "571" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 13:48:24 GMT + Etag: + - W/"f34d9cb0bf40a174bb523d96409c9272" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "187" + X-Request-Id: + - a63942ca-d07d-4de4-ae0f-d41d8be77f77 + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_AcSzjZJFamxNtScE + method: DELETE + response: + body: '{}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "2" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 13:48:24 GMT + Etag: + - W/"44136fa355b3678a1146ad16f7e8649e" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "186" + X-Request-Id: + - fbef11c2-9409-4a2a-9a43-4d771f24a46b + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/data_centers/_/default_network?data_center%5Bpermalink%5D=uk-lon-01 + method: GET + response: + body: '{"network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01"}}}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "181" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 13:48:24 GMT + Etag: + - W/"d60d47b2ba0b179327bb89a97b1c0e77" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "185" + X-Request-Id: + - 7625e96e-4b04-44c8-b512-1fa6b152f8aa + status: 200 OK + code: 200 + duration: "" +- request: + body: | + {"organization":{"sub_domain":"terraform-acc-test"},"network":{"id":"netw_gVRkZdSKczfNg34P"},"version":"ipv4","vip":true,"label":"vip-oh-yes"} + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/organizations/_/ip_addresses + method: POST + response: + body: '{"ip_address":{"id":"ip_AcSzjZJFamxNtScE","address":"185.199.222.45","reverse_dns":"185-199-222-45.rdns.katapult.cloud","vip":true,"label":"vip-oh-yes","address_with_mask":"185.199.222.45/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null}}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "556" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 13:48:25 GMT + Etag: + - W/"7aa3f2ee4c9e283f69e33ce8704f3fee" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "184" + X-Request-Id: + - 9cbb8dff-733c-4a6c-896d-538a1de8db73 + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_AcSzjZJFamxNtScE + method: GET + response: + body: '{"ip_address":{"id":"ip_AcSzjZJFamxNtScE","address":"185.199.222.45","reverse_dns":"185-199-222-45.rdns.katapult.cloud","vip":true,"label":"vip-oh-yes","address_with_mask":"185.199.222.45/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null},"allocation":null}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "574" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 13:48:25 GMT + Etag: + - W/"111d6b94ad29b7e4d15af23a665f7bf8" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "183" + X-Request-Id: + - 8e732595-ae72-460c-b3c1-2296a746ae20 + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_AcSzjZJFamxNtScE + method: GET + response: + body: '{"ip_address":{"id":"ip_AcSzjZJFamxNtScE","address":"185.199.222.45","reverse_dns":"185-199-222-45.rdns.katapult.cloud","vip":true,"label":"vip-oh-yes","address_with_mask":"185.199.222.45/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null},"allocation":null}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "574" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 13:48:25 GMT + Etag: + - W/"111d6b94ad29b7e4d15af23a665f7bf8" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "182" + X-Request-Id: + - 58f38431-8cb8-4be8-8018-433058843f52 + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_AcSzjZJFamxNtScE + method: GET + response: + body: '{"ip_address":{"id":"ip_AcSzjZJFamxNtScE","address":"185.199.222.45","reverse_dns":"185-199-222-45.rdns.katapult.cloud","vip":true,"label":"vip-oh-yes","address_with_mask":"185.199.222.45/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null},"allocation":null}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "574" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 13:48:25 GMT + Etag: + - W/"111d6b94ad29b7e4d15af23a665f7bf8" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "181" + X-Request-Id: + - 43589497-79fd-40e0-982e-b7b662edb929 + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_AcSzjZJFamxNtScE + method: GET + response: + body: '{"ip_address":{"id":"ip_AcSzjZJFamxNtScE","address":"185.199.222.45","reverse_dns":"185-199-222-45.rdns.katapult.cloud","vip":true,"label":"vip-oh-yes","address_with_mask":"185.199.222.45/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null},"allocation":null}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "574" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 13:48:25 GMT + Etag: + - W/"111d6b94ad29b7e4d15af23a665f7bf8" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "180" + X-Request-Id: + - be1e32e3-5172-4bec-816f-cbf676fd92ba + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_AcSzjZJFamxNtScE + method: DELETE + response: + body: '{}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "2" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 13:48:25 GMT + Etag: + - W/"44136fa355b3678a1146ad16f7e8649e" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "179" + X-Request-Id: + - cffde211-3bd9-43ff-81d6-3f64a2c77410 + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/data_centers/_/default_network?data_center%5Bpermalink%5D=uk-lon-01 + method: GET + response: + body: '{"network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01"}}}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "181" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 13:48:25 GMT + Etag: + - W/"d60d47b2ba0b179327bb89a97b1c0e77" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "178" + X-Request-Id: + - 106b9374-e4a1-4bc0-9402-3fd4e47fbfd2 + status: 200 OK + code: 200 + duration: "" +- request: + body: | + {"organization":{"sub_domain":"terraform-acc-test"},"network":{"id":"netw_gVRkZdSKczfNg34P"},"version":"ipv4"} + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/organizations/_/ip_addresses + method: POST + response: + body: '{"ip_address":{"id":"ip_AcSzjZJFamxNtScE","address":"185.199.222.45","reverse_dns":"185-199-222-45.rdns.katapult.cloud","vip":false,"label":null,"address_with_mask":"185.199.222.45/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null}}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "549" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 13:48:25 GMT + Etag: + - W/"da6e501e679e64075c688d63392b2251" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "177" + X-Request-Id: + - 8a58fdb3-0695-4cfc-90e7-ca5919b2490d + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_AcSzjZJFamxNtScE + method: GET + response: + body: '{"ip_address":{"id":"ip_AcSzjZJFamxNtScE","address":"185.199.222.45","reverse_dns":"185-199-222-45.rdns.katapult.cloud","vip":false,"label":null,"address_with_mask":"185.199.222.45/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null},"allocation":null}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "567" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 13:48:25 GMT + Etag: + - W/"d267285e34915427200cc05d039e8071" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "176" + X-Request-Id: + - f94f4bb8-d072-4ba7-99de-2178d71fc313 + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_AcSzjZJFamxNtScE + method: GET + response: + body: '{"ip_address":{"id":"ip_AcSzjZJFamxNtScE","address":"185.199.222.45","reverse_dns":"185-199-222-45.rdns.katapult.cloud","vip":false,"label":null,"address_with_mask":"185.199.222.45/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null},"allocation":null}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "567" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 13:48:25 GMT + Etag: + - W/"d267285e34915427200cc05d039e8071" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "175" + X-Request-Id: + - 46db66d5-1e79-4feb-a0fb-0b2125d1a6b4 + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_AcSzjZJFamxNtScE + method: GET + response: + body: '{"ip_address":{"id":"ip_AcSzjZJFamxNtScE","address":"185.199.222.45","reverse_dns":"185-199-222-45.rdns.katapult.cloud","vip":false,"label":null,"address_with_mask":"185.199.222.45/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null},"allocation":null}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "567" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 13:48:26 GMT + Etag: + - W/"d267285e34915427200cc05d039e8071" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "174" + X-Request-Id: + - fa4e6f42-5ad1-4836-a8b5-e18d29d72281 + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_AcSzjZJFamxNtScE + method: DELETE + response: + body: '{}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "2" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 13:48:26 GMT + Etag: + - W/"44136fa355b3678a1146ad16f7e8649e" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "173" + X-Request-Id: + - 357b8e38-f902-4d9b-b8c7-27e1109b85d0 + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_AcSzjZJFamxNtScE + method: GET + response: + body: '{"error":{"code":"ip_address_not_found","description":"No IP addresses + were found matching any of the criteria provided in the arguments","detail":{}}}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - no-cache + Content-Length: + - "151" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 13:48:26 GMT + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Api-Schema: + - json-error + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "172" + X-Request-Id: + - 85c1c381-d77b-4ea2-bd7d-81bdf2ac8635 + status: 404 Not Found + code: 404 + duration: "" diff --git a/internal/v6provider/testdata/IP_vip.cassette.rand_id b/internal/v6provider/testdata/IP_vip.cassette.rand_id new file mode 100644 index 00000000..b0c30697 --- /dev/null +++ b/internal/v6provider/testdata/IP_vip.cassette.rand_id @@ -0,0 +1 @@ +oZ7bfWTPwrLz \ No newline at end of file diff --git a/internal/v6provider/testdata/IP_vip.cassette.yaml b/internal/v6provider/testdata/IP_vip.cassette.yaml new file mode 100644 index 00000000..a0d30771 --- /dev/null +++ b/internal/v6provider/testdata/IP_vip.cassette.yaml @@ -0,0 +1,337 @@ +--- +version: 1 +interactions: +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/data_centers/_/default_network?data_center%5Bpermalink%5D=uk-lon-01 + method: GET + response: + body: '{"network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01"}}}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "181" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 12:53:30 GMT + Etag: + - W/"d60d47b2ba0b179327bb89a97b1c0e77" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "190" + X-Request-Id: + - fbff1797-504f-4e3e-b173-eba9522bd6a5 + status: 200 OK + code: 200 + duration: "" +- request: + body: | + {"organization":{"sub_domain":"terraform-acc-test"},"network":{"id":"netw_gVRkZdSKczfNg34P"},"version":"ipv4","vip":true,"label":"tf-acc-test-vip-oZ7bfWTPwrLz"} + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/organizations/_/ip_addresses + method: POST + response: + body: '{"ip_address":{"id":"ip_l2q3LlblqoZCf4qB","address":"185.199.222.18","reverse_dns":"185-199-222-18.rdns.katapult.cloud","vip":true,"label":"tf-acc-test-vip-oZ7bfWTPwrLz","address_with_mask":"185.199.222.18/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null}}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "574" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 12:53:31 GMT + Etag: + - W/"cfa78994060e3675c46c977079e5ea4c" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "183" + X-Request-Id: + - 30c03ca9-48d4-4420-8993-778b0fa7ee4a + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_l2q3LlblqoZCf4qB + method: GET + response: + body: '{"ip_address":{"id":"ip_l2q3LlblqoZCf4qB","address":"185.199.222.18","reverse_dns":"185-199-222-18.rdns.katapult.cloud","vip":true,"label":"tf-acc-test-vip-oZ7bfWTPwrLz","address_with_mask":"185.199.222.18/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null},"allocation":null}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "592" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 12:53:31 GMT + Etag: + - W/"cf4b456356a493c2561f06ddd5c84072" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "166" + X-Request-Id: + - b9e0b8dd-a860-4ca0-a4b7-7bf8b5d0c4bb + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_l2q3LlblqoZCf4qB + method: GET + response: + body: '{"ip_address":{"id":"ip_l2q3LlblqoZCf4qB","address":"185.199.222.18","reverse_dns":"185-199-222-18.rdns.katapult.cloud","vip":true,"label":"tf-acc-test-vip-oZ7bfWTPwrLz","address_with_mask":"185.199.222.18/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null},"allocation":null}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "592" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 12:53:31 GMT + Etag: + - W/"cf4b456356a493c2561f06ddd5c84072" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "163" + X-Request-Id: + - def1c271-70a6-4c5c-bbaf-0ae0187f9ae7 + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_l2q3LlblqoZCf4qB + method: GET + response: + body: '{"ip_address":{"id":"ip_l2q3LlblqoZCf4qB","address":"185.199.222.18","reverse_dns":"185-199-222-18.rdns.katapult.cloud","vip":true,"label":"tf-acc-test-vip-oZ7bfWTPwrLz","address_with_mask":"185.199.222.18/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null},"allocation":null}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "592" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 12:53:31 GMT + Etag: + - W/"cf4b456356a493c2561f06ddd5c84072" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "160" + X-Request-Id: + - 286da6bb-cb82-4c32-b3f0-bdacb12faab3 + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_l2q3LlblqoZCf4qB + method: GET + response: + body: '{"ip_address":{"id":"ip_l2q3LlblqoZCf4qB","address":"185.199.222.18","reverse_dns":"185-199-222-18.rdns.katapult.cloud","vip":true,"label":"tf-acc-test-vip-oZ7bfWTPwrLz","address_with_mask":"185.199.222.18/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null},"allocation":null}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "592" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 12:53:31 GMT + Etag: + - W/"cf4b456356a493c2561f06ddd5c84072" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "156" + X-Request-Id: + - 7602828a-1709-44a1-94c9-e0b3c5e9d562 + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_l2q3LlblqoZCf4qB + method: DELETE + response: + body: '{}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "2" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 12:53:31 GMT + Etag: + - W/"44136fa355b3678a1146ad16f7e8649e" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "154" + X-Request-Id: + - feab9654-b726-4b2d-97b3-505142abb857 + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_l2q3LlblqoZCf4qB + method: GET + response: + body: '{"error":{"code":"ip_address_not_found","description":"No IP addresses + were found matching any of the criteria provided in the arguments","detail":{}}}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - no-cache + Content-Length: + - "151" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 12:53:31 GMT + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Api-Schema: + - json-error + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "153" + X-Request-Id: + - 008810db-2787-42b7-8bfc-ba15e6741576 + status: 404 Not Found + code: 404 + duration: "" diff --git a/internal/v6provider/testdata/IP_vip_without_label.cassette.yaml b/internal/v6provider/testdata/IP_vip_without_label.cassette.yaml new file mode 100644 index 00000000..7ae63ab5 --- /dev/null +++ b/internal/v6provider/testdata/IP_vip_without_label.cassette.yaml @@ -0,0 +1,88 @@ +--- +version: 1 +interactions: +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/data_centers/_/default_network?data_center%5Bpermalink%5D=uk-lon-01 + method: GET + response: + body: '{"network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01"}}}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "181" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 12:53:30 GMT + Etag: + - W/"d60d47b2ba0b179327bb89a97b1c0e77" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "193" + X-Request-Id: + - d5c61e49-8680-4f61-a199-d9f6eddd3c5b + status: 200 OK + code: 200 + duration: "" +- request: + body: | + {"organization":{"sub_domain":"terraform-acc-test"},"network":{"id":"netw_gVRkZdSKczfNg34P"},"version":"ipv4","vip":true} + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/organizations/_/ip_addresses + method: POST + response: + body: '{"error":{"code":"validation_error","description":"A validation error occurred + with the object that was being created/updated/deleted","detail":{"errors":["Label + can''t be blank"]}}}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - no-cache + Content-Length: + - "181" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 12:53:30 GMT + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Api-Schema: + - json-error + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "186" + X-Request-Id: + - 7dfe10fb-feeb-48d0-8615-d37e6920a888 + status: 422 Unprocessable Entity + code: 422 + duration: "" diff --git a/internal/v6provider/testdata/IP_with_network_id.cassette.yaml b/internal/v6provider/testdata/IP_with_network_id.cassette.yaml new file mode 100644 index 00000000..8bef08d9 --- /dev/null +++ b/internal/v6provider/testdata/IP_with_network_id.cassette.yaml @@ -0,0 +1,337 @@ +--- +version: 1 +interactions: +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/data_centers/_/default_network?data_center%5Bpermalink%5D=uk-lon-01 + method: GET + response: + body: '{"network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01"}}}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "181" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 12:53:29 GMT + Etag: + - W/"d60d47b2ba0b179327bb89a97b1c0e77" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "196" + X-Request-Id: + - ac1c087a-46c0-4780-8018-0058f071a739 + status: 200 OK + code: 200 + duration: "" +- request: + body: | + {"organization":{"sub_domain":"terraform-acc-test"},"network":{"id":"netw_gVRkZdSKczfNg34P"},"version":"ipv4"} + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/organizations/_/ip_addresses + method: POST + response: + body: '{"ip_address":{"id":"ip_3Mc6zF0VP1zK9Z7n","address":"185.199.222.21","reverse_dns":"185-199-222-21.rdns.katapult.cloud","vip":false,"label":null,"address_with_mask":"185.199.222.21/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null}}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "549" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 12:53:30 GMT + Etag: + - W/"3800ced61b87a06fdc1ed4f888deb861" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "191" + X-Request-Id: + - 3ec0dcd1-457a-4153-bda4-756183b1d3c7 + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_3Mc6zF0VP1zK9Z7n + method: GET + response: + body: '{"ip_address":{"id":"ip_3Mc6zF0VP1zK9Z7n","address":"185.199.222.21","reverse_dns":"185-199-222-21.rdns.katapult.cloud","vip":false,"label":null,"address_with_mask":"185.199.222.21/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null},"allocation":null}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "567" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 12:53:30 GMT + Etag: + - W/"d73e9de6162e4a6972c8f55598b5f968" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "182" + X-Request-Id: + - 526ddfe0-159f-4c3b-9431-19357ac2f008 + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_3Mc6zF0VP1zK9Z7n + method: GET + response: + body: '{"ip_address":{"id":"ip_3Mc6zF0VP1zK9Z7n","address":"185.199.222.21","reverse_dns":"185-199-222-21.rdns.katapult.cloud","vip":false,"label":null,"address_with_mask":"185.199.222.21/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null},"allocation":null}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "567" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 12:53:30 GMT + Etag: + - W/"d73e9de6162e4a6972c8f55598b5f968" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "181" + X-Request-Id: + - eed00384-04b1-4503-8e1f-a31efb3bc902 + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_3Mc6zF0VP1zK9Z7n + method: GET + response: + body: '{"ip_address":{"id":"ip_3Mc6zF0VP1zK9Z7n","address":"185.199.222.21","reverse_dns":"185-199-222-21.rdns.katapult.cloud","vip":false,"label":null,"address_with_mask":"185.199.222.21/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null},"allocation":null}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "567" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 12:53:30 GMT + Etag: + - W/"d73e9de6162e4a6972c8f55598b5f968" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "179" + X-Request-Id: + - 006ddce6-4f5a-46ee-8851-1901249eb805 + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_3Mc6zF0VP1zK9Z7n + method: GET + response: + body: '{"ip_address":{"id":"ip_3Mc6zF0VP1zK9Z7n","address":"185.199.222.21","reverse_dns":"185-199-222-21.rdns.katapult.cloud","vip":false,"label":null,"address_with_mask":"185.199.222.21/24","network":{"id":"netw_gVRkZdSKczfNg34P","name":"Public + Network","permalink":"uk-lon-01-public","data_center":{"id":"loc_UUhPmoCbpic6UX0Y","name":"London","permalink":"uk-lon-01","country":{"id":"ctry_6AO9tYYugvTGnd5b","name":"United + Kingdom","iso_code2":"GB","iso_code3":"GBR","time_zone":"Europe/London","eu":false}}},"allocation_id":null,"allocation_type":null},"allocation":null}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "567" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 12:53:30 GMT + Etag: + - W/"d73e9de6162e4a6972c8f55598b5f968" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "174" + X-Request-Id: + - 33ce8eb3-226e-41e5-992d-f446eebfc2df + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_3Mc6zF0VP1zK9Z7n + method: DELETE + response: + body: '{}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - "2" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 12:53:30 GMT + Etag: + - W/"44136fa355b3678a1146ad16f7e8649e" + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "171" + X-Request-Id: + - 5050ff7a-2f95-44a4-9e20-4fdc1bd3e4ab + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + User-Agent: + - Terraform/ (+https://www.terraform.io) Terraform-Plugin-Framework terraform-provider-katapult + url: https://api.katapult.io/core/v1/ip_addresses/_?ip_address%5Bid%5D=ip_3Mc6zF0VP1zK9Z7n + method: GET + response: + body: '{"error":{"code":"ip_address_not_found","description":"No IP addresses + were found matching any of the criteria provided in the arguments","detail":{}}}' + headers: + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - no-cache + Content-Length: + - "151" + Content-Type: + - application/json + Date: + - Wed, 08 Nov 2023 12:53:31 GMT + Server: + - Caddy + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Api-Schema: + - json-error + X-Ratelimit-Permitted: + - "200" + X-Ratelimit-Remaining: + - "168" + X-Request-Id: + - c2b35dbe-0af8-49e5-bb32-fb3f095dc42b + status: 404 Not Found + code: 404 + duration: "" diff --git a/internal/v6provider/v6provider.go b/internal/v6provider/v6provider.go new file mode 100644 index 00000000..7dc3717c --- /dev/null +++ b/internal/v6provider/v6provider.go @@ -0,0 +1,272 @@ +package v6provider + +import ( + "context" + "fmt" + "log" + "net/http" + "os" + "strings" + "time" + + "github.com/hashicorp/go-hclog" + "github.com/hashicorp/go-retryablehttp" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/provider" + "github.com/hashicorp/terraform-plugin-framework/provider/schema" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +const ( + defaultGeneratedNamePrefix = "tf" + uaEnvVar = "TF_APPEND_USER_AGENT" +) + +type ( + KatapultProvider struct { + Version string + Commit string + HTTPClient *http.Client + + GeneratedNamePrefix string + m *Meta + } + + KatapultProviderModel struct { + APIKey types.String `tfsdk:"api_key"` + Organization types.String `tfsdk:"organization"` + DataCenter types.String `tfsdk:"data_center"` + SkipTrashObjectPurge types.Bool `tfsdk:"skip_trash_object_purge"` + LogLevel types.String `tfsdk:"log_level"` + } +) + +func New(k *KatapultProvider) func() provider.Provider { + return func() provider.Provider { + if k != nil { + return k + } + + return &KatapultProvider{} + } +} + +func (k *KatapultProvider) Metadata( + _ context.Context, + _ provider.MetadataRequest, + resp *provider.MetadataResponse, +) { + resp.TypeName = "katapult" +} + +func (k *KatapultProvider) Schema( + _ context.Context, + _ provider.SchemaRequest, + resp *provider.SchemaResponse, +) { + resp.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + "api_key": schema.StringAttribute{ + Optional: true, + Sensitive: true, + MarkdownDescription: "**REQUIRED** via config or " + + "environment variable. " + + "API Key for Katapult Core API. Can be " + + "specified with the `KATAPULT_API_KEY` environment " + + "variable.", + }, + "organization": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "**REQUIRED** via config or " + + "environment variable. " + + "Organization sub-domain. Can be " + + "specified with the `KATAPULT_ORGANIZATION` " + + "environment variable.", + }, + "data_center": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "**REQUIRED** via config or " + + "environment variable. " + + "Data center permalink. Can be " + + "specified with the `KATAPULT_DATA_CENTER` " + + "environment variable.", + }, + "skip_trash_object_purge": schema.BoolAttribute{ + Optional: true, + //nolint:lll + Description: strings.TrimSpace(` + +Skip purging deleted resources from Katapult's trash when they are destroyed by Terraform. Only relevant to some resources which are moved to the trash when they are deleted. Can be specified with the +` + "`KATAPULT_SKIP_TRASH_OBJECT_PURGE`" + ` environment variable. Defaults to ` + "`false`" + `. + + ~> **Note:** Using ` + "`skip_trash_object_purge`" + ` can quickly lead to a build up of a lot objects in the trash if you are replacing resources repeatedly. Hence this option is disabled by default, and should only be used if you are sure you want to keep deleted resources in the trash. + +`), + //nolint:lll + MarkdownDescription: strings.TrimSpace(` + +Skip purging deleted resources from Katapult's trash when they are destroyed by Terraform. Only relevant to some resources which are moved to the trash when they are deleted. Can be specified with the +` + "`KATAPULT_SKIP_TRASH_OBJECT_PURGE`" + ` environment variable. Defaults to ` + "`false`" + `. + + ~> **Note:** Using ` + "`skip_trash_object_purge`" + ` can quickly lead to a build up of a lot objects in the trash if you are replacing resources repeatedly. Hence this option is disabled by default, and should only be used if you are sure you want to keep deleted resources in the trash. + +`), + }, + "log_level": schema.StringAttribute{ + Optional: true, + + Validators: []validator.String{ + stringvalidator.OneOfCaseInsensitive("trace", + "debug", + "info", + "warn", + "error", + "off", + ), + }, + Description: "Log level used by Katapult Terraform " + + "provider. Can be specified with the " + + "`KATAPULT_LOG_LEVEL` environment variable. " + + "Defaults to `info`.", + MarkdownDescription: "Log level used by Katapult Terraform " + + "provider. Can be specified with the " + + "`KATAPULT_LOG_LEVEL` environment variable. " + + "Defaults to `info`.", + }, + }, + } +} + +func stringOrEnv(in string, env string) string { + if in != "" { + return in + } + + return os.Getenv(env) +} + +func boolOrEnv(in *bool, env string) bool { + if in != nil { + return *in + } + + switch strings.ToLower(os.Getenv(env)) { + case "true", "1", "yes", "on", "y", "t": + return true + } + + return false +} + +func userAgent(name string, terraformVersion string, version string) string { + ua := fmt.Sprintf( + "Terraform/%s (+https://www.terraform.io) Terraform-Plugin-Framework", + terraformVersion, + ) + if name != "" { + ua += " " + name + if version != "" { + ua += "/" + version + } + } + + if add := os.Getenv(uaEnvVar); add != "" { + add = strings.TrimSpace(add) + if len(add) > 0 { + ua += " " + add + log.Printf("[DEBUG] Using modified User-Agent: %s", ua) + } + } + + return ua +} + +func (k *KatapultProvider) Configure( + ctx context.Context, + req provider.ConfigureRequest, + resp *provider.ConfigureResponse, +) { + if k.m != nil { + resp.ResourceData = k.m + resp.DataSourceData = k.m + return + } + + var conf KatapultProviderModel + diags := req.Config.Get(ctx, &conf) + resp.Diagnostics.Append(diags...) + + m, err := NewMeta( + conf.APIKey.ValueString(), + conf.DataCenter.ValueString(), + conf.Organization.ValueString(), + conf.SkipTrashObjectPurge.ValueBoolPointer(), + conf.LogLevel.ValueString(), + k.GeneratedNamePrefix, + k.HTTPClient, + k.Version, + req.TerraformVersion, + ) + if err != nil { + resp.Diagnostics.AddError( + "Configure Error", + err.Error(), + ) + return + } + + k.m = m + resp.ResourceData = m + resp.DataSourceData = m +} + +func (k *KatapultProvider) Resources( + _ context.Context, +) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &IPResource{} + }, + } +} + +func (k *KatapultProvider) DataSources( + _ context.Context, +) []func() datasource.DataSource { + return []func() datasource.DataSource{ + func() datasource.DataSource { + return &IPDataSource{} + }, + } +} + +func newRetryableHTTPClient( + httpClient *http.Client, + logger hclog.Logger, +) *retryablehttp.Client { + client := retryablehttp.NewClient() + client.HTTPClient = httpClient + client.Logger = logger + + client.RetryWaitMin = 1 * time.Second + client.RetryWaitMax = 2 * time.Minute + client.RetryMax = 10 + client.CheckRetry = requestRetryPolicy + + return client +} + +func requestRetryPolicy( + ctx context.Context, + resp *http.Response, + err error, +) (bool, error) { + if resp == nil || resp.StatusCode == http.StatusTooManyRequests { + return true, err + } + + return retryablehttp.DefaultRetryPolicy(ctx, resp, err) +} diff --git a/internal/v6provider/v6provider_test.go b/internal/v6provider/v6provider_test.go new file mode 100644 index 00000000..bde5f169 --- /dev/null +++ b/internal/v6provider/v6provider_test.go @@ -0,0 +1,275 @@ +package v6provider + +import ( + "bytes" + "context" + "errors" + "fmt" + "net/http" + "os" + "path/filepath" + "regexp" + "strings" + "testing" + + "github.com/dnaeon/go-vcr/cassette" + "github.com/dnaeon/go-vcr/recorder" + "github.com/hashicorp/terraform-plugin-framework/provider" + "github.com/hashicorp/terraform-plugin-framework/providerserver" + "github.com/hashicorp/terraform-plugin-go/tfprotov6" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/jimeh/rands/randsmust" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +const ( + testAccResourceNamePrefix = "tf-acc-test" + testAccProviderVersion = "0.0.999" +) + +func testAccPreCheck(t *testing.T) { + t.Helper() + + k := &KatapultProvider{ + Version: testAccProviderVersion, + GeneratedNamePrefix: testAccResourceNamePrefix, + } + + anyMissing := false + envVars := []string{ + "KATAPULT_API_KEY", + "KATAPULT_ORGANIZATION", + "KATAPULT_DATA_CENTER", + } + for _, name := range envVars { + if os.Getenv(name) == "" { + anyMissing = true + t.Errorf( + "%s environment variable must be set for acceptance tests", + name, + ) + } + } + if anyMissing { + t.Fatal("acceptance tests cannot run due to missing configuration") + } + _, err := providerserver.NewProtocol6WithError(k)() + require.NoError(t, err) +} + +type providerFactoryList map[string]func() (tfprotov6.ProviderServer, error) + +type stopRequests struct{} + +func (s *stopRequests) RoundTrip(_ *http.Request) (*http.Response, error) { + return &http.Response{ + StatusCode: http.StatusBadRequest, + }, errors.New("real HTTP(S) requests are disabled") +} + +type testTools struct { + T *testing.T + Ctx context.Context + Recorder *recorder.Recorder + Meta *Meta + ProviderFactories providerFactoryList + randID string +} + +func newTestTools(t *testing.T) *testTools { + r := newVCRRecorder(t) + k := &KatapultProvider{ + Version: testAccProviderVersion, + GeneratedNamePrefix: testAccResourceNamePrefix, + } + + if r != nil { + k.HTTPClient = &http.Client{Transport: r} + } + + ctx := context.Background() + + meta, err := NewMeta("", "", "", nil, "", "", k.HTTPClient, "", "") + require.NoError(t, err) + + k.m = meta + + return &testTools{ + T: t, + Ctx: ctx, + Recorder: r, + Meta: meta, + ProviderFactories: providerFactoryList{ + "katapult": providerserver.NewProtocol6WithError(k), + }, + } +} + +// ResourceName returns the name of a resource in the test provider, for the +// purpose of having unique names which can easily be identified as belonging to +// the acceptance test suite. +func (tt *testTools) ResourceName(name ...string) string { + if len(name) == 0 && strings.HasPrefix(tt.T.Name(), "TestAcc") { + if parts := strings.Split(tt.T.Name(), "_"); len(parts) > 1 { + if strings.Contains(parts[0], "DataSource") { + name = append(name, "data-source") + } + + name = append(name, parts[1:]...) + } + } + + if len(name) == 0 { + name = []string{"default"} + } + + nameStr := strings.Join(name, "-") + + return fmt.Sprintf("%s-%s-%s", + testAccResourceNamePrefix, nameStr, tt.RandID(), + ) +} + +func (tt *testTools) RandID() string { + if tt.randID != "" { + return tt.randID + } + + rand := randsmust.Alphanumeric(12) + if tt.Recorder == nil { + return rand + } + + randIDFile := testDataFilePath(tt.T, ".cassette.rand_id") + if tt.Recorder.Mode() == recorder.ModeReplaying { + data, err := os.ReadFile(randIDFile) + require.NoError(tt.T, err, "missing rand required for VCR replay") + rand = string(bytes.TrimSpace(data)) + } else if tt.Recorder.Mode() == recorder.ModeRecording { + err := os.MkdirAll(filepath.Dir(randIDFile), 0o755) + require.NoError(tt.T, err, "failed to write rand VCR resource ID") + + err = os.WriteFile(randIDFile, []byte(rand), 0o644) //nolint:gosec + require.NoError(tt.T, err, "failed to write rand VCR resource ID") + } + + return rand +} + +func testDataFilePath(t *testing.T, suffix string) string { + baseName := filepath.FromSlash(t.Name()) + baseName = strings.TrimPrefix(baseName, "TestAccKatapult") + + if suffix != "" { + baseName += suffix + } + + return filepath.Join(".", "testdata", baseName) +} + +//nolint:unused // will be used eventually +func exampleResourceConfig(t *testing.T, name string) string { + t.Helper() + + filename := filepath.Join( + "..", "..", "examples", "resources", name, "resource.tf", + ) + data, err := os.ReadFile(filename) + require.NoError(t, err) + + return string(data) +} + +func vcrMode() recorder.Mode { + switch strings.ToLower(os.Getenv("VCR")) { + case "disabled", "off", "no", "0": + return recorder.ModeDisabled + case "record", "rec": + return recorder.ModeRecording + default: + // Prevent real requests unless VCR is explicitly set to record mode. + return recorder.ModeReplaying + } +} + +func newVCRRecorder(t *testing.T) *recorder.Recorder { + cassettePath := testDataFilePath(t, ".cassette") + + var transport http.RoundTripper + mode := vcrMode() + + switch mode { + case recorder.ModeDisabled: + return nil + case recorder.ModeReplaying: + transport = &stopRequests{} + case recorder.ModeRecording: + // Use the default transport. + } + + r, err := recorder.NewAsMode(cassettePath, mode, transport) + if err != nil { + t.Fatal(err) + } + + r.AddFilter(func(i *cassette.Interaction) error { + delete(i.Request.Headers, "Authorization") + + return nil + }) + + t.Cleanup(func() { + assert.NoError(t, r.Stop()) + }) + + return r +} + +// +// Terraform TestCheckFunc helpers +// + +//nolint:unused // will be used eventually +func testCheckGeneratedResourceName( + name string, + key string, +) resource.TestCheckFunc { + return resource.TestMatchResourceAttr( + name, key, + regexp.MustCompile( + fmt.Sprintf( + "^%s-.+-.+$", + regexp.QuoteMeta(testAccResourceNamePrefix), + ), + ), + ) +} + +//nolint:unused // will be used eventually +func testCheckGeneratedHostnameName( + name string, + key string, +) resource.TestCheckFunc { + return resource.TestMatchResourceAttr( + name, key, + regexp.MustCompile( + fmt.Sprintf( + "^%s-.+-.+-.+$", + regexp.QuoteMeta(testAccResourceNamePrefix), + ), + ), + ) +} + +// +// Provider Tests +// + +func TestProvider(t *testing.T) { + pf := New(&KatapultProvider{Version: testAccProviderVersion}) + resp := &provider.SchemaResponse{} + pf().Schema(context.Background(), provider.SchemaRequest{}, resp) + require.False(t, resp.Diagnostics.HasError()) +} diff --git a/main.go b/main.go index 9f215354..d260414b 100644 --- a/main.go +++ b/main.go @@ -4,11 +4,13 @@ import ( "context" "log" + "github.com/hashicorp/terraform-plugin-framework/providerserver" "github.com/hashicorp/terraform-plugin-go/tfprotov6" "github.com/hashicorp/terraform-plugin-go/tfprotov6/tf6server" "github.com/hashicorp/terraform-plugin-mux/tf5to6server" "github.com/hashicorp/terraform-plugin-mux/tf6muxserver" "github.com/krystal/terraform-provider-katapult/internal/provider" + "github.com/krystal/terraform-provider-katapult/internal/v6provider" ) var ( @@ -31,6 +33,10 @@ func main() { providers := []func() tfprotov6.ProviderServer{ func() tfprotov6.ProviderServer { return upgradedSDKServer }, + providerserver.NewProtocol6(v6provider.New(&v6provider.KatapultProvider{ + Version: version, + Commit: commit, + })()), } muxServer, err := tf6muxserver.NewMuxServer(ctx, providers...)