From 56a5f89b0387d4f1aa89b0795528e41b6cd5ae72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Sacrist=C3=A1n=20Izcue?= Date: Sat, 18 May 2024 18:24:01 +0200 Subject: [PATCH 1/3] chore(sdk): Serve the provider through a mux server This is in preparation to migrate to the plugin framework. --- cloudamqp/provider_test.go | 21 ++++++++++----- cloudamqp/resource_cloudamqp_alarm_test.go | 3 +-- ...resource_cloudamqp_aws_eventbridge_test.go | 3 +-- ...resource_cloudamqp_extra_disk_size_test.go | 9 +++---- cloudamqp/resource_cloudamqp_instance_test.go | 12 +++------ ...resource_cloudamqp_integration_log_test.go | 3 +-- ...ource_cloudamqp_integration_metric_test.go | 3 +-- ...ource_cloudamqp_maintenance_window_test.go | 6 ++--- .../resource_cloudamqp_notification_test.go | 3 +-- ...esource_cloudamqp_plugin_community_test.go | 3 +-- cloudamqp/resource_cloudamqp_plugin_test.go | 3 +-- ...e_cloudamqp_rabbitmq_configuration_test.go | 6 ++--- ...source_cloudamqp_security_firewall_test.go | 3 +-- ...resource_cloudamqp_upgrade_lavinmq_test.go | 3 +-- ...esource_cloudamqp_upgrade_rabbitmq_test.go | 6 ++--- .../resource_cloudamqp_vpc_connect_test.go | 9 +++---- ...resource_cloudamqp_vpc_gcp_peering_test.go | 3 +-- .../resource_cloudamqp_vpc_peering_test.go | 1 - cloudamqp/resource_cloudamqp_webhook_test.go | 3 +-- go.mod | 13 ++++----- go.sum | 22 ++++++++------- main.go | 27 ++++++++++++++----- 22 files changed, 81 insertions(+), 84 deletions(-) diff --git a/cloudamqp/provider_test.go b/cloudamqp/provider_test.go index 0be2f40b..0c4f50fb 100644 --- a/cloudamqp/provider_test.go +++ b/cloudamqp/provider_test.go @@ -1,6 +1,7 @@ package cloudamqp import ( + "context" "fmt" "net/http" "net/url" @@ -9,16 +10,15 @@ import ( "testing" "github.com/cloudamqp/terraform-provider-cloudamqp/cloudamqp/vcr-testing/sanitizer" + "github.com/hashicorp/terraform-plugin-go/tfprotov5" + "github.com/hashicorp/terraform-plugin-mux/tf5muxserver" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/tidwall/gjson" "gopkg.in/dnaeon/go-vcr.v3/cassette" "gopkg.in/dnaeon/go-vcr.v3/recorder" ) var ( - testAccProviderFactory map[string]func() (*schema.Provider, error) - mode = recorder.ModeReplayOnly ) @@ -167,10 +167,19 @@ func cloudamqpResourceTest(t *testing.T, c resource.TestCase) { return req.URL.Path == "/login" }) - testAccProviderFactory = map[string]func() (*schema.Provider, error){ - "cloudamqp": func() (*schema.Provider, error) { return Provider("1.0", rec.GetDefaultClient()), nil }, + c.ProtoV5ProviderFactories = map[string]func() (tfprotov5.ProviderServer, error){ + "cloudamqp": func() (tfprotov5.ProviderServer, error) { + ctx := context.Background() + + muxServer, err := tf5muxserver.NewMuxServer(ctx, Provider("1.0", rec.GetDefaultClient()).GRPCProvider) + + if err != nil { + return nil, err + } + + return muxServer.ProviderServer(), nil + }, } - c.ProviderFactories = testAccProviderFactory resource.Test(t, c) } diff --git a/cloudamqp/resource_cloudamqp_alarm_test.go b/cloudamqp/resource_cloudamqp_alarm_test.go index 6ca2f0a5..79c6502d 100644 --- a/cloudamqp/resource_cloudamqp_alarm_test.go +++ b/cloudamqp/resource_cloudamqp_alarm_test.go @@ -55,8 +55,7 @@ func TestAccAlarm_Basic(t *testing.T) { ) cloudamqpResourceTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ProviderFactories: testAccProviderFactory, + PreCheck: func() { testAccPreCheck(t) }, Steps: []resource.TestStep{ { Config: configuration.GetTemplatedConfig(t, fileNames, params), diff --git a/cloudamqp/resource_cloudamqp_aws_eventbridge_test.go b/cloudamqp/resource_cloudamqp_aws_eventbridge_test.go index 2cc59860..d8de79cd 100644 --- a/cloudamqp/resource_cloudamqp_aws_eventbridge_test.go +++ b/cloudamqp/resource_cloudamqp_aws_eventbridge_test.go @@ -27,8 +27,7 @@ func TestAccIntegrationAwsEventbridge_Basic(t *testing.T) { ) cloudamqpResourceTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ProviderFactories: testAccProviderFactory, + PreCheck: func() { testAccPreCheck(t) }, Steps: []resource.TestStep{ { Config: configuration.GetTemplatedConfig(t, fileNames, params), diff --git a/cloudamqp/resource_cloudamqp_extra_disk_size_test.go b/cloudamqp/resource_cloudamqp_extra_disk_size_test.go index 662e51c3..e465e0e2 100644 --- a/cloudamqp/resource_cloudamqp_extra_disk_size_test.go +++ b/cloudamqp/resource_cloudamqp_extra_disk_size_test.go @@ -26,8 +26,7 @@ func TestAccExtraDiskSize_AWS_Basic(t *testing.T) { ) cloudamqpResourceTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ProviderFactories: testAccProviderFactory, + PreCheck: func() { testAccPreCheck(t) }, Steps: []resource.TestStep{ { Config: configuration.GetTemplatedConfig(t, fileNames, params), @@ -60,8 +59,7 @@ func TestAccExtraDiskSize_GCE_Basic(t *testing.T) { ) cloudamqpResourceTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ProviderFactories: testAccProviderFactory, + PreCheck: func() { testAccPreCheck(t) }, Steps: []resource.TestStep{ { Config: configuration.GetTemplatedConfig(t, fileNames, params), @@ -94,8 +92,7 @@ func TestAccExtraDiskSize_Azure_Basic(t *testing.T) { ) cloudamqpResourceTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ProviderFactories: testAccProviderFactory, + PreCheck: func() { testAccPreCheck(t) }, Steps: []resource.TestStep{ { Config: configuration.GetTemplatedConfig(t, fileNames, params), diff --git a/cloudamqp/resource_cloudamqp_instance_test.go b/cloudamqp/resource_cloudamqp_instance_test.go index 48379a3b..c0c6beeb 100644 --- a/cloudamqp/resource_cloudamqp_instance_test.go +++ b/cloudamqp/resource_cloudamqp_instance_test.go @@ -34,8 +34,7 @@ func TestAccInstance_Basic(t *testing.T) { ) cloudamqpResourceTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ProviderFactories: testAccProviderFactory, + PreCheck: func() { testAccPreCheck(t) }, Steps: []resource.TestStep{ { Config: configuration.GetTemplatedConfig(t, fileNames, params), @@ -96,8 +95,7 @@ func TestAccInstance_Upgrade(t *testing.T) { } ) cloudamqpResourceTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ProviderFactories: testAccProviderFactory, + PreCheck: func() { testAccPreCheck(t) }, Steps: []resource.TestStep{ { Config: configuration.GetTemplatedConfig(t, fileNames, params), @@ -146,8 +144,7 @@ func TestAccInstance_PlanChange(t *testing.T) { ) cloudamqpResourceTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ProviderFactories: testAccProviderFactory, + PreCheck: func() { testAccPreCheck(t) }, Steps: []resource.TestStep{ { Config: configuration.GetTemplatedConfig(t, fileNames, params), @@ -189,8 +186,7 @@ func TestAccInstance_Downgrade(t *testing.T) { ) cloudamqpResourceTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ProviderFactories: testAccProviderFactory, + PreCheck: func() { testAccPreCheck(t) }, Steps: []resource.TestStep{ { Config: configuration.GetTemplatedConfig(t, fileNames, params), diff --git a/cloudamqp/resource_cloudamqp_integration_log_test.go b/cloudamqp/resource_cloudamqp_integration_log_test.go index b8de0d0e..53a0d4c3 100644 --- a/cloudamqp/resource_cloudamqp_integration_log_test.go +++ b/cloudamqp/resource_cloudamqp_integration_log_test.go @@ -55,8 +55,7 @@ func TestAccIntegrationLog_Basic(t *testing.T) { ) cloudamqpResourceTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ProviderFactories: testAccProviderFactory, + PreCheck: func() { testAccPreCheck(t) }, Steps: []resource.TestStep{ { ExpectNonEmptyPlan: true, diff --git a/cloudamqp/resource_cloudamqp_integration_metric_test.go b/cloudamqp/resource_cloudamqp_integration_metric_test.go index 957f6190..94427ddd 100644 --- a/cloudamqp/resource_cloudamqp_integration_metric_test.go +++ b/cloudamqp/resource_cloudamqp_integration_metric_test.go @@ -40,8 +40,7 @@ func TestAccIntegrationMetric_Basic(t *testing.T) { ) cloudamqpResourceTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ProviderFactories: testAccProviderFactory, + PreCheck: func() { testAccPreCheck(t) }, Steps: []resource.TestStep{ { ExpectNonEmptyPlan: true, diff --git a/cloudamqp/resource_cloudamqp_maintenance_window_test.go b/cloudamqp/resource_cloudamqp_maintenance_window_test.go index 04dec69f..bd6b107f 100644 --- a/cloudamqp/resource_cloudamqp_maintenance_window_test.go +++ b/cloudamqp/resource_cloudamqp_maintenance_window_test.go @@ -53,8 +53,7 @@ func TestAccMaintenanceWindow_LavinMQ(t *testing.T) { ) cloudamqpResourceTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ProviderFactories: testAccProviderFactory, + PreCheck: func() { testAccPreCheck(t) }, Steps: []resource.TestStep{ { Config: configuration.GetTemplatedConfig(t, fileNamesDayTime, paramsDayTime), @@ -138,8 +137,7 @@ func TestAccMaintenanceWindow_RabbitMQ(t *testing.T) { ) cloudamqpResourceTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ProviderFactories: testAccProviderFactory, + PreCheck: func() { testAccPreCheck(t) }, Steps: []resource.TestStep{ { Config: configuration.GetTemplatedConfig(t, fileNamesDayTime, paramsDayTime), diff --git a/cloudamqp/resource_cloudamqp_notification_test.go b/cloudamqp/resource_cloudamqp_notification_test.go index 2a6cb6cb..4c94abb0 100644 --- a/cloudamqp/resource_cloudamqp_notification_test.go +++ b/cloudamqp/resource_cloudamqp_notification_test.go @@ -35,8 +35,7 @@ func TestAccNotification_Basic(t *testing.T) { ) cloudamqpResourceTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ProviderFactories: testAccProviderFactory, + PreCheck: func() { testAccPreCheck(t) }, Steps: []resource.TestStep{ { Config: configuration.GetTemplatedConfig(t, fileNames, params), diff --git a/cloudamqp/resource_cloudamqp_plugin_community_test.go b/cloudamqp/resource_cloudamqp_plugin_community_test.go index 037309f5..cf8873c5 100644 --- a/cloudamqp/resource_cloudamqp_plugin_community_test.go +++ b/cloudamqp/resource_cloudamqp_plugin_community_test.go @@ -40,8 +40,7 @@ func TestAccPluginCommunity_Basic(t *testing.T) { ) cloudamqpResourceTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ProviderFactories: testAccProviderFactory, + PreCheck: func() { testAccPreCheck(t) }, Steps: []resource.TestStep{ { Config: configuration.GetTemplatedConfig(t, fileNames, params), diff --git a/cloudamqp/resource_cloudamqp_plugin_test.go b/cloudamqp/resource_cloudamqp_plugin_test.go index f2b97011..1e42abbd 100644 --- a/cloudamqp/resource_cloudamqp_plugin_test.go +++ b/cloudamqp/resource_cloudamqp_plugin_test.go @@ -40,8 +40,7 @@ func TestAccPlugin_Basic(t *testing.T) { ) cloudamqpResourceTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ProviderFactories: testAccProviderFactory, + PreCheck: func() { testAccPreCheck(t) }, Steps: []resource.TestStep{ { Config: configuration.GetTemplatedConfig(t, fileNames, params), diff --git a/cloudamqp/resource_cloudamqp_rabbitmq_configuration_test.go b/cloudamqp/resource_cloudamqp_rabbitmq_configuration_test.go index a8398ffb..cec3958a 100644 --- a/cloudamqp/resource_cloudamqp_rabbitmq_configuration_test.go +++ b/cloudamqp/resource_cloudamqp_rabbitmq_configuration_test.go @@ -27,8 +27,7 @@ func TestAccRabbitMqConfiguration_Basic(t *testing.T) { ) cloudamqpResourceTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ProviderFactories: testAccProviderFactory, + PreCheck: func() { testAccPreCheck(t) }, Steps: []resource.TestStep{ { Config: configuration.GetTemplatedConfig(t, fileNames, params), @@ -70,8 +69,7 @@ func TestAccRabbitMqConfiguration_LogExhangeLevel(t *testing.T) { ) cloudamqpResourceTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ProviderFactories: testAccProviderFactory, + PreCheck: func() { testAccPreCheck(t) }, Steps: []resource.TestStep{ { Config: configuration.GetTemplatedConfig(t, fileNames, params), diff --git a/cloudamqp/resource_cloudamqp_security_firewall_test.go b/cloudamqp/resource_cloudamqp_security_firewall_test.go index 069b7491..77152eb2 100644 --- a/cloudamqp/resource_cloudamqp_security_firewall_test.go +++ b/cloudamqp/resource_cloudamqp_security_firewall_test.go @@ -39,8 +39,7 @@ func TestAccFirewall_Basic(t *testing.T) { ) cloudamqpResourceTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ProviderFactories: testAccProviderFactory, + PreCheck: func() { testAccPreCheck(t) }, Steps: []resource.TestStep{ { Config: configuration.GetTemplatedConfig(t, fileNames, params), diff --git a/cloudamqp/resource_cloudamqp_upgrade_lavinmq_test.go b/cloudamqp/resource_cloudamqp_upgrade_lavinmq_test.go index e1dc51f4..8313f58b 100644 --- a/cloudamqp/resource_cloudamqp_upgrade_lavinmq_test.go +++ b/cloudamqp/resource_cloudamqp_upgrade_lavinmq_test.go @@ -48,8 +48,7 @@ func TestAccUpgradeLavinMQ(t *testing.T) { ) cloudamqpResourceTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ProviderFactories: testAccProviderFactory, + PreCheck: func() { testAccPreCheck(t) }, Steps: []resource.TestStep{ { Config: configuration.GetTemplatedConfig(t, fileNames, params), diff --git a/cloudamqp/resource_cloudamqp_upgrade_rabbitmq_test.go b/cloudamqp/resource_cloudamqp_upgrade_rabbitmq_test.go index 574c60f7..663e92ec 100644 --- a/cloudamqp/resource_cloudamqp_upgrade_rabbitmq_test.go +++ b/cloudamqp/resource_cloudamqp_upgrade_rabbitmq_test.go @@ -57,8 +57,7 @@ func TestAccUpgradeRabbitMQ_Latest(t *testing.T) { ) cloudamqpResourceTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ProviderFactories: testAccProviderFactory, + PreCheck: func() { testAccPreCheck(t) }, Steps: []resource.TestStep{ { Config: configuration.GetTemplatedConfig(t, fileNames, params), @@ -151,8 +150,7 @@ func TestAccUpgradeRabbitMQ_Specific(t *testing.T) { ) cloudamqpResourceTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ProviderFactories: testAccProviderFactory, + PreCheck: func() { testAccPreCheck(t) }, Steps: []resource.TestStep{ { Config: configuration.GetTemplatedConfig(t, fileNames, params), diff --git a/cloudamqp/resource_cloudamqp_vpc_connect_test.go b/cloudamqp/resource_cloudamqp_vpc_connect_test.go index d8316d11..c7817761 100644 --- a/cloudamqp/resource_cloudamqp_vpc_connect_test.go +++ b/cloudamqp/resource_cloudamqp_vpc_connect_test.go @@ -43,8 +43,7 @@ func TestAccVpcConnect_AWS_Basic(t *testing.T) { ) cloudamqpResourceTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ProviderFactories: testAccProviderFactory, + PreCheck: func() { testAccPreCheck(t) }, Steps: []resource.TestStep{ { Config: configuration.GetTemplatedConfig(t, fileNames, params), @@ -98,8 +97,7 @@ func TestAccVpcConnect_Azure_Basic(t *testing.T) { ) cloudamqpResourceTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ProviderFactories: testAccProviderFactory, + PreCheck: func() { testAccPreCheck(t) }, Steps: []resource.TestStep{ { Config: configuration.GetTemplatedConfig(t, fileNames, params), @@ -142,8 +140,7 @@ func TestAccVpcConnect_GCP_Basic(t *testing.T) { ) cloudamqpResourceTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ProviderFactories: testAccProviderFactory, + PreCheck: func() { testAccPreCheck(t) }, Steps: []resource.TestStep{ { Config: configuration.GetTemplatedConfig(t, fileNames, params), diff --git a/cloudamqp/resource_cloudamqp_vpc_gcp_peering_test.go b/cloudamqp/resource_cloudamqp_vpc_gcp_peering_test.go index 0bb25ba4..20f6c562 100644 --- a/cloudamqp/resource_cloudamqp_vpc_gcp_peering_test.go +++ b/cloudamqp/resource_cloudamqp_vpc_gcp_peering_test.go @@ -33,8 +33,7 @@ func TestAccVpcGcpPeering_Basic(t *testing.T) { ) cloudamqpResourceTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ProviderFactories: testAccProviderFactory, + PreCheck: func() { testAccPreCheck(t) }, Steps: []resource.TestStep{ { Config: configuration.GetTemplatedConfig(t, fileNames, params), diff --git a/cloudamqp/resource_cloudamqp_vpc_peering_test.go b/cloudamqp/resource_cloudamqp_vpc_peering_test.go index b839d188..4eb57b79 100644 --- a/cloudamqp/resource_cloudamqp_vpc_peering_test.go +++ b/cloudamqp/resource_cloudamqp_vpc_peering_test.go @@ -22,7 +22,6 @@ func TestAccVpcPeering_Basic(t *testing.T) { cloudamqpResourceTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, - ProviderFactories: testAccProviderFactory, PreventPostDestroyRefresh: true, Steps: []resource.TestStep{ { diff --git a/cloudamqp/resource_cloudamqp_webhook_test.go b/cloudamqp/resource_cloudamqp_webhook_test.go index 3531302b..00e9504e 100644 --- a/cloudamqp/resource_cloudamqp_webhook_test.go +++ b/cloudamqp/resource_cloudamqp_webhook_test.go @@ -37,8 +37,7 @@ func TestAccWebhook_Basic(t *testing.T) { ) cloudamqpResourceTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ProviderFactories: testAccProviderFactory, + PreCheck: func() { testAccPreCheck(t) }, Steps: []resource.TestStep{ { Config: configuration.GetTemplatedConfig(t, fileNames, params), diff --git a/go.mod b/go.mod index 9d18d421..0d246680 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,9 @@ go 1.24.0 require ( github.com/dghubble/sling v1.4.2 + github.com/hashicorp/terraform-plugin-go v0.26.0 github.com/hashicorp/terraform-plugin-log v0.9.0 + github.com/hashicorp/terraform-plugin-mux v0.18.0 github.com/hashicorp/terraform-plugin-sdk/v2 v2.36.1 github.com/tidwall/gjson v1.18.0 github.com/tidwall/sjson v1.2.5 @@ -35,7 +37,6 @@ require ( github.com/hashicorp/logutils v1.0.0 // indirect github.com/hashicorp/terraform-exec v0.22.0 // indirect github.com/hashicorp/terraform-json v0.24.0 // indirect - github.com/hashicorp/terraform-plugin-go v0.26.0 // indirect github.com/hashicorp/terraform-registry-address v0.2.4 // indirect github.com/hashicorp/terraform-svchost v0.1.1 // indirect github.com/hashicorp/yamux v0.1.1 // indirect @@ -53,12 +54,12 @@ require ( github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/zclconf/go-cty v1.16.2 // indirect - golang.org/x/crypto v0.36.0 // indirect + golang.org/x/crypto v0.33.0 // indirect golang.org/x/mod v0.22.0 // indirect - golang.org/x/net v0.38.0 // indirect - golang.org/x/sync v0.12.0 // indirect - golang.org/x/sys v0.31.0 // indirect - golang.org/x/text v0.23.0 // indirect + golang.org/x/net v0.34.0 // indirect + golang.org/x/sync v0.11.0 // indirect + golang.org/x/sys v0.30.0 // indirect + golang.org/x/text v0.22.0 // indirect golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect google.golang.org/appengine v1.6.8 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53 // indirect diff --git a/go.sum b/go.sum index 2b5e4555..719fa97c 100644 --- a/go.sum +++ b/go.sum @@ -89,6 +89,8 @@ github.com/hashicorp/terraform-plugin-go v0.26.0 h1:cuIzCv4qwigug3OS7iKhpGAbZTiy github.com/hashicorp/terraform-plugin-go v0.26.0/go.mod h1:+CXjuLDiFgqR+GcrM5a2E2Kal5t5q2jb0E3D57tTdNY= github.com/hashicorp/terraform-plugin-log v0.9.0 h1:i7hOA+vdAItN1/7UrfBqBwvYPQ9TFvymaRGZED3FCV0= github.com/hashicorp/terraform-plugin-log v0.9.0/go.mod h1:rKL8egZQ/eXSyDqzLUuwUYLVdlYeamldAHSxjUFADow= +github.com/hashicorp/terraform-plugin-mux v0.18.0 h1:7491JFSpWyAe0v9YqBT+kel7mzHAbO5EpxxT0cUL/Ms= +github.com/hashicorp/terraform-plugin-mux v0.18.0/go.mod h1:Ho1g4Rr8qv0qTJlcRKfjjXTIO67LNbDtM6r+zHUNHJQ= github.com/hashicorp/terraform-plugin-sdk/v2 v2.36.1 h1:WNMsTLkZf/3ydlgsuXePa3jvZFwAJhruxTxP/c1Viuw= github.com/hashicorp/terraform-plugin-sdk/v2 v2.36.1/go.mod h1:P6o64QS97plG44iFzSM6rAn6VJIC/Sy9a9IkEtl79K4= github.com/hashicorp/terraform-registry-address v0.2.4 h1:JXu/zHB2Ymg/TGVCRu10XqNa4Sh2bWcqCNyKWjnCPJA= @@ -176,8 +178,8 @@ go.opentelemetry.io/otel/trace v1.31.0 h1:ffjsj1aRouKewfr85U2aGagJ46+MvodynlQ1HY go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= -golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= +golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus= +golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4= golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= @@ -185,13 +187,13 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= -golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= +golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= +golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= -golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= +golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -204,8 +206,8 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= -golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -213,8 +215,8 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= -golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= +golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= +golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= diff --git a/main.go b/main.go index 55720f3b..74d7e3f9 100644 --- a/main.go +++ b/main.go @@ -1,19 +1,32 @@ package main import ( + "context" + "log" "net/http" "github.com/cloudamqp/terraform-provider-cloudamqp/cloudamqp" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/plugin" + "github.com/hashicorp/terraform-plugin-go/tfprotov5/tf5server" + "github.com/hashicorp/terraform-plugin-mux/tf5muxserver" ) var version string func main() { - plugin.Serve(&plugin.ServeOpts{ - ProviderFunc: func() *schema.Provider { - return cloudamqp.Provider(version, http.DefaultClient) - }, - }) + ctx := context.Background() + + muxServer, err := tf5muxserver.NewMuxServer(ctx, cloudamqp.Provider(version, http.DefaultClient).GRPCProvider) + + if err != nil { + log.Fatal(err) + } + + err = tf5server.Serve( + "registry.terraform.io/cloudamqp/cloudamqp", + muxServer.ProviderServer, + ) + + if err != nil { + log.Fatal(err) + } } From 864e721b4fc26614c04703a362e04f76a4a80690 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Sacrist=C3=A1n=20Izcue?= Date: Mon, 20 May 2024 00:30:45 +0200 Subject: [PATCH 2/3] chore(sdk): Implement skeleton of provider in the framework plugin This combined with the muxing will allow us to migrate resources and datasources one at a time --- cloudamqp/provider.go | 125 ++++++++++++++++++++++++++++++++----- cloudamqp/provider_test.go | 8 ++- go.mod | 1 + go.sum | 2 + main.go | 6 +- 5 files changed, 123 insertions(+), 19 deletions(-) diff --git a/cloudamqp/provider.go b/cloudamqp/provider.go index 4eea0345..c709cbe9 100644 --- a/cloudamqp/provider.go +++ b/cloudamqp/provider.go @@ -1,42 +1,136 @@ package cloudamqp import ( + "context" "fmt" "log" "net/http" + "os" "github.com/cloudamqp/terraform-provider-cloudamqp/api" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "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/types" + schemaSdk "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) var version string var enableFasterInstanceDestroy bool -func Provider(v string, client *http.Client) *schema.Provider { +type cloudamqpProvider struct { + version string + client *http.Client +} + +type cloudamqpProviderModel struct { + ApiKey types.String `tfsdk:"apikey"` + BaseUrl types.String `tfsdk:"baseurl"` + EnableFasterInstanceDestroy types.Bool `tfsdk:"enable_faster_instance_destroy"` +} + +func (p *cloudamqpProvider) Metadata(_ context.Context, _ provider.MetadataRequest, response *provider.MetadataResponse) { + response.Version = p.version + response.TypeName = "cloudamqp" +} + +func (p *cloudamqpProvider) Schema(_ context.Context, _ provider.SchemaRequest, response *provider.SchemaResponse) { + response.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + "apikey": schema.StringAttribute{ + Optional: true, + Description: "Key used to authentication to the CloudAMQP Customer API", + }, + "baseurl": schema.StringAttribute{ + Optional: true, + Description: "Base URL to CloudAMQP Customer website", + }, + "enable_faster_instance_destroy": schema.BoolAttribute{ + Optional: true, + Description: "Skips destroying backend resources on 'terraform destroy'", + }, + }, + } +} + +func (p *cloudamqpProvider) Configure(ctx context.Context, request provider.ConfigureRequest, response *provider.ConfigureResponse) { + var data cloudamqpProviderModel + + // Read configuration data into model + response.Diagnostics.Append(request.Config.Get(ctx, &data)...) + + apiKey := data.ApiKey.ValueString() + baseUrl := data.BaseUrl.ValueString() + + // Check configuration data, which should take precedence over + // environment variable data, if found. + if apiKey == "" { + apiKey = os.Getenv("CLOUDAMQP_APIKEY") + } + + if apiKey == "" { + response.Diagnostics.AddError( + "Missing API Key Configuration", + "While configuring the provider, the API key was not found in "+ + "the CLOUDAMQP_APIKEY environment variable or provider "+ + "configuration block apikey attribute.", + ) + } + + if baseUrl == "" { + baseUrl = os.Getenv("CLOUDAMQP_BASEURL") + } + + if baseUrl == "" { + baseUrl = "https://customer.cloudamqp.com" + } + + useragent := fmt.Sprintf("terraform-provider-cloudamqp_v%s", p.version) + log.Printf("[DEBUG] cloudamqp::provider::configure useragent: %v", useragent) + apiClient := api.New(baseUrl, apiKey, useragent, p.client) + + response.ResourceData = apiClient + response.DataSourceData = apiClient +} + +func (p *cloudamqpProvider) DataSources(_ context.Context) []func() datasource.DataSource { + return []func() datasource.DataSource{} +} + +func (p *cloudamqpProvider) Resources(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{} +} + +func New(version string, client *http.Client) provider.Provider { + return &cloudamqpProvider{version, client} +} + +func Provider(v string, client *http.Client) *schemaSdk.Provider { version = v log.Printf("Terraform-Provider-CloudAMQP Version: %s", version) - return &schema.Provider{ - Schema: map[string]*schema.Schema{ + return &schemaSdk.Provider{ + Schema: map[string]*schemaSdk.Schema{ "apikey": { - Type: schema.TypeString, + Type: schemaSdk.TypeString, Required: true, - DefaultFunc: schema.EnvDefaultFunc("CLOUDAMQP_APIKEY", nil), + DefaultFunc: schemaSdk.EnvDefaultFunc("CLOUDAMQP_APIKEY", nil), Description: "Key used to authentication to the CloudAMQP Customer API", }, "baseurl": { - Type: schema.TypeString, - DefaultFunc: schema.EnvDefaultFunc("CLOUDAMQP_BASEURL", "https://customer.cloudamqp.com"), + Type: schemaSdk.TypeString, + DefaultFunc: schemaSdk.EnvDefaultFunc("CLOUDAMQP_BASEURL", "https://customer.cloudamqp.com"), Optional: true, Description: "Base URL to CloudAMQP Customer website", }, "enable_faster_instance_destroy": { - Type: schema.TypeBool, - DefaultFunc: schema.EnvDefaultFunc("CLOUDAMQP_ENABLE_FASTER_INSTANCE_DESTROY", false), + Type: schemaSdk.TypeBool, + DefaultFunc: schemaSdk.EnvDefaultFunc("CLOUDAMQP_ENABLE_FASTER_INSTANCE_DESTROY", false), Optional: true, Description: "Skips destroying backend resources on 'terraform destroy'", }, }, - DataSourcesMap: map[string]*schema.Resource{ + DataSourcesMap: map[string]*schemaSdk.Resource{ "cloudamqp_account_vpcs": dataSourceAccountVpcs(), "cloudamqp_account": dataSourceAccount(), "cloudamqp_alarm": dataSourceAlarm(), @@ -51,16 +145,15 @@ func Provider(v string, client *http.Client) *schema.Provider { "cloudamqp_vpc_gcp_info": dataSourceVpcGcpInfo(), "cloudamqp_vpc_info": dataSourceVpcInfo(), }, - ResourcesMap: map[string]*schema.Resource{ + ResourcesMap: map[string]*schemaSdk.Resource{ "cloudamqp_account_action": resourceAccountAction(), "cloudamqp_alarm": resourceAlarm(), "cloudamqp_custom_domain": resourceCustomDomain(), "cloudamqp_extra_disk_size": resourceExtraDiskSize(), "cloudamqp_instance": resourceInstance(), - "cloudamqp_integration_aws_eventbridge": resourceAwsEventBridge(), "cloudamqp_integration_log": resourceIntegrationLog(), "cloudamqp_integration_metric": resourceIntegrationMetric(), - "cloudamqp_maintenance_window": resourceMaintenanceWindow(), + "cloudamqp_maintenance_window": resourceMaintenanceWindow(), "cloudamqp_node_actions": resourceNodeAction(), "cloudamqp_notification": resourceNotification(), "cloudamqp_plugin_community": resourcePluginCommunity(), @@ -81,8 +174,8 @@ func Provider(v string, client *http.Client) *schema.Provider { } } -func configureClient(client *http.Client) schema.ConfigureFunc { - return func(d *schema.ResourceData) (any, error) { +func configureClient(client *http.Client) schemaSdk.ConfigureFunc { + return func(d *schemaSdk.ResourceData) (any, error) { enableFasterInstanceDestroy = d.Get("enable_faster_instance_destroy").(bool) useragent := fmt.Sprintf("terraform-provider-cloudamqp_v%s", version) return api.New(d.Get("baseurl").(string), d.Get("apikey").(string), useragent, client), nil diff --git a/cloudamqp/provider_test.go b/cloudamqp/provider_test.go index 0c4f50fb..43a5db6f 100644 --- a/cloudamqp/provider_test.go +++ b/cloudamqp/provider_test.go @@ -10,6 +10,7 @@ import ( "testing" "github.com/cloudamqp/terraform-provider-cloudamqp/cloudamqp/vcr-testing/sanitizer" + "github.com/hashicorp/terraform-plugin-framework/providerserver" "github.com/hashicorp/terraform-plugin-go/tfprotov5" "github.com/hashicorp/terraform-plugin-mux/tf5muxserver" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -146,7 +147,7 @@ func cloudamqpResourceTest(t *testing.T, c resource.TestCase) { fmt.Println("SKIP: PUT /api/instances/{id}/config", i.Request.URL, "error:", errStr) i.DiscardOnSave = true } - case i.Response.Code == 200 && i.Request.Method == "GET" && + case i.Response.Code == 200 && i.Request.Method == "GET" && regexp.MustCompile(`/api/vpcs/\d+/vpc-peering$`).MatchString(i.Request.URL): // Filter polling for vpc peering state, only store active response state := gjson.Get(i.Response.Body, "rows.0.state").String() @@ -171,7 +172,10 @@ func cloudamqpResourceTest(t *testing.T, c resource.TestCase) { "cloudamqp": func() (tfprotov5.ProviderServer, error) { ctx := context.Background() - muxServer, err := tf5muxserver.NewMuxServer(ctx, Provider("1.0", rec.GetDefaultClient()).GRPCProvider) + muxServer, err := tf5muxserver.NewMuxServer(ctx, + Provider("1.0", rec.GetDefaultClient()).GRPCProvider, + providerserver.NewProtocol5(New("1.0", rec.GetDefaultClient())), + ) if err != nil { return nil, err diff --git a/go.mod b/go.mod index 0d246680..9f0a93ee 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.24.0 require ( github.com/dghubble/sling v1.4.2 + github.com/hashicorp/terraform-plugin-framework v1.14.1 github.com/hashicorp/terraform-plugin-go v0.26.0 github.com/hashicorp/terraform-plugin-log v0.9.0 github.com/hashicorp/terraform-plugin-mux v0.18.0 diff --git a/go.sum b/go.sum index 719fa97c..d4765091 100644 --- a/go.sum +++ b/go.sum @@ -85,6 +85,8 @@ github.com/hashicorp/terraform-exec v0.22.0 h1:G5+4Sz6jYZfRYUCg6eQgDsqTzkNXV+fP8 github.com/hashicorp/terraform-exec v0.22.0/go.mod h1:bjVbsncaeh8jVdhttWYZuBGj21FcYw6Ia/XfHcNO7lQ= github.com/hashicorp/terraform-json v0.24.0 h1:rUiyF+x1kYawXeRth6fKFm/MdfBS6+lW4NbeATsYz8Q= github.com/hashicorp/terraform-json v0.24.0/go.mod h1:Nfj5ubo9xbu9uiAoZVBsNOjvNKB66Oyrvtit74kC7ow= +github.com/hashicorp/terraform-plugin-framework v1.14.1 h1:jaT1yvU/kEKEsxnbrn4ZHlgcxyIfjvZ41BLdlLk52fY= +github.com/hashicorp/terraform-plugin-framework v1.14.1/go.mod h1:xNUKmvTs6ldbwTuId5euAtg37dTxuyj3LHS3uj7BHQ4= github.com/hashicorp/terraform-plugin-go v0.26.0 h1:cuIzCv4qwigug3OS7iKhpGAbZTiypAfFQmw8aE65O2M= github.com/hashicorp/terraform-plugin-go v0.26.0/go.mod h1:+CXjuLDiFgqR+GcrM5a2E2Kal5t5q2jb0E3D57tTdNY= github.com/hashicorp/terraform-plugin-log v0.9.0 h1:i7hOA+vdAItN1/7UrfBqBwvYPQ9TFvymaRGZED3FCV0= diff --git a/main.go b/main.go index 74d7e3f9..24939b79 100644 --- a/main.go +++ b/main.go @@ -6,6 +6,7 @@ import ( "net/http" "github.com/cloudamqp/terraform-provider-cloudamqp/cloudamqp" + "github.com/hashicorp/terraform-plugin-framework/providerserver" "github.com/hashicorp/terraform-plugin-go/tfprotov5/tf5server" "github.com/hashicorp/terraform-plugin-mux/tf5muxserver" ) @@ -15,7 +16,10 @@ var version string func main() { ctx := context.Background() - muxServer, err := tf5muxserver.NewMuxServer(ctx, cloudamqp.Provider(version, http.DefaultClient).GRPCProvider) + muxServer, err := tf5muxserver.NewMuxServer( + ctx, cloudamqp.Provider(version, http.DefaultClient).GRPCProvider, + providerserver.NewProtocol5(cloudamqp.New(version, http.DefaultClient)), + ) if err != nil { log.Fatal(err) From 5146f7bd819e0a6bd66a6e2e4404b47f7429fb20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Sacrist=C3=A1n=20Izcue?= Date: Wed, 29 May 2024 01:04:06 +0200 Subject: [PATCH 3/3] chore(cloudamqp_integration_aws_eventbridge): Migrate towards terraform plugin framework This is the first resource to move towards the new system and should serve as a template for all others. The reason to choose this one as the first is because it is the smallest file that still has tests to prove everything still works as before. --- cloudamqp/provider.go | 52 ++-- .../resource_cloudamqp_aws_eventbridge.go | 276 +++++++++++------- 2 files changed, 206 insertions(+), 122 deletions(-) diff --git a/cloudamqp/provider.go b/cloudamqp/provider.go index c709cbe9..41730833 100644 --- a/cloudamqp/provider.go +++ b/cloudamqp/provider.go @@ -99,7 +99,11 @@ func (p *cloudamqpProvider) DataSources(_ context.Context) []func() datasource.D } func (p *cloudamqpProvider) Resources(_ context.Context) []func() resource.Resource { - return []func() resource.Resource{} + return []func() resource.Resource{ + func() resource.Resource { + return &awsEventBridgeResource{} + }, + } } func New(version string, client *http.Client) provider.Provider { @@ -146,29 +150,29 @@ func Provider(v string, client *http.Client) *schemaSdk.Provider { "cloudamqp_vpc_info": dataSourceVpcInfo(), }, ResourcesMap: map[string]*schemaSdk.Resource{ - "cloudamqp_account_action": resourceAccountAction(), - "cloudamqp_alarm": resourceAlarm(), - "cloudamqp_custom_domain": resourceCustomDomain(), - "cloudamqp_extra_disk_size": resourceExtraDiskSize(), - "cloudamqp_instance": resourceInstance(), - "cloudamqp_integration_log": resourceIntegrationLog(), - "cloudamqp_integration_metric": resourceIntegrationMetric(), - "cloudamqp_maintenance_window": resourceMaintenanceWindow(), - "cloudamqp_node_actions": resourceNodeAction(), - "cloudamqp_notification": resourceNotification(), - "cloudamqp_plugin_community": resourcePluginCommunity(), - "cloudamqp_plugin": resourcePlugin(), - "cloudamqp_privatelink_aws": resourcePrivateLinkAws(), - "cloudamqp_privatelink_azure": resourcePrivateLinkAzure(), - "cloudamqp_rabbitmq_configuration": resourceRabbitMqConfiguration(), - "cloudamqp_security_firewall": resourceSecurityFirewall(), - "cloudamqp_upgrade_rabbitmq": resourceUpgradeRabbitMQ(), - "cloudamqp_upgrade_lavinmq": resourceUpgradeLavinMQ(), - "cloudamqp_vpc_connect": resourceVpcConnect(), - "cloudamqp_vpc_gcp_peering": resourceVpcGcpPeering(), - "cloudamqp_vpc_peering": resourceVpcPeering(), - "cloudamqp_vpc": resourceVpc(), - "cloudamqp_webhook": resourceWebhook(), + "cloudamqp_account_action": resourceAccountAction(), + "cloudamqp_alarm": resourceAlarm(), + "cloudamqp_custom_domain": resourceCustomDomain(), + "cloudamqp_extra_disk_size": resourceExtraDiskSize(), + "cloudamqp_instance": resourceInstance(), + "cloudamqp_integration_log": resourceIntegrationLog(), + "cloudamqp_integration_metric": resourceIntegrationMetric(), + "cloudamqp_maintenance_window": resourceMaintenanceWindow(), + "cloudamqp_node_actions": resourceNodeAction(), + "cloudamqp_notification": resourceNotification(), + "cloudamqp_plugin_community": resourcePluginCommunity(), + "cloudamqp_plugin": resourcePlugin(), + "cloudamqp_privatelink_aws": resourcePrivateLinkAws(), + "cloudamqp_privatelink_azure": resourcePrivateLinkAzure(), + "cloudamqp_rabbitmq_configuration": resourceRabbitMqConfiguration(), + "cloudamqp_security_firewall": resourceSecurityFirewall(), + "cloudamqp_upgrade_rabbitmq": resourceUpgradeRabbitMQ(), + "cloudamqp_upgrade_lavinmq": resourceUpgradeLavinMQ(), + "cloudamqp_vpc_connect": resourceVpcConnect(), + "cloudamqp_vpc_gcp_peering": resourceVpcGcpPeering(), + "cloudamqp_vpc_peering": resourceVpcPeering(), + "cloudamqp_vpc": resourceVpc(), + "cloudamqp_webhook": resourceWebhook(), }, ConfigureFunc: configureClient(client), } diff --git a/cloudamqp/resource_cloudamqp_aws_eventbridge.go b/cloudamqp/resource_cloudamqp_aws_eventbridge.go index 14b1b5cb..973c21b9 100644 --- a/cloudamqp/resource_cloudamqp_aws_eventbridge.go +++ b/cloudamqp/resource_cloudamqp_aws_eventbridge.go @@ -2,63 +2,120 @@ package cloudamqp import ( "context" + "encoding/json" "fmt" + "log" "strconv" "strings" "github.com/cloudamqp/terraform-provider-cloudamqp/api" - "github.com/hashicorp/terraform-plugin-log/tflog" - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "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/boolplanmodifier" + "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/types" ) -func resourceAwsEventBridge() *schema.Resource { - return &schema.Resource{ - CreateContext: resourceAwsEventBridgeCreate, - ReadContext: resourceAwsEventBridgeRead, - DeleteContext: resourceAwsEventBridgeDelete, - Importer: &schema.ResourceImporter{ - StateContext: schema.ImportStatePassthroughContext, - }, - Schema: map[string]*schema.Schema{ - "instance_id": { - Type: schema.TypeInt, - ForceNew: true, +type awsEventBridgeResource struct { + client *api.API +} + +type awsEventBridgeResourceModel struct { + Id types.String `tfsdk:"id"` + InstanceID types.Int64 `tfsdk:"instance_id"` + AwsAccountId types.String `tfsdk:"aws_account_id"` + AwsRegion types.String `tfsdk:"aws_region"` + Vhost types.String `tfsdk:"vhost"` + QueueName types.String `tfsdk:"queue"` + WithHeaders types.Bool `tfsdk:"with_headers"` + Status types.String `tfsdk:"status"` +} + +type awsEventBridgeResourceApiModel struct { + AwsAccountId string `json:"aws_account_id"` + AwsRegion string `json:"aws_region"` + Vhost string `json:"vhost"` + QueueName string `json:"queue"` + WithHeaders bool `json:"with_headers"` +} + +func (r *awsEventBridgeResource) Configure(ctx context.Context, request resource.ConfigureRequest, response *resource.ConfigureResponse) { + // Always perform a nil check when handling ProviderData because Terraform + // sets that data after it calls the ConfigureProvider RPC. + if request.ProviderData == nil { + return + } + + client, ok := request.ProviderData.(*api.API) + + if !ok { + response.Diagnostics.AddError( + "Unexpected Resource Configure Type", + fmt.Sprintf("Expected *api.API, got: %T. Please report this issue to the provider developers.", request.ProviderData), + ) + + return + } + + r.client = client +} + +func (r *awsEventBridgeResource) Metadata(ctx context.Context, request resource.MetadataRequest, response *resource.MetadataResponse) { + response.TypeName = "cloudamqp_integration_aws_eventbridge" +} + +func (r *awsEventBridgeResource) Schema(ctx context.Context, request resource.SchemaRequest, response *resource.SchemaResponse) { + response.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Computed: true, + }, + "instance_id": schema.Int64Attribute{ Required: true, Description: "Instance identifier", + PlanModifiers: []planmodifier.Int64{ + int64planmodifier.RequiresReplace(), + }, }, - "aws_account_id": { - Type: schema.TypeString, - ForceNew: true, + "aws_account_id": schema.StringAttribute{ Required: true, Description: "The 12 digit AWS Account ID where you want the events to be sent to.", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, }, - "aws_region": { - Type: schema.TypeString, - ForceNew: true, + "aws_region": schema.StringAttribute{ Required: true, Description: "The AWS region where you the events to be sent to. (e.g. us-west-1, us-west-2, ..., etc.)", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, }, - "vhost": { - Type: schema.TypeString, - ForceNew: true, + "vhost": schema.StringAttribute{ Required: true, Description: "The VHost the queue resides in.", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, }, - "queue": { - Type: schema.TypeString, - ForceNew: true, + "queue": schema.StringAttribute{ Required: true, Description: "A (durable) queue on your RabbitMQ instance.", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, }, - "with_headers": { - Type: schema.TypeBool, - ForceNew: true, + "with_headers": schema.BoolAttribute{ Required: true, Description: "Include message headers in the event data.", + PlanModifiers: []planmodifier.Bool{ + boolplanmodifier.RequiresReplace(), + }, }, - "status": { - Type: schema.TypeString, + "status": schema.StringAttribute{ Computed: true, Description: "Always set to null, unless there is an error starting the EventBridge", }, @@ -66,96 +123,119 @@ func resourceAwsEventBridge() *schema.Resource { } } -func resourceAwsEventBridgeCreate(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { - var ( - api = meta.(*api.API) - keys = awsEventbridgeAttributeKeys() - params = make(map[string]any) - instanceID = d.Get("instance_id").(int) - ) +func (r *awsEventBridgeResource) Create(ctx context.Context, request resource.CreateRequest, response *resource.CreateResponse) { + var data awsEventBridgeResourceModel - for _, k := range keys { - if v := d.Get(k); v != nil { - params[k] = v - } + // Read Terraform plan data into the model + response.Diagnostics.Append(request.Plan.Get(ctx, &data)...) + + if response.Diagnostics.HasError() { + return + } + + apiModel := awsEventBridgeResourceApiModel{ + AwsAccountId: data.AwsAccountId.ValueString(), + AwsRegion: data.AwsRegion.ValueString(), + Vhost: data.Vhost.ValueString(), + QueueName: data.QueueName.ValueString(), + WithHeaders: data.WithHeaders.ValueBool(), + } + + var params map[string]interface{} + temp, err := json.Marshal(apiModel) + if err != nil { + response.Diagnostics.AddError( + "Unable to Create Resource", + "An unexpected error occurred while creating the resource create request. "+ + "Please report this issue to the provider developers.\n\n"+ + "JSON Error: "+err.Error(), + ) + return } + // TODO: This is totally a hack to get the struct into a map[string]interface{} + // It is very unlikely this will fail after the first one succeeds, so it should be fine to ignore the error + // Maybe after the api is moved into the repo we can improve the interface + _ = json.Unmarshal(temp, ¶ms) - data, err := api.CreateAwsEventBridge(ctx, instanceID, params) + apiResponse, err := r.client.CreateAwsEventBridge(ctx, int(data.InstanceID.ValueInt64()), params) if err != nil { - return diag.FromErr(err) + response.Diagnostics.AddError( + "Failed to Create Resource", + "An error occurred while calling the api to create the surface, verify your permissions are correct.\n\n"+ + "JSON Error: "+err.Error(), + ) + return } - d.SetId(data["id"].(string)) - return diag.Diagnostics{} + data.Id = types.StringValue(apiResponse["id"].(string)) + data.Status = types.StringNull() + + // Save data into Terraform state + response.Diagnostics.Append(response.State.Set(ctx, &data)...) } -func resourceAwsEventBridgeRead(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { - if strings.Contains(d.Id(), ",") { - tflog.Debug(ctx, fmt.Sprintf("import AWS eventbridge from input identifier: %s", d.Id())) - s := strings.Split(d.Id(), ",") - d.SetId(s[0]) +func (r *awsEventBridgeResource) Read(ctx context.Context, request resource.ReadRequest, response *resource.ReadResponse) { + var state awsEventBridgeResourceModel + + // Read Terraform plan data into the model + response.Diagnostics.Append(request.State.Get(ctx, &state)...) + + if strings.Contains(state.Id.ValueString(), ",") { + log.Printf("[DEBUG] cloudamqp::resource::aws-eventbridge::read id contains : %v", state.Id.String()) + s := strings.Split(state.Id.ValueString(), ",") + log.Printf("[DEBUG] cloudamqp::resource::aws-eventbridge::read split ids: %v, %v", s[0], s[1]) + state.Id = types.StringValue(s[0]) instanceID, _ := strconv.Atoi(s[1]) - d.Set("instance_id", instanceID) + state.InstanceID = types.Int64Value(int64(instanceID)) } - if d.Get("instance_id").(int) == 0 { - return diag.Errorf("missing input identifier for import: {resource_id},{instance_id}") + if state.InstanceID.ValueInt64() == 0 { + response.Diagnostics.AddError("Missing instance identifier {resource_id},{instance_id}", "") + return } var ( - api = meta.(*api.API) - instanceID = d.Get("instance_id").(int) + id = state.Id.ValueString() + instanceID = int(state.InstanceID.ValueInt64()) ) - data, err := api.ReadAwsEventBridge(ctx, instanceID, d.Id()) + log.Printf("[DEBUG] cloudamqp::resource::aws-eventbridge::read ID: %v, instanceID %v", id, instanceID) + data, err := r.client.ReadAwsEventBridge(ctx, instanceID, id) if err != nil { - return diag.FromErr(err) + response.Diagnostics.AddError("Something went wrong while reading the aws event bridge", fmt.Sprintf("%v", err)) + return } - for k, v := range data { - if validateAwsEventBridgeSchemaAttribute(k) { - if v == nil { - continue - } - if err = d.Set(k, v); err != nil { - return diag.Errorf("error setting %s for resource %s: %s", k, d.Id(), err) - } - } - } + state.AwsAccountId = types.StringValue(data["aws_account_id"].(string)) + state.AwsRegion = types.StringValue(data["aws_region"].(string)) + state.Vhost = types.StringValue(data["vhost"].(string)) + state.QueueName = types.StringValue(data["queue"].(string)) + state.WithHeaders = types.BoolValue(data["with_headers"].(bool)) - return diag.Diagnostics{} -} + // Save data into Terraform state + response.Diagnostics.Append(response.State.Set(ctx, &state)...) -func resourceAwsEventBridgeDelete(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { - var ( - api = meta.(*api.API) - instanceID = d.Get("instance_id").(int) - ) + return +} - if err := api.DeleteAwsEventBridge(ctx, instanceID, d.Id()); err != nil { - return diag.FromErr(err) - } - return diag.Diagnostics{} +func (r *awsEventBridgeResource) Update(ctx context.Context, request resource.UpdateRequest, response *resource.UpdateResponse) { + // This resource does not implement the Update function } -func awsEventbridgeAttributeKeys() []string { - return []string{ - "aws_account_id", - "aws_region", - "vhost", - "queue", - "with_headers", +func (r *awsEventBridgeResource) Delete(ctx context.Context, request resource.DeleteRequest, response *resource.DeleteResponse) { + var data awsEventBridgeResourceModel + + // Read Terraform plan data into the model + response.Diagnostics.Append(request.State.Get(ctx, &data)...) + var id = data.Id.ValueString() + err := r.client.DeleteAwsEventBridge(ctx, int(data.InstanceID.ValueInt64()), id) + + if err != nil { + response.Diagnostics.AddError("An error occurred while deleting cloudamqp_integration_aws_eventbridge", + fmt.Sprintf("Error deleting Cloudamqp event bridge %s: %s", id, err), + ) } } -func validateAwsEventBridgeSchemaAttribute(key string) bool { - switch key { - case "aws_account_id", - "aws_region", - "vhost", - "queue", - "with_headers", - "status": - return true - } - return false +func (r *awsEventBridgeResource) ImportState(ctx context.Context, request resource.ImportStateRequest, response *resource.ImportStateResponse) { + resource.ImportStatePassthroughID(ctx, path.Root("id"), request, response) }