From eaa619b73d99fb2500023093d5bb75c402826569 Mon Sep 17 00:00:00 2001 From: Jeffrey Held Date: Wed, 6 Dec 2023 11:03:48 +0100 Subject: [PATCH] chore: deprecate aiven_account_authentication resource --- CHANGELOG.md | 81 ++-- .../service/account/account_authentication.go | 35 +- .../account_authentication_data_source.go | 1 + .../account/account_authentication_test.go | 416 ------------------ 4 files changed, 46 insertions(+), 487 deletions(-) delete mode 100644 internal/sdkprovider/service/account/account_authentication_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e989228e..838c58ec2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ nav_order: 1 ## [MAJOR.MINOR.PATCH] - YYYY-MM-DD - Deprecating `project_user`, `account_team` and `account_team_member` resources +- Deprecate `account_authentication` resource. Resource creation is removed, while other operations are still possible. - Fix unmarshalling empty userconfig crash - Never skip basic auth username/password in service integrations user config options when sending them to the API - Add `emit_backward_heartbeats_enabled` field support in Mirrormaker replication flow @@ -50,7 +51,7 @@ nav_order: 1 - Add Organization User Groups support - Fixed incorrect `account_id` behavior in mixed constraint setup in `aiven_project` resource -- Use updated aiven-go-client with enhanced retries +- Use updated aiven-go-client with enhanced retries - Change `plan` from optional to required - Improve `disk_space` deprecation message to become more explicit to migrating users - Fix account deletion flakiness @@ -104,7 +105,7 @@ nav_order: 1 - Added docs and validation for `aiven_service_integration_endpoint` - Dropped `signalfx` from supported integration types -- Fix MySQL user creation authentication field +- Fix MySQL user creation authentication field - Fix Account SAML Field mapping set method - Adjust generated SQL for ClickHouse privilege grants - Fix `required` not generated for top level fields for user config options @@ -182,7 +183,7 @@ nav_order: 1 - Integration with Kafka source - Integration with PostgreSQL source - Fix VPC peering ID parser -- Add `offset_syncs_topic_location` support for `aiven_mirrormaker_replication_flow` resource +- Add `offset_syncs_topic_location` support for `aiven_mirrormaker_replication_flow` resource - Add `ssl` and `kafka_authentication_method` output support in service components - Fix `admin_username` and `admin_password` fields diff @@ -192,7 +193,7 @@ nav_order: 1 - Add `ip_filter_object` and `namespaces_object` user config options which are meant to extend the existing `ip_filter` and `namespaces` ones - Revert `datasource_project_vpc` `cloud_name` and `project` deprecations - Add extra timeout for `kafka_connect` service integration create -- Support `clickhouse_kafka` integration type in `aiven_service_integration` +- Support `clickhouse_kafka` integration type in `aiven_service_integration` - Fix `aiven_transit_gateway_vpc_attachment` fails to parse ID - Prevent generation of `Default` field in static schema generator - Add `self_link` field to `aiven_gcp_vpc_peering_connection` resource @@ -212,7 +213,7 @@ nav_order: 1 ## [3.8.0] - 2022-09-30 - Fix `aiven_gcp_vpc_peering_connection` creation -- Improve static IP error handling end messaging +- Improve static IP error handling end messaging - Fix `aiven_account_authentication` resource update, add tests - Change `aiven_project_vpc` datasource behaviour - Fix `aiven_service_component` optional parameters filters @@ -271,7 +272,7 @@ nav_order: 1 - Update Changelog Enforcer workflow - Add CodeQL workflow - Add `opensearch_index` support to `aiven_flink_table` -- Add not found checks to the Kafka availability waiter +- Add not found checks to the Kafka availability waiter - Add PostgreSQL max connections and PgBouncer outputs - Perform general code clean-up and add `revive` linter - Add support for new user configuration options @@ -523,8 +524,8 @@ New resources and data-sources: - Add database deletion waiter - Remove default values for user configuration options - Improve documentation and examples - - Add Prometheus integration example - - Add example for Datadog metrics integration + - Add Prometheus integration example + - Add example for Datadog metrics integration ## [2.1.14] - 2021-05-18 @@ -533,11 +534,11 @@ New resources and data-sources: - Use golang 1.16 - Remove GitHub pages and supporting code - Rework documentation and examples - - New README file structure - - Removed the Getting Started guide and merged its contents on `docs/index.md` - - Splitting `docs/index.md` contents in other pages on the guides - - In examples use data source for the Aiven Project instead of resource - - In examples use `aiven_` resource instead of `aiven_service` + - New README file structure + - Removed the Getting Started guide and merged its contents on `docs/index.md` + - Splitting `docs/index.md` contents in other pages on the guides + - In examples use data source for the Aiven Project instead of resource + - In examples use `aiven_` resource instead of `aiven_service` ## [2.1.13] - 2021-05-07 @@ -546,10 +547,10 @@ New resources and data-sources: ## [2.1.12] - 2021-04-20 - Improve documentation - - Add missing import instructions - - Add `aiven_billing_group` documentation - - Fix required and optional `aiven_connection_pool` options - - Updates to `MirrorMaker` arguments list + - Add missing import instructions + - Add `aiven_billing_group` documentation + - Fix required and optional `aiven_connection_pool` options + - Updates to `MirrorMaker` arguments list - Fix error message for prometheus user creation - Fix project `technical_emails` and `billing_emails` fields schema - Add support for new user configuration options @@ -704,11 +705,11 @@ New resources and data-sources: ## [2.0.5] - 2020-09-17 - Extend service integration endpoint, add user configuration options - - `external_aws_cloudwatch_logs` - - `external_google_cloud_logging` - - `external_kafka` - - `jolokia` - - `signalfx` + - `external_aws_cloudwatch_logs` + - `external_google_cloud_logging` + - `external_kafka` + - `jolokia` + - `signalfx` - Add support for new user configuration options - Add Azure specific behaviour for VPC peering connection resource @@ -744,16 +745,16 @@ New resources and data-sources: - Add mongo sink connector examples and tests - Kafka ACL regex modification - New resources: - - `aiven_pg` PostgreSQL service - - `aiven_cassandra` Cassandra service - - `aiven_elasticsearch` Elasticsearch service - - `aiven_grafana` Grafana service - - `aiven_influxdb` Influxdb service - - `aiven_redis` Redis service - - `aiven_mysql` MySQL service - - `aiven_kafka` Kafka service - - `aiven_kafka_connect` Kafka Connect service - - `aiven_kafka_mirrormaker` Kafka Mirrormaker 2 service + - `aiven_pg` PostgreSQL service + - `aiven_cassandra` Cassandra service + - `aiven_elasticsearch` Elasticsearch service + - `aiven_grafana` Grafana service + - `aiven_influxdb` Influxdb service + - `aiven_redis` Redis service + - `aiven_mysql` MySQL service + - `aiven_kafka` Kafka service + - `aiven_kafka_connect` Kafka Connect service + - `aiven_kafka_mirrormaker` Kafka Mirrormaker 2 service ## [1.3.5] - 2020-08-11 @@ -796,10 +797,10 @@ Improve vpc_id error handling for vpc peering connection - Speed up kafka topic availability waiter - Kafka Connect examples - TF client timings added for the following resources: - - aiven_vpc_peering_connection - - aiven_project_vpc - - aiven_service - - aiven_kafka_topic + - aiven_vpc_peering_connection + - aiven_project_vpc + - aiven_service + - aiven_kafka_topic ## [1.2.3] - 2020-03-30 @@ -823,10 +824,10 @@ Terraform client-side termination protection for resources: - Following new types of resources have been added: - - account - - account_team - - account_team_member - - account_team_project + - account + - account_team + - account_team_member + - account_team_project - New configuration options - Fix for a read-only replica service types diff --git a/internal/sdkprovider/service/account/account_authentication.go b/internal/sdkprovider/service/account/account_authentication.go index dc0e81d13..2bd207ec0 100644 --- a/internal/sdkprovider/service/account/account_authentication.go +++ b/internal/sdkprovider/service/account/account_authentication.go @@ -153,40 +153,13 @@ func ResourceAccountAuthentication() *schema.Resource { }, Timeouts: schemautil.DefaultResourceTimeouts(), - Schema: aivenAccountAuthenticationSchema, + Schema: aivenAccountAuthenticationSchema, + DeprecationMessage: "This resource is deprecated", } } -func resourceAccountAuthenticationCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { - client := m.(*aiven.Client) - - accountID := d.Get("account_id").(string) - r, err := client.AccountAuthentications.Create( - ctx, - accountID, - aiven.AccountAuthenticationMethodCreate{ - AuthenticationMethodName: d.Get("name").(string), - AuthenticationMethodType: d.Get("type").(string), - AutoJoinTeamID: d.Get("auto_join_team_id").(string), - SAMLCertificate: strings.TrimSpace(d.Get("saml_certificate").(string)), - SAMLDigestAlgorithm: d.Get("saml_digest_algorithm").(string), - SAMLEntityID: d.Get("saml_entity_id").(string), - SAMLFieldMapping: readSAMLFieldMappingFromSchema(d), - SAMLIdpLoginAllowed: d.Get("saml_idp_login_allowed").(bool), - SAMLIdpURL: d.Get("saml_idp_url").(string), - SAMLSignatureAlgorithm: d.Get("saml_signature_algorithm").(string), - SAMLVariant: d.Get("saml_variant").(string), - }, - ) - if err != nil { - return diag.FromErr(err) - } - - d.SetId(schemautil.BuildResourceID( - accountID, - r.AuthenticationMethod.AuthenticationMethodID)) - - return resourceAccountAuthenticationRead(ctx, d, m) +func resourceAccountAuthenticationCreate(_ context.Context, _ *schema.ResourceData, _ interface{}) diag.Diagnostics { + return diag.Errorf("creating account authentication is unsupported") } func resourceAccountAuthenticationRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { diff --git a/internal/sdkprovider/service/account/account_authentication_data_source.go b/internal/sdkprovider/service/account/account_authentication_data_source.go index b4c06e21b..76c518c93 100644 --- a/internal/sdkprovider/service/account/account_authentication_data_source.go +++ b/internal/sdkprovider/service/account/account_authentication_data_source.go @@ -16,6 +16,7 @@ func DatasourceAccountAuthentication() *schema.Resource { Description: "The Account Authentication data source provides information about the existing Aiven Account Authentication.", Schema: schemautil.ResourceSchemaAsDatasourceSchema(aivenAccountAuthenticationSchema, "account_id", "name"), + DeprecationMessage: "This resource is deprecated", } } diff --git a/internal/sdkprovider/service/account/account_authentication_test.go b/internal/sdkprovider/service/account/account_authentication_test.go deleted file mode 100644 index 87ce69ba5..000000000 --- a/internal/sdkprovider/service/account/account_authentication_test.go +++ /dev/null @@ -1,416 +0,0 @@ -package account_test - -import ( - "bytes" - "context" - "crypto/rand" - "crypto/rsa" - "crypto/x509" - "crypto/x509/pkix" - "encoding/pem" - "fmt" - "log" - "math/big" - "os" - "strings" - "testing" - "time" - - "github.com/aiven/aiven-go-client/v2" - "github.com/hashicorp/terraform-plugin-testing/helper/acctest" - "github.com/hashicorp/terraform-plugin-testing/helper/resource" - "github.com/hashicorp/terraform-plugin-testing/terraform" - "github.com/stretchr/testify/assert" - - acc "github.com/aiven/terraform-provider-aiven/internal/acctest" - "github.com/aiven/terraform-provider-aiven/internal/schemautil" -) - -func TestAccAivenAccountAuthentication_basic(t *testing.T) { - resourceName := "aiven_account_authentication.foo" - rName := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acc.TestAccPreCheck(t) }, - ProtoV6ProviderFactories: acc.TestProtoV6ProviderFactories, - CheckDestroy: testAccCheckAivenAccountAuthenticationResourceDestroy, - Steps: []resource.TestStep{ - { - Config: testAccAccountAuthenticationResource(rName), - Check: resource.ComposeTestCheckFunc( - testAccCheckAivenAccountAuthenticationAttributes("data.aiven_account_authentication.auth"), - resource.TestCheckResourceAttr(resourceName, "name", fmt.Sprintf("test-acc-auth-%s", rName)), - resource.TestCheckResourceAttr(resourceName, "enabled", "false"), - resource.TestCheckResourceAttr(resourceName, "type", "saml"), - ), - }, - }, - }) -} - -func testAccAccountAuthenticationResourceSAMLCertificate(rName, certificate string) string { - return fmt.Sprintf(` -resource "aiven_account" "user" { - name = "test-acc-account-%[1]s" -} - -resource "aiven_account_authentication" "method" { - account_id = aiven_account.user.account_id - type = "saml" - name = "test-acc-auth-method-%[1]s" - saml_certificate = <<-EOT - %[2]s - EOT - - saml_field_mapping { - email = "test@aiven.io" - first_name = "TestName" - identity = "1234567" - last_name = "TestLastName" - real_name = "TestRealName" - } -} -`, rName, certificate) -} - -func TestAccAivenAccountAuthentication_saml_valid_certificate_create_update(t *testing.T) { - certCreate, err := genX509Certificate(time.Now()) - assert.NoError(t, err) - - certUpdate, err := genX509Certificate(time.Now()) - assert.NoError(t, err) - - rName := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) - resourceName := "aiven_account_authentication.method" - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acc.TestAccPreCheck(t) }, - ProtoV6ProviderFactories: acc.TestProtoV6ProviderFactories, - CheckDestroy: testAccCheckAivenAccountAuthenticationResourceDestroy, - Steps: []resource.TestStep{ - // Creates - { - Config: testAccAccountAuthenticationResourceSAMLCertificate(rName, certCreate), - Check: resource.ComposeTestCheckFunc( - testAccCheckAivenAccountAuthenticationAttributes(resourceName), - resource.TestCheckResourceAttr(resourceName, "name", "test-acc-auth-method-"+rName), - resource.TestCheckResourceAttr(resourceName, "saml_certificate", certCreate), - ), - }, - // Updates - { - Config: testAccAccountAuthenticationResourceSAMLCertificate(rName, certUpdate), - Check: resource.ComposeTestCheckFunc( - testAccCheckAivenAccountAuthenticationAttributes(resourceName), - resource.TestCheckResourceAttr(resourceName, "name", "test-acc-auth-method-"+rName), - resource.TestCheckResourceAttr(resourceName, "saml_certificate", certUpdate), - ), - }, - }, - }) -} - -func TestAccAivenAccountAuthentication_saml_invalid_certificate(t *testing.T) { - certCreate, err := genX509Certificate(time.Now().AddDate(-30, 0, 0)) - assert.NoError(t, err) - - rName := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acc.TestAccPreCheck(t) }, - ProtoV6ProviderFactories: acc.TestProtoV6ProviderFactories, - CheckDestroy: testAccCheckAivenAccountAuthenticationResourceDestroy, - Steps: []resource.TestStep{ - // Creates - { - Config: testAccAccountAuthenticationResourceSAMLCertificate(rName, certCreate), - }, - }, - ErrorCheck: func(err error) error { - assert.ErrorContains(t, err, "Certificate is no longer valid") - return nil - }, - }) -} - -func TestAccAivenAccountAuthentication_auto_join_team_id(t *testing.T) { - if _, ok := os.LookupEnv("AIVEN_ACCOUNT_NAME"); !ok { - t.Skip("AIVEN_ACCOUNT_NAME env variable is required to run this test") - } - - resourceName := "aiven_account_authentication.foo" - rName := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acc.TestAccPreCheck(t) }, - ProtoV6ProviderFactories: acc.TestProtoV6ProviderFactories, - CheckDestroy: testAccCheckAivenAccountAuthenticationWithAutoJoinTeamIDResourceDestroy, - Steps: []resource.TestStep{ - { - Config: testAccAccountAuthenticationWithAutoJoinTeamIDResource(rName), - Check: resource.ComposeTestCheckFunc( - testAccCheckAivenAccountAuthenticationAttributes("data.aiven_account_authentication.auth"), - resource.TestCheckResourceAttr(resourceName, "name", fmt.Sprintf("test-acc-auth-%s", rName)), - resource.TestCheckResourceAttr(resourceName, "enabled", "false"), - resource.TestCheckResourceAttr(resourceName, "type", "saml"), - resource.TestCheckResourceAttrPair(resourceName, "auto_join_team_id", "aiven_account_team.foo", "team_id"), - ), - }, - }, - }) -} - -func testAccAccountAuthenticationResource(name string) string { - return fmt.Sprintf(` -resource "aiven_account" "foo" { - name = "test-acc-ac-%s" -} - -resource "aiven_account_authentication" "foo" { - account_id = aiven_account.foo.account_id - name = "test-acc-auth-%s" - type = "saml" - enabled = false -} - -data "aiven_account_authentication" "auth" { - account_id = aiven_account_authentication.foo.account_id - name = aiven_account_authentication.foo.name - - depends_on = [aiven_account_authentication.foo] -}`, name, name) -} - -func testAccAccountAuthenticationWithAutoJoinTeamIDResource(name string) string { - orgName := os.Getenv("AIVEN_ACCOUNT_NAME") - - return fmt.Sprintf(` -data "aiven_account" "foo" { - name = "%[1]s" -} - -resource "aiven_account_team" "foo" { - account_id = data.aiven_account.foo.account_id - name = "test-acc-team-%[2]s" -} - -resource "aiven_account_authentication" "foo" { - account_id = data.aiven_account.foo.account_id - name = "test-acc-auth-%[2]s" - type = "saml" - enabled = false - auto_join_team_id = aiven_account_team.foo.team_id -} - -data "aiven_account_team" "team" { - name = aiven_account_team.foo.name - account_id = aiven_account_team.foo.account_id - - depends_on = [aiven_account_team.foo] -} - -data "aiven_account_authentication" "auth" { - account_id = aiven_account_authentication.foo.account_id - name = aiven_account_authentication.foo.name - - depends_on = [aiven_account_authentication.foo] -}`, orgName, name) -} - -func testAccCheckAivenAccountAuthenticationResourceDestroy(s *terraform.State) error { - c := acc.GetTestAivenClient() - - ctx := context.Background() - - // loop through the resources in state, verifying each account authentication is destroyed - for _, rs := range s.RootModule().Resources { - if rs.Type != "aiven_account_authentication" { - continue - } - - accountID, authID, err := schemautil.SplitResourceID2(rs.Primary.ID) - if err != nil { - return err - } - - r, err := c.Accounts.List(ctx) - if err != nil { - if err.(aiven.Error).Status != 404 { - return err - } - - return nil - } - - for _, ac := range r.Accounts { - if ac.Id == accountID { - ra, err := c.AccountAuthentications.List(ctx, accountID) - if err != nil { - if err.(aiven.Error).Status != 404 { - return err - } - - return nil - } - - for _, a := range ra.AuthenticationMethods { - if a.AuthenticationMethodID == authID { - return fmt.Errorf("account authentication (%s) still exists", rs.Primary.ID) - } - } - } - } - } - - return nil -} - -func testAccCheckAivenAccountAuthenticationWithAutoJoinTeamIDResourceDestroy(s *terraform.State) error { - c := acc.GetTestAivenClient() - - ctx := context.Background() - - // loop through the resources in state, verifying each account authentication is destroyed - for _, rs := range s.RootModule().Resources { - if rs.Type != "aiven_account_team" && rs.Type != "aiven_account_authentication" { - continue - } - - isTeam := rs.Type == "aiven_account_team" - - accountID, secondaryID, err := schemautil.SplitResourceID2(rs.Primary.ID) - if err != nil { - return err - } - - r, err := c.Accounts.List(ctx) - if err != nil { - if err.(aiven.Error).Status != 404 { - return err - } - - return nil - } - - ctx := context.Background() - - for _, ac := range r.Accounts { - if ac.Id == accountID { - if isTeam { - rl, err := c.AccountTeams.List(ctx, accountID) - if err != nil { - if err.(aiven.Error).Status != 404 { - return err - } - - return nil - } - - for _, team := range rl.Teams { - if team.Id == secondaryID { - return fmt.Errorf("account team (%s) still exists", rs.Primary.ID) - } - } - } else { - ra, err := c.AccountAuthentications.List(ctx, accountID) - if err != nil { - if err.(aiven.Error).Status != 404 { - return err - } - - return nil - } - - for _, a := range ra.AuthenticationMethods { - if a.AuthenticationMethodID == secondaryID { - return fmt.Errorf("account authentication (%s) still exists", rs.Primary.ID) - } - } - } - } - } - } - - return nil -} - -func testAccCheckAivenAccountAuthenticationAttributes(n string) resource.TestCheckFunc { - return func(s *terraform.State) error { - r := s.RootModule().Resources[n] - if r.Primary == nil { - return fmt.Errorf("resource %s not found", n) - } - - a := r.Primary.Attributes - log.Printf("[DEBUG] account team attributes %v", a) - - if a["enabled"] != "false" { - return fmt.Errorf("expected to get an enabled from Aiven") - } - - if a["type"] != "saml" { - return fmt.Errorf("expected to get a correty type from Aiven") - } - - if a["account_id"] == "" { - return fmt.Errorf("expected to get an account id from Aiven") - } - - if a["authentication_id"] == "" { - return fmt.Errorf("expected to get an authentication_id from Aiven") - } - - if a["name"] == "" { - return fmt.Errorf("expected to get a name from Aiven") - } - - if a["create_time"] == "" { - return fmt.Errorf("expected to get a create_time from Aiven") - } - - if a["saml_acs_url"] == "" { - return fmt.Errorf("expected to get a saml_acs_url from Aiven") - } - - if a["saml_metadata_url"] == "" { - return fmt.Errorf("expected to get a saml_metadata_url from Aiven") - } - - return nil - } -} - -func genX509Certificate(now time.Time) (string, error) { - ca := &x509.Certificate{ - SerialNumber: big.NewInt(2022), - NotBefore: now, - NotAfter: now.Add(time.Hour), - Subject: pkix.Name{ - Organization: []string{"aiven"}, - }, - IsCA: true, - KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, - ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, - BasicConstraintsValid: true, - } - key, err := rsa.GenerateKey(rand.Reader, 4096) - if err != nil { - return "", err - } - - caBytes, err := x509.CreateCertificate(rand.Reader, ca, ca, &key.PublicKey, key) - if err != nil { - return "", err - } - - p := new(bytes.Buffer) - err = pem.Encode(p, &pem.Block{ - Type: "CERTIFICATE", - Bytes: caBytes, - }) - - if err != nil { - return "", err - } - return strings.TrimSpace(p.String()), nil -}